Jump to content

Interesting Phenomenon with Platformer Cliff Detection


druphoria
 Share

Recommended Posts

I coded up a simple algorithm for an enemy in a platformer, whose default behavior is to walk forward until he hits a wall and then change direction, to also turn around if he arrives at a cliff/the edge of a platform so that he doesn't just walk off.

 

Basically, in the update loop, I check to the lower left of the sprite if the sprite is walking left, and vice versa for right - if the space that I examine is an "empty space" tile, then I change the direction of the sprite. I've noticed that if I check just one unit to the left of the sprite (offset of -1) or one unit to the right (offset of the sprite's width) then the sprite will occasionally just run over the cliff anyway without the "checkForCliff" method ever returning true. I changed the offset to 3 units instead of 1 and this seemed to fix the problem. I'm confused as to why - there must be something about sprite velocity or sprite movement or the update loop that I am not understanding here.

 

Here are the relevant code snippets.

 

The function for checking cliff:

Phaser.Sprite.prototype.checkForCliff = function(side) {    var offsetX;    if(side == 'left') {        offsetX = -3;     } else if(side == 'right') {        offsetX = this.body.width + 2;    }    var tile = level.map.getTileWorldXY(this.body.position.x + offsetX, this.body.position.y + this.body.height);    if(this.isTouchingGround() && tile && emptySpaceTiles.indexOf(tile.index) > -1) {        console.log("You are at the cliff.");        return true;    } else {        return false;    }};

The snippet from my update loop that calls the above function and changes the enemy's walking direction if necessary:

			if(enemy.previousXPosition == enemy.body.position.x				|| (enemy.currentDirection == 'left' && enemy.checkForCliff('left'))				|| (enemy.currentDirection == 'right' && enemy.checkForCliff('right'))) {				this.changeDirection(enemy);			}

Anyone have any idea why the enemy would occasionally fail to detect a cliff when the offset is only 1? Also, I tried setting it to two and it reduced the failed detections by a little bit but not completely. An offset of three seems (so far) to be working.

Link to comment
Share on other sites

At a guess I think it may be related to the speed the enemy is moving. If the enemy is moving reasonably fast and the detection is happening very close to the enemy, then it may not detect in time for the next frame where the enemy is already falling off the cliff. If you detect it well before it reaches the cliff, then you have ample time to change velocity.

 

It may be worth checking to see what's going on by using game.enableStep() and then stepping through frame by frame as an enemy approaches the edge. This should shed some light on what's going on.

 

For what it's worth, typically this kind of detection is done with invisible 'bumpers', triggers put at the edge of platforms to tell the enemy to turn around. Your way is more dynamic but means you'll possibly have to put more work in to make it robust, plus it will eat up a bit more performance.

Link to comment
Share on other sites

I see. I had not realized that the enemy actually might be moving between calls to the "update" function, but I'm guessing this could easily happen with a high enough velocity then?

 

As for eating up more performance - how does the trigger at the end of the platform work regarding that? Would Phaser not be checking if that sprite is on that tile each time the sprite changes position?

Link to comment
Share on other sites

If the object is moving more than 1px/s then yeah, the object will have to skip pixels to traverse the world, and the collision detection happens discreetly rather than as a 'sweep' through the positions the object has moved. So if your object has moved 5 pixels in a frame, but its detection is only 1 pixel away from it, it could easily overshoot the platform without detecting it, or detect it when it's too late.

 

The collision detection for TileMaps is pretty optimised, and since you're probably already doing collision detection against the map to traverse it you can just throw the bumper detection into the collision callback, essentially getting it for free.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...