2D Platformer Kollisions-"Verhinderung"
-
Hallo,
ich quäle mich jetzt schon seit 2-3 Wochen wiedereinmal damit herum, einen Weg zu finden einen einfachen 2D Platformer wie Mario/Megaman umzusetzen.
Ich hab das ganze schon öfters in der Vergangenheit versucht und bin IMMER an der Kollisions-"Auflösung" gescheitert, ich kam an diesem Punkt nie weiter und musste immer aufgeben.
Dieses mal bin ich auch wieder kurz davor, weil ich einfach keinen Schritt vorran komme und mein Hirn mich im Stich lässt...
Tutorials wie man herausfindet OB zwei Rechtecke sich schneiden gibt es ja genügend, nur am Ende steht dann immer sowas wie:if(collision()) { // Do something }
Es wird praktisch nur die Funktion collision() erklärt, ja schön, aber was zur Hölle kommt bei DO SOMETHING rein?!?!?......
Folgender Link wird auch in vielen Foren gepostet, der bringt mich allerdings 0 weiter weil da nichts konkretes erklärt wird:
http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/
Hab es schon auf 5-6 verschiedene Arten versucht und nichts funktioniert, der Spieler fällt durch den Boden, kann am Boden nicht mehr laufen, kann an Wänden stehen, wird von Tile zu Tile teleportiert, aus der Welt geschoben etc...
Ich bin echt am verzweifeln, mein Hirn raucht und ich komm überhaupt nicht vorran, ich versteh nurnoch Bahnhof.
Ich verstehe überhaupt nicht wieso der Code den ich habe nicht das macht was er soll, wo der Denkfehler liegt...
Folgende Methode hab ich versucht umzusetzen:
http://go.colorize.net/xna/2d_collision_response_xna/
Hab den Code etwas umgeschrieben weil ich ihn zu umständlich fand aber im Prinzip sollte er immernoch das selbe machen wenn ich das richtig verstanden habe...
Hier mein Code (nur eine Achse, die andere ist ja sowieso identisch):COLLISION_INFO ResolveCollisions(RECT* rect, std::vector<RECT>* obstacles, int dirX, int dirY) { COLLISION_INFO ci = {0,0}; int pushX = GetMinOverlapX(rect, obstacles); int pushY = GetMinOverlapY(rect, obstacles); if(abs(pushX) < abs(pushY)) // Kleinsten Overlap zuerst korrigieren { ci.pushDirectionX = ResolveCollisionOnXAxis(rect, pushX, dirX); pushY = GetMinOverlapY(rect, obstacles); if(abs(pushY) > 0) // Wenn auf der anderen Achse auch noch was overlapped { ci.pushDirectionY = ResolveCollisionOnYAxis(rect, pushY, dirY); } } else { ci.pushDirectionY = ResolveCollisionOnYAxis(rect, pushY, dirY); pushX = GetMinOverlapX(rect, obstacles); if(abs(pushX) > 0) // Wenn auf der anderen Achse auch noch was overlapped { pushX = GetMinOverlapX(rect, obstacles); ci.pushDirectionX = ResolveCollisionOnXAxis(rect, pushX, dirX); } } return ci; } int ResolveCollisionOnXAxis(RECT* rect, int pushX, int dirX) { if((dirX > 0 && pushX < 0) || (dirX < 0 && pushX > 0)) // Nicht in die selbe Richtung schieben wie gelaufen wird, sonst wird man beim Fallen an Wänden nach unten gedrückt etc... { if(pushX > 0) { rect->left += pushX+1; // 1 mehr damit man auch wirklich aus dem Tile raus ist return 1; } if(pushX < 0) { rect->left += pushX-1; return -1; } } return 0; } int GetMinOverlapX(RECT* rect, std::vector<RECT>* obstacles) { int minPushX = INT_MAX; for(auto obstacle = obstacles->begin(); obstacle != obstacles->end(); obstacle++) { int dx1 = rect->left - obstacle->right; int dx2 = rect->right - obstacle->left; int thisPushX = 0; if(abs(dx1) < abs(dx2)) { // Player nach rechts aus dem Tile schieben thisPushX = -dx1; } else { // Player nach links aus dem Tile schieben thisPushX = -dx2; } if(abs(thisPushX) < abs(minPushX)) minPushX = thisPushX; } if(minPushX == INT_MAX) return 0; // Wenn aus irgendeinem Grund ein leerer Vector übergeben wurde... else return minPushX; }
rect ist die Player/Objekt "Hitbox"/Boundingbox.
player.x <=> rect.left
player.y <=> rect.topZuerst verschiebe ich Player, dann rufe ich ResolveCollisions() auf und übergene einen Vector mit RECTs mit denen er kollidiert und die auch unpassierbar sind und setze danach die Playerposition auf die von der Funktion veränderte rect.left und rect.top.
COLLISION_INFO ist nur ein struct mit 2 variablen pushDirectionX, bzw Y, mit denen ich danach weiss ob der Spieler wieder springen kann, wenn er zB nach oben gedrückt wurde, also auf Boden aufgeknallt ist. (Obwohl das warscheinlich auch nicht richtig funktionieren wird...)Wo ist jetzt also der Denkfehler, ist das überhaupt eine gute Lösung?
Hab auch noch das gefunden aber da blick ich nicht durch...
http://www.wildbunny.co.uk/blog/2011/12/14/how-to-make-a-2d-platform-game-part-2-collision-detection/Langsam verliere ich die Hoffnung überhaupt irgendwann verstehen zu können wie man dieses Problem löst, immerhin sitze ich schon mindestens 2 Wochen NUR an diesem einem Problem und der Moment wo es *klick* macht und man sich denkt "AHA! Jetz hab ichs!" bleibt aus. Das Einzige dass ich mir noch vorstellen könnte ist die Brute-Force Methode: Mit einem for-loop den Player bei einer Kollision Pixel für Pixel zurückzuschieben bis es keine Kollision mehr gibt... das wäre finde ich aber keine besonders elegante Lösung...
Wäre echt nett wenn ihr mir weiterhelfen könntet, bin für jeden Tip/Lösungsvorschlag dankbar.