Physics Running Faster in Browser

I’m having a strange problem, the physics in my game is running faster in a browser than it is in the simulator. In my game, I can aim in 360 degrees and fire off a shot. The shot (a rigidbody attached to a sprite, not a bullet) is always given the same speed, and is fired off in the direction the player aimed. The shot is moved by setting its linear velocity. I have an array of unit vectors for each degree in all 360 degrees, and I multiply the unit vector by my speed (set to 500 always) to calculate velocity.

In the simulator, everything looks as I expect. In the browser, the shot moves way faster than I expect. I placed some log statements and found out how far the shot fires the first frame after velocity is applied:

Shot position after frame 1 (Simulator): (-2.58, 7.93, 0.00) dt: 0.016667999999999666

Shot position after frame 1 (Browser): (-2.22, 8.03, 0.00) dt: 0.006881000000000313

This is a 2D game so I’ll ignore z values. In the simulator the shot moves from (0, 0) to (-2.58, 7.93) in 0.01667 seconds (60fps). This is what I expect, the distance traveled is 7.717 , the frames per second is 60.

Looking at the browser, the shot moves from (0, 0) to (-2.22, 8.03). A similar distance traveled of 7.499, however it did so in 0.006881 seconds. It traveled almost the same exact distance in one frame at 145fps in the browser as it did in 60fps in the simulator.

I’ve tried to cap the frame rate to 60fps in the browser by calling:

cc.game.setFrameRate(60);

But that doesn’t seem to have an effect on anything.

Am I doing something wrong? This behavior makes no sense to me, I feel like the fix is something completely obvious that I’m missing here. Any help would be appreciated, thanks!

Seems like the problem shows up when I’m working on my Windows 10 machine (tried with both Edge and Firefox).

On Mac using Brave, everything works fine and the frame rate is limited to 60fps in both simulator and browser. This is weird.

The physics engine - box2d - runs at a fixed timestep of 1/60, as you can see here: https://github.com/cocos-creator/engine/blob/master/cocos2d/core/physics/CCPhysicsManager.js

It’s weird that capping the game fps doesn’t’ work though.

Yeah, that’s why I tried an FPS cap of 60 to see if the problem would go away. Not really sure what’s going wrong here, maybe the problem is that setFrameRate() isn’t working properly.

Anyway I give up, I have bigger fish to fry at the moment. I guess I just won’t release a web version.

out of curiosity, when you build the web version, in the resulting main.js, what value does the frameRate has? should be in an option object, something like:

var option = {
        // stuff
        frameRate: 60,
       // more stuff
    };

Had some free time so I looked further into this issue, I’m seeing a few weird things going on:

  1. It looks like I am getting strange behavior if I set the FPS (using cc.Game.setFrameRate) to 30 or 60. Setting the FPS to 59 or 61 essentially solves my problem, but then my game is running at a strange frame rate.

  2. If I set the FPS to higher than what my device’s performance allows (e.g. I set to 60 but can only run at ~20fps), the physics runs slowly (rigid bodies move slower than what their velocities/impluses should be). I suppose that’s not surprising.

Also, the device I’m experiencing issues on has a display refresh rate of 144Hz. On my Mac, where the refresh rate is 60Hz, I don’t see any problems.

On the 144Hz machine, if I set the FPS to 60, it appears to run at the refresh rate of the device: 144Hz. If I set it to 30, it appears to run at half the refresh rate: 72fps.

I am kind of wondering if there is an issue/bug with the cc.Game._setAnimFrame() function. Specifically the else case for where the frame rate is not 60 or 30:

_setAnimFrame: function () {

	...

	if (CC_JSB || CC_RUNTIME) {
	    jsb.setPreferredFramesPerSecond(frameRate);
	    window.requestAnimFrame = window.requestAnimationFrame;
	    window.cancelAnimFrame = window.cancelAnimationFrame;
	}
	else {
	    if (frameRate !== 60 && frameRate !== 30) {
	        window.requestAnimFrame = this._stTime;
	        window.cancelAnimFrame = this._ctTime;
	    }
	    else {
	    	// Is there possibly an error in the logic here?
	    }
	}
},