[SOLVED] Setting linearVelocity freezes entity

I created an entity.mom property for shorthand access to the entity.rigidbody.linearVelocity property, but I was not successful and the entity acts as though there’s no velocity. No errors are shown; it just simply does not work. My project is here: https://playcanvas.com/editor/scene/578037
This is my code:

var Momentum = pc.createScript('momentum');

//Check if exists
function is(object) {return typeof(object) != "undefined";}

pc.Entity.prototype.ResetMomentum = function() {
    if (this.rigidbody) {
        this.mom = [];
        var vect = this.rigidbody.linearVelocity;
        this.mom.x = vect.x;
        this.mom.y = vect.y;
        this.mom.z = vect.z;
    }
};

// update code called every frame
Momentum.prototype.update = function(dt) {
    var entity = this.entity;
    
    if (is(entity.mom)) {
        //Something's wrong with entity.mom -------------------------
        //
        if (typeof(entity.mom) != "object" || typeof(entity.mom.x) != "number" || typeof(entity.mom.y) != "number" || typeof(entity.mom.z) != "number") {
            console.error("entity.mom must be an object with properties x, y, and z as numbers.");
            //Momentum is invalid, so create it again
            entity.ResetMomentum();
        }
        //
        // -----------------------------------------------------------
        
        //Set the velocity
        entity.rigidbody.linearVelocity = new pc.Vec3(entity.mom.x, entity.mom.y, entity.mom.z);
    }
    //Make momentum consistent with velocity
    entity.ResetMomentum();
    
    // -----------------------------------------------------------------------------
    //Do stuff with entity.mom
};

this.mom is a property on the script object but you try to access it via the entity: if (is(entity.mom)) { which will give you an undefined value.

Edit: This is wrong. I didn’t see pc.Entity.prototype.ResetMomentum when the `mom object is being set

This led me to the conclusion that this was not referencing the entity that I wanted it to so I changed the pc.Entity.prototype.ResetMomentum = function() { line to pc.GraphNode.prototype.ResetMomentum = function() {. Strangely, the entity remains frozen though.

I’m not 100% sure what you are trying to achieve here. Are you just trying to make a wrapper around setting entity.rigidbody.linearVelocity?

Yes, that is what I intend to accomplish.

The easiest thing to do is to create a function wrapper:

Momentum.prototype.setLinearVelocity = function(velocity) {
  this.entity.rigidbody.linearVelocity = velocity;
}

And call it like:

Momentum.prototype.update = function(dt) {
    /// Some code
    this.setLinearVelocity(new pc.Vec3(0, 0, 0));
    /// Some more code
};

Thanks for the fast response. Is there an way to do this without making “getter” and “setter” functions? I would prefer to just edit entity.mom.x and that would carry over into entity.rigidbody.linearVelocity.x, and likewise read entity.mom.x and that would give me entity.rigidbody.linearVelocity.x. Most of my code is ported from an engine that modifies momentum this way.

You can make it a property at best? The thing is is rigidBody.linearVelocity is a getter/setter property itself and not really an object and also has some logic on the getter and setter so you can’t just reference it with an alias.

Also, you can’t change rigidBody.linearVelocity.x directly. You have to set the whole property due to the extra logic in the setter in the engine. (aka rigidBody.linearVelocity = something).

    Object.defineProperty(RigidBodyComponent.prototype, "linearVelocity", {
        get: function() {
            if (!this.isKinematic()) {
                if (this.body) {
                    var vel = this.body.getLinearVelocity();
                    this._linearVelocity.set(vel.x(), vel.y(), vel.z());
                    return this._linearVelocity;
                }
            } else {
                return this._linearVelocity;
            }
        },
        set: function(lv) {
            this.activate();
            if (!this.isKinematic()) {
                var body = this.body;
                if (body) {
                    ammoVec1.setValue(lv.x, lv.y, lv.z);
                    body.setLinearVelocity(ammoVec1);
                }
            } else {
                this._linearVelocity.copy(lv);
            }
        },
    });

If you want to just change one of the properties, you unfortunately have to do the following:

var v = this.entity.rigidbody.linearVelocity;
v.x = 100;
this.entity.rigidbody.linearVelocity = v;

Thinking about it a bit more, you could make mom an object with x, y, z getters and setters that wrap the logic above.

(untested but you get the idea)

// Define the class of Mom somewhere in a JS file in the project.
pc.extend(pc, function () {
    Mom = function(rigidbody) {
        this.rb = rigidbody;
    };

    Mom.prototype = {};

    Object.defineProperty(Mom.prototype, 'x', {
        get: function () {
            return this.rb.linearVelocity.x;
        },
        set: function (value) {
            var v = this.entity.rigidbody.linearVelocity;
            v.x = value;
            this.rb.linearVelocity = v;
        }
    });

   // etc

    return {
        RigidBodyComponent: RigidBodyComponent
    };
}());
Momentum.prototype.initialize = function () {
    this.mom = new pc.Mom(this.entity.rigidbody);
    console.log(this.mom.x); // Should give you the linear velocity of x
}
1 Like

Thank you, this solved my problem. I had to modify the code as there were a few errors though; the updated code is below for anyone who has a similar issue:

// Define the class of Mom
pc.extend(pc, function () {
    //Constructor
    //the 'this' keyword in a constructor doesn't have a value; it's a substitute for the new object
    Mom = function(rigidbody) {
        this.rb = rigidbody;
    };

    Mom.prototype = {};
    
    Object.defineProperty(Mom.prototype, 'x', {
        get: function () {
            return this.rb.linearVelocity.x;
        },
        set: function (value) {
            var v = this.rb.linearVelocity;
            v.x = value;
            this.rb.linearVelocity = v;
        }
    });
    
    Object.defineProperty(Mom.prototype, 'y', {
        get: function () {
            return this.rb.linearVelocity.y;
        },
        set: function (value) {
            var v = this.rb.linearVelocity;
            v.y = value;
            this.rb.linearVelocity = v;
        }
    });
    
    Object.defineProperty(Mom.prototype, 'z', {
        get: function () {
            return this.rb.linearVelocity.z;
        },
        set: function (value) {
            var v = this.rb.linearVelocity;
            v.z = value;
            this.rb.linearVelocity = v;
        }
    });

    return {
        Mom: Mom
    };
}());