cannon.js icon indicating copy to clipboard operation
cannon.js copied to clipboard

Correct way to change a body's position and orientation?

Open josephrocca opened this issue 8 years ago • 13 comments

I want to change a body's position and orientation and reset all of its dynamic properties like velocity, angular velocity, and anything else that affects the simulation. Currently I use the following (where x, y, z is my new position and a, b, c, w is my new quaternion):

body.position.set(x, y, z);
body.quaternion.set(a, b, c, w);
body.velocity.set(0, 0, 0);
body.angularVelocity.set(0, 0, 0);

I'm wondering whether this is the most efficient way to do it and/or whether I've missed anything?

Thanks!

josephrocca avatar Jul 27 '15 08:07 josephrocca

Hi,

For many cases, your code should be fine. If you use interpolation, sleeping, or if you have custom force fields, you might want to add some more stuff. Here's some draft code to reset the (hopefully) whole state.

// Position
body.position.setZero();
body.previousPosition.setZero();
body.interpolatedPosition.setZero();
body.initPosition.setZero();

// orientation
body.quaternion.set(0,0,0,1);
body.initQuaternion.set(0,0,0,1);
body.previousQuaternion.set(0,0,0,1);
body.interpolatedQuaternion.set(0,0,0,1);

// Velocity
body.velocity.setZero();
body.initVelocity.setZero();
body.angularVelocity.setZero();
body.initAngularVelocity.setZero();

// Force
body.force.setZero();
body.torque.setZero();

// Sleep state reset
body.sleepState = 0;
body.timeLastSleepy = 0;
body._wakeUpAfterNarrowphase = false;

I've been wondering if this code should be in a method, but I'm not sure how... The position and interpolation stuff could fit in a .teleport(position, quaternion) method, but that would not cover velocity or force.

schteppe avatar Jul 27 '15 09:07 schteppe

Thanks! A teleport method would be fantastic - maybe with an option or two to handle the dynamic stuff?

josephrocca avatar Jul 27 '15 14:07 josephrocca

+1

ioquatix avatar Jan 31 '16 03:01 ioquatix

In addition, since I'm writing a game where I need to do key-frame physics synchronisation, it would be great to have a serialise and deserialise method which generates a JSON compatible array which clones exact object state so the physics can be copied from server to client.

ioquatix avatar Jan 31 '16 03:01 ioquatix

Okay, yeah, this is causing me problems. Trying to sync the state between the server and client is causing issues. If I sync all these values, should that (in theory) work?

ioquatix avatar Jan 31 '16 13:01 ioquatix

Here is a really quick hack to see if this would fix sync bugs I'm having.. doesn't seem to be working well.. any ideas?

CANNON.Body.prototype.serialize = function() {
    return [
        // Position
        this.position.x, this.position.y, this.position.z,
        this.previousPosition.x, this.previousPosition.y, this.previousPosition.z,
        this.interpolatedPosition.x, this.interpolatedPosition.y, this.interpolatedPosition.z,
        this.initPosition.x, this.initPosition.y, this.initPosition.z,

        // Orientation
        this.quaternion.x, this.quaternion.y, this.quaternion.z, this.quaternion.w,
        this.previousQuaternion.x, this.previousQuaternion.y, this.previousQuaternion.z, this.previousQuaternion.w,
        this.interpolatedQuaternion.x, this.interpolatedQuaternion.y, this.interpolatedQuaternion.z, this.interpolatedQuaternion.w,
        this.initQuaternion.x, this.initQuaternion.y, this.initQuaternion.z, this.initQuaternion.w,

        // Velocity
        this.velocity.x, this.velocity.y, this.velocity.z,
        this.initVelocity.x, this.initVelocity.y, this.initVelocity.z,
        this.angularVelocity.x, this.angularVelocity.y, this.angularVelocity.z,
        this.initAngularVelocity.x, this.initAngularVelocity.y, this.initAngularVelocity.z,

        this.force.x, this.force.y, this.force.z,
        this.torque.x, this.torque.y, this.torque.z,

        this.sleepState,
        this.timeLastSleepy,
        this._wakeUpAfterNarrowphase
    ];
}

