RichJ

Physics glitch

9 posts in this topic

Hi, I'm new to Phaser, but a seasoned games programmer.  Seems like a great framework so far, but I'm experiencing a glitch in the Arcade physics engine which I'm not sure is a bug, or down to the way I'm manipulating the body's velocity in code.

I've setup a sprite object and strips of horizontal & vertical wall blocks, all of which are enabled in the physics engine.  The walls are immovable.  If I move my sprite up, it will eventually hit a wall, but with the up key held I can still use the left & right keys to move the sprite smoothly against the wall.  If I do the same thing against the vertical wall, the up and down movements get stuck at the edge of some of the wall blocks if I keep the right key pressed.  Here's a example...

http://cam64.net/temp/phaser/default.html

...and here's the code.  Is it a bug, or am I doing something wrong?

var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create, update: update });
var walls;
var player;

function preload()
{
    game.load.image('playerImage', 'Images/sprite.png');
    game.load.image('wallImage', 'Images/block.png');
}

function create()
{
    // Start physics engine
    game.physics.startSystem(Phaser.Physics.ARCADE);

    // Setup walls group
    walls = game.add.group();
    walls.enableBody = true;

    // Create horizontal and vertical wall blocks
    for (i = 0; i < 9; i++)
    {
        var w1 = walls.create(i * 64, 0, 'wallImage');
        w1.body.immovable = true;

        var w2 = walls.create(576, i * 64, 'wallImage');
        w2.body.immovable = true;
    }

    // Create player
    player = game.add.sprite(250, 250, 'playerImage');
    game.physics.arcade.enable(player);
    player.body.maxVelocity.setTo(300, 300);
    player.body.collideWorldBounds = true;
}


function update()
{
    cursors = game.input.keyboard.createCursorKeys();

    // Move left and right
    if (cursors.left.isDown)
    {
        player.body.velocity.x -= 50;
    }
    else if (cursors.right.isDown)
    {
        player.body.velocity.x += 50;
    }
    else
    {
        player.body.velocity.x = 0;
    }

    // Move up and down
    if (cursors.up.isDown)
    {
        player.body.velocity.y -= 50;
    }
    else if (cursors.down.isDown)
    {
        player.body.velocity.y += 50;
    }
    else
    {
        player.body.velocity.y = 0;
    }

    // Update collisions
    game.physics.arcade.collide(player, walls);
}

 

samid737 likes this

Share this post


Link to post
Share on other sites

Anyone else experienced this, even if it hasn't been resolved?  It's kind of a deal breaker, quite surprised that the arcade physics engine fails in such a simple scenario, hence I'm thinking I've done something wrong :D

Share this post


Link to post
Share on other sites

Thanks for the tip, I didn't realise you could display all that debug info.  It doesn't show anything up though.  Really odd how the problem only occurs when brushing up against the vertical wall.

 

Share this post


Link to post
Share on other sites

This is a common fail state in 2d physics engines. The engine usually has to have special code to overcome this. Phaser's special code is in its Tilemap implementation. I would suggest making your blocks a Tilemap (even if you have to generate it dynamically) and going from there.

What's happening is that the physics engine tries to move your sprite by its velocity. Each dimension (x and y) are exactly the same mathematically: add the velocity * time delta to the position and you're done. However, there are two components to velocity, so which one do we do first? Phaser picks a really common one: do y first (we're more often standing on floors than sliding down walls, if you get me). The side effect is that your sprites can catch on edges like you're seeing. Since the sprite's velocity is, say, (5, 5) the sprite's AABB body tries to move diagonally downwards to the right. First we check y, then we check x. Checking y we see that the wall is there, intersecting the right side of our AABB body! So we stop downwards movement entirely. And there's your bug.

The best way around this that I know (and that Phaser uses in its Tilemap implementation) is to declare particular edges in a map as "uninteresting" so they don't get checked for collision. The most important edge in your wall of solid vertical tiles is the left one, not each edge between each adjacent tile. This prevents the problem from happening. But Phaser doesn't want to generalize that behavior across a bunch of individual sprites for performance reasons. Sprites move all the time, have different sizes, etc.

Ah, but Tilemaps! All the same size, all not moving. And there you go. Here's the function in Tilemap that does just what I described and finds "interesting" edges on Tiles. It saves them by modifying the tiles' face* properties.

RichJ and samid737 like this

Share this post


Link to post
Share on other sites

Thanks for the detailed post @drhayes, I've looked into Tilemaps and got it all up and running perfectly.  I was yet to come across Tilemaps, still only a few days into Phaser, so I'd fallen into the trap of going against the framework by trying to build up my tile map manually.  Can't believe how simple it is to implement a map exported as JSON from the Tiled map editor :D

Shame about the physics bug, but I understand what you're saying.  I wrote a very simple 2D physics engine a few months ago for a Monogame project and ran into pretty much the same problem.

Thanks again ;)

Share this post


Link to post
Share on other sites

I think you could try

game.physics.arcade.collide(player, walls);

var touching = player.body.touching;

var cursors = game.input.keyboard.createCursorKeys();

if      (cursors.left.isDown  && !touching.left ) player.body.velocity.x -= 50;
else if (cursors.right.isDown && !touching.right) player.body.velocity.x += 50;
else                                              player.body.velocity.x  =  0;

if      (cursors.up.isDown   && !touching.up  )   player.body.velocity.y -= 50;
else if (cursors.down.isDown && !touching.down)   player.body.velocity.y += 50;
else                                              player.body.velocity.y  =  0;

 

Share this post


Link to post
Share on other sites

Thanks @samme , I tried reading the "touching" properties but that didn't work either.  The debug info showed the touching properties being set every other frame.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.