Inconsistent Physics & Movement


#1

I’m running into a problem with the gravity system lately that I don’t know how to solve.
I’m using impulses and delta time (dt) for movement, but the problem is there none the less.

When running the demo flappy bird game (https://playcanvas.com/project/375389/overview/flappy-bird) on weaker devices, the gameplay is inconsistent to how it runs on a good device. On a good device the pipes move fast and the bird can only do a solid 2 or 3 flaps. On a weaker device the bird can fit a good 5 flaps between pipes, clearly altering the gameplay in a significant way.

This problem exists in my own PlayCanvas game as well (https://playcanvas.com/project/599997/overview/hydra-run), and it’s very troubling to me. In my game, it changes the entire gameplay mechanic of jumping. For example, I expect the gravity system to make my character float down slower when the jump button is held, but instead the character just falls like a rock on weaker devices, making the game impossible for some people to play as intended.

Is there a way to fix this problem? If anybody has encountered it and knows a workaround, please let me know what I should do.


#2

The Flappy bird project doesn’t use the physics system. Looking @will code, there’s a bug in the pipe scrolling code where it doesn’t use dt to move the pipes so on lower framerates, it’s slower.

// update code called every frame
Scroll.prototype.update = function(dt) {
    var app = this.app;

    if (!this.frozen && !this.paused) {
        this.entity.translateLocal(this.speed, 0, 0); // <- dt not used here

        // Check to see if we've scrolled beyond the window...
        var pos = this.entity.getLocalPosition();
        if (pos.x < this.endX) {
            // Translate back to the start
            this.entity.translateLocal(this.startX - this.endX, 0, 0);
            app.fire(this.cycleEvent);
        }
    }
};

Can you point us to the area of code we should be looking at in your project for your issue?


#3

Thanks for the prompt reply, that info you provided is a relief to hear :slight_smile:

My problem is in my player movement script: https://playcanvas.com/editor/code/599997?tabs=17452076

While my script may be a bit of a mess to decipher since I’m terrible at Javascript, I think the problem lies in this code which is called in update(dt)


PlayerMovement.prototype.jump = function (dt) {
    if(self.jumpTimerRecent < 0) {
        if((self.onGround && this.entity.rigidbody.linearVelocity.y >= 0) || self.timeSinceCollision > 0) {
            this.entity.rigidbody.applyImpulse(0, this.initalJumpForce, 0);
            self.jumpTimerRecent = 0.1;
            self.jumpExtraTimeAllowed = this.extraJumpTime;
            self.timeOnGround = 0;
            this.app.fire("trigger:jumped");
        }
    }
    
    if(this.isJumping()) {
        if(self.jumpExtraTimeAllowed > 0) {
            this.entity.rigidbody.applyImpulse(0, this.extraJumpForce, 0);
        } else {
            // resistance force
            if(this.entity.rigidbody.linearVelocity.y < -0.5) {
                this.entity.rigidbody.applyImpulse(0, this.extraJumpForce*(-this.entity.rigidbody.linearVelocity.y*2), 0);
            }
        }
    }
};

Basically my script decrements jumpTimerRecent and jumpExtraTimeAllowed by dt in update, then:
The first “if” checks that the player has been on the ground for an adequate amount of time before allowing for a strong jump.
The second “if” checks if the player is now jumping (not on the ground)
and then if there’s still some extra jump boost remaining, allows the player to jump a little higher. Otherwise, as long as the player is falling, I apply a resistance force to break the fall. This part seems to be where the problem is and for some reason doesn’t behave the same on weaker devices. The resistance force simply works far less effectively, and the extra impulse just doesn’t add the same amount of boost as it does on a normal device.


#4

Looking at the code, you are applying impulse, not force to break the fall.


#5

Yeah, but should that make a difference? Why would the effect of the impulse vary?


#6

Impulse gives and immediate response. IE it sets the velocity. Force is like gravity, it applies acceleration over time.

Giving something impulse every frame is like being hit with a hammer each frame rather than being pushed.


#7

See the problem is that when I used forces for jumping, the jumps would occasionally result in massive and random variations. Now impulse seems to work perfectly for the initial jump, so I still don’t really understand why it’s bad for the continued jump.

In short, it sounds from your explanation like impulse is perfect for the initial jump and forces will be perfect for the variable jumping. I’ll try that, but let me know if there’s anything I’m still missing here. Aside from that, thanks!


#8

That’s because for jumping, you do want that instant, explosive impulse to get the player object to jump and you only use it in one frame, not over a series of frames.


#9

Conceptually now makes perfect sense, I really appreciate the explanation.