How to pre-calculate a physics simulation

Hi everybody,
what I am trying to achieve is simulating a physics scenario only in-memory (without rendering) and taking note of the position of my object in an array for each step of the simulation. The simulation has complex collisions, so it is not possible to use math formulas of some sort.

I tried to use the step function, outside the update method, but the position of the object does not change of an inch:

	const { world } = this.physics;

	world.on("worldstep", () => { // this callback is correctly invoked
		console.log(ball.x); // it does not change
	});

	for (let i = 0; i < 10000; i++) {
		world.step();
		// world.update(0, world._frameTimeMS); // I tried also this, but no difference
	}

I tried with both arcade.customUpdate true and false.

Is what I am trying to do even possible with Phaser?

If you don’t need rendering, turn on customUpdate and call step() directly, then read the body values.

const { world } = this.physics;

// Step length in seconds (default 0.166).
const delta = world._frameTime;

for (let i = 0; i < 10000; i++) {
  world.step(delta);

  // RIP console
  console.log(ball.body.x);
}

Hi @samme, this is what I tried but I get an incomprehensible behaviour.

Although the position of the body changes, it does it only by a few pixels. Something completely different from the rendered simulation.

That’s odd. It should move a few pixels each step, depending on velocity.

This will skip any update() functions outside of physics (e.g. the scene update()).

I isolated the relevant part of the code, such that the behaviour changes only if I change the customUpdate config option. The two resulting arrays are completely different. Do you see something wrong?

		this.visible = true;
		const xPositions = [];
		const yPositions = [];

		this.reset();
		this.body.setAllowGravity(true);
		this.body.setVelocityX(200);
		this.body.setVelocityY(200);

		console.log(`customUpdate is ${scnGame.physics.config.customUpdate}`);

		if (scnGame.physics.config.customUpdate) {
			const { world } = scnGame.physics;

			const delta = world._frameTime;

			for (let i = 0; i < 100; i++) {
				world.step(delta);
				xPositions.push(Math.round(this.body.x));
				yPositions.push(Math.round(this.body.y));
			}

			console.log({
				x: xPositions,
				y: yPositions,
			});
		} else {
			const updateHandler = () => {
				xPositions.push(Math.round(this.x));
				yPositions.push(Math.round(this.y));

				if (xPositions.length === 100) {
					console.log({
						x: xPositions,
						y: yPositions,
					});
				}
			};
			scnGame.events.on("update", updateHandler);
		}

Not sure. Try using

world.update(0, world._frameTimeMS);

instead of step().

I tried. The result array is different from the one obtained with step, but it is even more weird: the body position never changed.

I forgot world.update() won’t work by itself. You can try

world.update(0, world._frameTimeMS);
world.postUpdate();
1 Like

Oh yeah, that works! Thank you @samme, you’re the best.

I guess the step method is broken then (and the documentation incomplete). Gonna raise an issue on GH later.

Created this pull request.

I think step works correctly.

Not sure, not under every conditions at least.

How would you explain that it fails in my case, whereas it works with the update and postUpdate methods?

Step operates on physics bodies only. You need to read the body coordinates to see the results. Also body coordinates and game object coordinates are distinct so you can’t compare them directly. I didn’t notice that in the code above, sorry.

If you want to match how the scene works when custom update is off, you need to use update + postUpdate instead of step, that’s true.

This is code I run when the customUpdate is true:

			const { world } = scnGame.physics;

			for (let i = 0; i < 100; i++) {
				world.step(world._frameTime);
				xPositions.push(Math.round(this.body.x));
				yPositions.push(Math.round(this.body.y));
			}

			console.log({
				x: xPositions,
				y: yPositions,
			});

As you can see, I read only the body coordinates, not the gameObject’s ones. That returned body positions are not coherent with the real simulation.

The only thing I then changed, was this line:

world.step(world._frameTime);

with these lines:

world.update(0, world._frameTimeMS);
world.postUpdate();

and everything worked as expected.

To me, this smells as something is wrong with the World step method. Or, as I tend to think, its purpose is not the one that a developer can interfere from the official documentation.

The step method should be basically considered as internal, and the developer should be provided with a more straightforward method, called singleStep, which does what one could expect. Hence the pull request.