Jump to content

Setting sprite mass causes strange behavior


CruelYodeler
 Share

Recommended Posts

I'm creating a game which contains simple puzzles. Early on, the player will have to push some crates out of the way to continue on. In my code here, I have two crates stacked on top of each other. As expected, when the player pushes against the bottom crate, it moves out of the way and the one on top falls to the ground. Now, this is where it gets tricky. I want there to be a delay once the player has collided with the crate before the crate can be pushed. I use "timers" (not really timers, but counters incremented in the update() function) to determine when to start playing the animation that shows the player pushing against the crates and when to actually start pushing the crates. I tried giving the crates a lot of mass to prevent the player from pushing them, but that causes the crates to go zooming away super fast from the player.

 

I could use a little help figuring this out. :)  I've tried a lot of different things but with no luck. I had a solution before which toggled the crates' immovable state, but that prevented the top box from falling after the bottom box was pushed out.


function create() {
game.world.setBounds(0, 0, 2000, 600);
game.physics.startSystem(Phaser.Physics.ARCADE);

solidPlatforms = game.add.group();
pushablePlatforms = game.add.group();
solidPlatforms.enableBody = true;
pushablePlatforms.enableBody = true;

var ground = solidPlatforms.create(0, game.world.height - 64, 'ground');
ground.scale.setTo(5, 2);
ground.body.immovable = true;

// two moveable crates
crate = pushablePlatforms.create(310, game.world.height - 142, 'crate1');
crate.body.gravity.y = 600;

crate = pushablePlatforms.create(300, game.world.height - 221, 'crate2');
crate.body.gravity.y = 600;

pushablePlatforms.setAll('body.mass', 99);

player = game.add.sprite(41, game.world.height - 130, 'robot');

game.physics.arcade.enable(player);
player.body.bounce.y = 0.2;
player.body.gravity.y = 600;
player.body.collideWorldBounds = true;

// Set player direction to the right
direction = 'right';

// Pushing animations, left and right
player.animations.add('push-left', [8, 9, 10, 11], 6, true);
player.animations.add('push-right', [12, 13, 14, 15], 6, true);

// Moving animations, left and right
player.animations.add('left', [0, 1, 2, 3], 10, true);
player.animations.add('right', [4, 5, 6, 7], 10, true);

player.body.setSize(37, 51, 2, 4);

// Initialize push timers
pushLeftTimer = 0;
pushRightTimer = 0;

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

game.camera.follow(player, Phaser.Camera.FOLLOW_PLATFORMER);
}

function update() {
game.physics.arcade.collide(player, solidPlatforms);
game.physics.arcade.collide(player, pushablePlatforms, platformCollisionHandler, null, this);
game.physics.arcade.collide(pushablePlatforms, solidPlatforms);
game.physics.arcade.collide(pushablePlatforms, pushablePlatforms);

player.body.velocity.x = 0;

if (cursors.left.isDown) {
// Set player direction to left
direction = 'left';
player.body.velocity.x = -150;

pushRightTimer = 0;
if (player.body.touching.left && player.body.touching.down) // Can only push while touching the ground
pushLeftTimer++;

if (pushLeftTimer > 15 && player.body.touching.down) {
// Play the pushing animation
player.animations.play('push-left');
} else {
stopPushingPlatforms();
player.animations.play('left');
}
} else if (cursors.right.isDown) {
// Set player direction to right
player.body.velocity.x = 150;

pushLeftTimer = 0;
if (player.body.touching.right && player.body.touching.down) // Can only push while touching the ground
pushRightTimer++;

if (pushRightTimer > 15 && player.body.touching.down) {
// Play the pushing animation
player.animations.play('push-right');
} else {
stopPushingPlatforms();
player.animations.play('right');
}
} else {
// Stand still
player.animations.stop();

// Stop pushing objects
stopPushingPlatforms();

// Reset both push timers
pushRightTimer = 0;
pushLeftTimer = 0;

// Reset player frame
if (direction == 'right') {
player.frame = 4;
} else {
player.frame = 0;
}
}

// Allow the player to jump if they are touching the ground.
if (cursors.up.isDown && player.body.touching.down)
{
// Reset both push timers
pushRightTimer = 0;
pushLeftTimer = 0;

player.body.velocity.y = -350;
}


}

function platformCollisionHandler(obj1, obj2) {
if (obj1.body.touching.down) {
if (pushRightTimer >= 80)
obj2.body.mass = 1;
else if (pushLeftTimer >= 80)
obj2.body.mass = 1;
else
obj2.body.mass = 999;
}
}

function stopPushingPlatforms() {
for (var i = 0; i < pushablePlatforms.children.length; i++) {
var platform = pushablePlatforms.children[i];

platform.body.velocity.x = 0;
}
}

Link to comment
Share on other sites

Mass I believe is only used to calculate how much momentum is transferred between two colliding objects, and doesn't work for constant forces such as this. Instead I think you could maybe temporarily zero the player's velocity.x when pushing against a crate, and then return it to normal after the timer ends so the player can then start pushing.

 

Also I think what you need to use is the body.drag property, which is basically the object's 'friction'. Setting the drag to high values will let you push objects but they will come to a stop very quickly - which means you can drop the 'stopPushingPlatforms' function.

Link to comment
Share on other sites

I've been playing with this for a little bit and come up with a quick, dirty and wholly unsatisfying solution: http://jsfiddle.net/lewster32/ba8x3/

 

It may serve as a start, but it has issues; crates can get pushed 'through' other crates, for instance. I feel a simpler and better solution is flittering around in my head somewhere but I can't seem to get at it right now.

Link to comment
Share on other sites

I had to scrap my solution because the physics were so buggy. I think your solution is definitely the way to go; there's just the one bug. I was able to determine that the crates don't trigger the collision handler (I added one to the collide function for the crates) when their sides touch. Even body.touching.left and body.touching.right return false for both crates.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

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