Jump to content

Create Water-flow-type physics when sprites overlap?


Recommended Posts

Hi all,


I'm very very new to Phaser and game dev in general. To teach myself the basics, I've been working on a few different prototypes that implement various physics mechanics, or address some other specific challenge.


Recently I created a prototype in which a rogue-like char has to avoid a few moving columns and get to a "win" sprite (...physics.arcade.overlap) to finish the level.  To make things more interesting I tried to implement some tiles where, on ...arcade.overlap the tiles would manipulate the players movement - essentially creating a water-like current, so that the players movement was lightly restricted in one direction, but enhanced in the other direction. 


Here's the code:


Under create():

    // configure the water blocks    waters = game.add.group();    waters.enableBody = true;    water1 = waters.create(0, 96, 'water');    water2 = waters.create(game.world.width - 256, 224, 'water');    water1.body.immovable = true;    water2.body.immovable = true;

Under update():

    game.physics.arcade.overlap(player,water1, water1Flow, null, this);    game.physics.arcade.overlap(player,water2, water2Flow, null, this);

water1Flow (since the two functions are nearly identical):

function water1Flow() {    player.body.velocity.x = 100;}

expected that this would have an impact on the player sprite's movement, but it hasn't done ANYTHING. I put a "console.log(player.body.velocity.x);" line in the function, and it showed that the velocity was 100, but in actual gameplay, that doesn't seem to be the case.


Any help or ideas would be greatly appreciated!



Link to comment
Share on other sites

Is the player under the context of "this"? If not try to pass the player directly to the function:

 game.physics.arcade.overlap(player, water1, water1Flow, null, player);
function water1Flow() {    this.body.velocity.x = 100;}
Link to comment
Share on other sites



thanks for the reply! I made the change but unfortunately had the same end result. Here I included:

function water1Flow() {    player.body.velocity.x = 100;    console.log(player.body.velocity.x);}

The result is, that as soon as I hit the "water" tile, the console begins printing out "100"'s like crazy. However, the player sprite remains still...


Perhaps it's something in the way I'm defining movement?

    if (keyboard.isDown(Phaser.Keyboard.A)) {        player.body.velocity.x = -150;    } else if (keyboard.isDown(Phaser.Keyboard.D)) {        player.body.velocity.x = 150;    } else {        player.body.velocity.x = 0;    }    if (keyboard.isDown(Phaser.Keyboard.W)) {        player.body.velocity.y = -150;    } else if (keyboard.isDown(Phaser.Keyboard.S)) {        player.body.velocity.y = 150;    } else {        player.body.velocity.y = 0;    }

Any ideas are appreciated! 

Link to comment
Share on other sites



I tried 

function water1Flow() {    player.body.gravity.x = 100;}

but without luck. The player sprite moves, but negligibly. I believe that the " } else { player.body.velocity.x = 0; } " is inhibiting movement in the case of using the body.gravity property, but I'm not sure how to alleviate that.

Link to comment
Share on other sites

I think the issue is due to you setting, rather than adding, velocity. Typically when moving via velocity, you want to set the initial velocity, and then add to or subtract from that velocity to change it - otherwise you may as well set body.moves = false and handle the positioning yourself.


What you could do if you want to keep this way of doing it is add a new Phaser.Point to your player called 'externalForce' and add another called 'force' on any tiles that you want to impart a force on the player, then change the externalForce when the player is touching a tile which has a force property, then finally you can add the externalForce to the player's normal movement velocities. So where you create your player, do this:

player.externalForce = new Phaser.Point(0, 0);

Ensure all of your force-imparting tiles are in a single group or array called something like 'forceTiles' and on each do the following:

// this tile adds a velocity of 100 to the x axis of the player, moving it right;// use -100 to move the player left insteadtile.force = new Phaser.Point(100, 0); 

Then change your movement loop to this:

    if (keyboard.isDown(Phaser.Keyboard.A)) {        player.body.velocity.x = -150 + player.externalForce.x;    } else if (keyboard.isDown(Phaser.Keyboard.D)) {        player.body.velocity.x = 150 + player.externalForce.x;    } else {        player.body.velocity.x = 0 + player.externalForce.x;    }     if (keyboard.isDown(Phaser.Keyboard.W)) {        player.body.velocity.y = -150 + player.externalForce.y;    } else if (keyboard.isDown(Phaser.Keyboard.S)) {        player.body.velocity.y = 150 + player.externalForce.y;    } else {        player.body.velocity.y = 0 + player.externalForce.y;    }

Then instead of separate waterFlow functions just create one called applyForceTile:

function applyForceTile(player, tile) {    // does this tile have a force?    if (tile.force) {      // if so, add its x and y values to the player's externalForce      player.externalForce.add(tile.force.x, tile.force.y);    }}

Finally you need to ensure you zero the externalForce when the player isn't touching anything:

    // if we're not overlapping a force tile, zero the external force    if (!game.physics.arcade.overlap(player, forceTiles, applyForceTile, null, this)) {      player.externalForce.setTo(0, 0);    };

The above gives you a clean way of applying arbitrary forces per tile with a single overlap loop, and you can make your forces go in any direction, so you can have things like gravity lifts, boost pads and so on.

Link to comment
Share on other sites

Hey lewster32,


Thank you again for your help. However, the mechanics did not quite work as I would have liked. Instead of applying a static velocity when the player and the tile sprites overlap, the velocity is compounded. So that, although it starts out at the desired value, it quickly accelerates, giving the player no hope of "swimming up-stream" as it were. For instance, with the initial force set to 150, and adding a console.log() line in the function, the results are:


and so on.

Link to comment
Share on other sites

Oops, the bug is in applyForce, which is adding the velocity every frame - instead it should be setting it:

function applyForceTile(player, tile) {    // does this tile have a force?    if (tile.force) {      // if so, set the externalForce values to be the same as the tile's force values      player.externalForce.copyFrom(tile.force);    }}
Link to comment
Share on other sites

Hey Lewster32 - I will try again a bit later, and update this post. I really appreciate your help though! The Phaser examples that are included with the framework are wonderful, and usually succeed in getting me over these little humps and on my way - but this one has been a stumper. Being new to all of this, I really appreciate your willingness to show how it's done!

Link to comment
Share on other sites


  • Recently Browsing   0 members

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