Ich arbeite an einem kachelbasierten Mario-Klon.
Dies funktioniert gut beim Gehen und Fallen. Aber wenn der Spieler in die Nähe einer Wand springt und nach rechts in die Luft geht, bleibt der Spieler an der Wand hängen. Das Spieler-Sprite fällt erneut, wenn der Spieler den Schlüssel loslässt.
Das Setup ist ziemlich einfach und ich kann das Problem nicht finden. Die Karte wird als 2D-Array mit Kartenblöcken aufgebaut. Ein Block kann fest sein oder nicht. Der Spieler kann sich nicht durch feste Objekte bewegen, duh ..
In der Spielschleife:
- Der Standort des Spielers wird aktualisiert (Schwerkraft, Bewegung usw.).
- Überprüfen Sie die Karte auf Kollisionen. Wenn eine Kollision im Y gefunden wird, wird der Standort des Spielers so aktualisiert, dass er über oder unter dem Block liegt (abhängig von der Richtung des Spielers), und das Kollisionsfeld wird mit dem neuen Standort aktualisiert. Dann der gleiche Vorgang für das X.
- Das Kollisionsfeld wird auf den neuen Speicherort (einen freien Speicherort) aktualisiert. Das Feld ist so eingestellt, dass es etwas höher ist, wenn der Block unter dem Spieler überprüft, ob er gelandet ist. Dies dient dazu, den Status des Spielers vom fliegenden Sprite zum Leerlauf zu ändern.
Ich habe auch versucht, die X- und Y-Prüfung so umzuschalten, dass der Player auf der X-Linie bewegt wird. Wenn sich der Spieler dann bewegt, wird die Bewegung sehr verzögert. Wenn ich den Knopf drücke und loslasse, um mich zu bewegen, bewegt sich der Spieler schneller, aber in Spannfuttern. Sehr trippy ..
Hat jemand den Fehler gesehen oder kann mir dafür einen besseren Kollisionsalgorithmus geben?
UPDATE (Code wurde nicht aktualisiert)
Ich habe die x- und y-Prüfmethode ausgetauscht und die isonland-Variable implementiert. Wenn Sie also gegen Wände gehen und springen, funktioniert dies perfekt. Erst jetzt, wenn der Spieler springt, wird Mario bei der Landung zurückgesetzt. Dies liegt daran, dass die X-Check-Methode zuerst die Position von Mario anpasst.
Wie kann ich das lösen?
Aktualisierungsmethode für Kartenklassen:
public void update(int timeElapsed) {
//update entities
for(Entity entity : _mapEntities) {
entity.update(timeElapsed);
}
//update objects
for(MapObject mapObt : _mapObjects) {
mapObt.update(timeElapsed);
}
//check for collisions
checkMapCollision();
}
Aktualisierungsmethode für Entitäten (abstrakt):
public void update(int timeElapsed) {
_velocity = new Vector2d(0.0F, 0.0F);
//add gravity
_velocity.y = Map._GRAVITY_PER_SEC * timeElapsed;
}
Mario (erweitert Entität) Update Methos:
@Override
public void update(int timeElapsed) {
super.update(timeElapsed);
if(_state == STATES.IDLE) {
} else if(_isMoving) {
_marioSmallWalk.update(timeElapsed);
}
if(_state == STATES.JUMPING) {
setVelocityY(getVelocity().y + _jumpSpeed);
_jumpSpeed += _JUMP_DECREASE * timeElapsed;
//falling?
if(getVelocity().y > 0) {
setState(STATES.FALLING);
}
}
if(_isMoving) {
double walkSpd = (_WALK_SPEED_SEC * timeElapsed);
if(getFacing() == FACING.LEFT) {
walkSpd = -walkSpd;
}
setVelocityX(getVelocity().x + walkSpd);
}
//falling?
if(getVelocity().y > (Map._GRAVITY_PER_SEC * timeElapsed) + 1.0F) {
setState(STATES.FALLING);
}
setPosition((int)(getX() + getVelocity().x), (int)(getY() + getVelocity().y));
}
Kartenklasse CheckMapCollision-Methode:
public void checkMapCollision() {
//enteties move so check it
for(Entity entity : _mapEntities) {
//get the corners
Rectangle bounds = entity.getBounds();
Block[] corners = getCornerBlocks(bounds);
Vector2d dir = entity.getDirection();
//moving down
if(dir.y > 0) {
if(corners[2].isSolid() || corners[3].isSolid()) {
Rectangle blkBounds = null;
if(corners[2].isSolid()) {
blkBounds = corners[2].getBounds();
} else {
blkBounds = corners[3].getBounds();
}
entity.setPositionY(blkBounds.y);
}
} else {
if(corners[0].isSolid() || corners[1].isSolid()) {
Rectangle blkBounds = null;
if(corners[0].isSolid()) {
blkBounds = corners[0].getBounds();
} else {
blkBounds = corners[1].getBounds();
}
entity.setPositionY(blkBounds.y + blkBounds.height + bounds.height);
}
}
bounds = entity.getBounds();
corners = getCornerBlocks(bounds);
//moving to the right
if(dir.x > 0) {
if(corners[1].isSolid() || corners[3].isSolid()) {
Rectangle blkBounds;
if(corners[1].isSolid()) {
blkBounds = corners[1].getBounds();
} else {
blkBounds = corners[3].getBounds();
}
entity.setPositionX(blkBounds.x - (bounds.width-entity.getCurrentSprite().getOffsetX())-1);
}
} else {
if(corners[0].isSolid() || corners[2].isSolid()) {
Rectangle blkBounds;
if(corners[0].isSolid()) {
blkBounds = corners[0].getBounds();
} else {
blkBounds = corners[2].getBounds();
}
entity.setPositionX(blkBounds.x + blkBounds.width + (bounds.width/2));
}
}
bounds = new Rectangle(bounds.x, bounds.y, bounds.width, bounds.height+1);
corners = getCornerBlocks(bounds);
//moving down
if(dir.y > 0) {
if(corners[2].isSolid() || corners[3].isSolid()) {
Rectangle blkBounds = null;
if(corners[2].isSolid()) {
blkBounds = corners[2].getBounds();
} else {
blkBounds = corners[3].getBounds();
}
entity.landed();
System.out.println("landed");
}
}
}
}
entity.setPositionX()
oder entity.setPositionY()
wird nach der Kollisionsprüfung aufgerufen. Wenn ich ohne zu springen gegen die Wand gehe, wird der Spieler richtig zurückgeschoben.