CANNON.Body.prototype.deserialize = function(data) {
    this.position.set(data[0], data[1], data[2]);
    this.previousPosition.set(data[3], data[4], data[5]);
    this.interpolatedPosition.set(data[6], data[7], data[8]);
    this.initPosition.set(data[9], data[10], data[11]);

    // orientation
    this.quaternion.set(data[12], data[13], data[14], data[15]);
    this.previousQuaternion.set(data[16], data[17], data[18], data[19]);
    this.interpolatedQuaternion.set(data[20], data[21], data[22], data[23]);
    this.initQuaternion.set(data[24], data[25], data[26], data[27]);

    // Velocity
    this.velocity.set(data[28], data[29], data[30]);
    this.initVelocity.set(data[31], data[32], data[33]);
    this.angularVelocity.set(data[34], data[35], data[36]);
    this.initAngularVelocity.set(data[37], data[38], data[39]);

    // Force
    this.force.set(data[40], data[41], data[42]);
    this.torque.set(data[43], data[44], data[45]);

    // Sleep state reset
    this.sleepState = data[46];
    this.timeLastSleepy = data[47];
    this._wakeUpAfterNarrowphase = data[48];
}

ioquatix avatar Jan 31 '16 13:01 ioquatix

@ioquatix I made a serializer for p2.js, but I removed it after a while. It's a bit of work to maintain it, and in the end I realized that it's not being used in practice. You always want a custom file format for whatever you are building, so the only value in a serializer is just the knowledge how to serialize and deserialize a physics state.

Synchronizing those values should probably work for one given point in time. Do you use client side prediction or any similar algorithm? (This is a difficult problem you know - even the big game titles avoid this :P)

schteppe avatar Jan 31 '16 13:01 schteppe

@schteppe So we are using Node.js and running the physics both server and client side. The idea is to send keyframe sync but in general the two simulations run independently, but I'm seeing some pretty wonky behaviour, but most of the time it is working "reasonable". I've had a lot of issues with player movement.. This is a work in progress :)

I'd really appreciate if you have some time to check it out:

https://github.com/GameMechanicsSociety/warehouse

ioquatix avatar Jan 31 '16 13:01 ioquatix

I've just committed to the development branch, a commit that only does server side physics and has a client side update rate of 15 FPS., just FYI.

ioquatix avatar Jan 31 '16 13:01 ioquatix

Sorry to bother you but one more issue that comes up is that sometimes player cannot move. I wonder if they got stuck in the ground plane. I tried to add a small +ve Z value in applyImpulse but I'm not sure if that helps or not.

ioquatix avatar Jan 31 '16 13:01 ioquatix

@ioquatix All right. It should work perfectly for a single body without contacts. If you have contacts you should probably not touch the position or velocity. Maybe you can add a force toward the authoritative server position, and if the player is way off, teleport?

I never got client/server physics sync working - I've always avoided it because it's a really difficult problem.

Maybe you are interested in how UDK does it. For small corrections they add an impulse toward the server position. https://udn.epicgames.com/Three/NetworkingOverview.html

15FPS is probably too bad for rigid body physics. Probably works for game-specific physics like minecraft but for general rigid body simulation, probably not. Try this link, set FPS to 15 and drag the ragdoll around: https://schteppe.github.io/p2.js/demos/ragdoll.html

schteppe avatar Jan 31 '16 14:01 schteppe

+1 for teleport method :)

top-kat avatar Mar 04 '17 20:03 top-kat

+1 again for a teleport method. It would be great if the teleport method would not only handle position/rotation and interpolation for both, but also to change the direction of forces/impulses that are currently applied to move in the direction of the new rotation. That would be great!

MrSonicMaster avatar Sep 25 '18 21:09 MrSonicMaster