engine icon indicating copy to clipboard operation
engine copied to clipboard

Entity.getPosition is sometimes wrong after teleport

Open ludovit-as opened this issue 6 months ago • 8 comments

When reading the entity's position after a teleport, the position is sometimes the new and correct one, and sometimes the old one from before the teleport.

Project to reproduce: https://playcanvas.com/editor/scene/2276474

ludovit-as avatar Jul 07 '25 10:07 ludovit-as

How do I reproduce the bug? I refreshed multiple times, but don't see any issue in the console.

Image

LeXXik avatar Jul 07 '25 11:07 LeXXik

Well, all I can say is to refresh more, I tried to debug it for a couple of hours already, and have absolutely no idea why this is happening

Image

ludovit-as avatar Jul 07 '25 11:07 ludovit-as

The source of the bad position data is coming from the _updateDynamic method of RigidBodyComponent, this part in particular:

            const motionState = body.getMotionState();
            if (motionState) {
                const entity = this.entity;

                motionState.getWorldTransform(_ammoTransform);

                const p = _ammoTransform.getOrigin();
                const q = _ammoTransform.getRotation();

The question is why is the old position stored in the motion state

ludovit-as avatar Jul 07 '25 11:07 ludovit-as

~~I see it. This is probably due to #7769.~~ The issue I mentioned is not valid, so there must be something else in play here.

LeXXik avatar Jul 07 '25 11:07 LeXXik

I've looked into it a bit. The issue is that when you teleport a body, its motion state is not updated, unless it is a kinematic body.

https://github.com/playcanvas/engine/blob/7b4f9c0c08a3a22e9c9197a300ab75ca613ed24f/src/framework/components/rigid-body/component.js#L1059-L1064

You need to wait for the physics to step, which happens after your script update. If the new position is needed right after teleport, you can either use the new position directly (since you are teleporting to it, instead of reading entity position), or you can read it in postUpdate method, after the physics have stepped.

LeXXik avatar Jul 08 '25 09:07 LeXXik

Thanks for the investigation @LeXXik , that is great. Is there anything that can be done to improve this, like copying the teleporting position to motion state? Or is it better to leave it as is.

mvaligursky avatar Jul 08 '25 09:07 mvaligursky

In my framework with Jolt, I do update the motion state of a body after a teleport, unless it is a static one. Works great. We could change the guard here to avoid a static body, instead of only accepting kinematic one. Its a safe operation.

Edit: We'd need to check when the entity transform would get that new position from the motion state, though.

LeXXik avatar Jul 08 '25 10:07 LeXXik

You need to wait for the physics to step, which happens after your script update. If the new position is needed right after teleport, you can either use the new position directly (since you are teleporting to it, instead of reading entity position), or you can read it in postUpdate method, after the physics have stepped.

In such a situation, fixedUpdate would help, which makes the physics behavior predictable in the update method.

... fixedUpdate() <- here make teleport physicsFixedUpdate() ... update() <- here get position after teleport

AlexAPPi avatar Jul 09 '25 09:07 AlexAPPi