[SOLVED] Pickup & throw objects

Project: PlayCanvas 3D HTML5 Game Engine

Hello good. It is happening to me that when I manage to grab an object from the scene, it inexplicably rotates when it is in the air and when it crosses collisions with walls or the floor. When the player drops the item, this item comes out with inexplicable force.

the first part is when the object is grabbed by an event:

(on file first-person-camera.js)

app.on('firstperson:interact', async function () {


....

....

switch (typeInteract) {

  case "pickable":
                        this.entity.pickedEntity = interactableEntities[i];
                        this.entity.pickedEntity.isPicking = true;
                        if (this.entity.pickedEntity.rigidbody) {
                            this.entity.pickedEntity.rigidbody.applyImpulse(0, 0, 0);
                            this.entity.pickedEntity.rigidbody.applyForce(0, 0, 0);
                            this.entity.pickedEntity.rigidbody.applyTorqueImpulse(0, 0, 0);
                            this.entity.pickedEntity.rigidbody.applyTorque(0, 0, 0);
                        }
                        this.entity.pickedEntity.distance = this.entity.pickedEntity.getPosition().distance(this.entity.cameraEntity.getPosition());
                        this.entity.pickedEntity.startPosition = new pc.Vec2();
                        this.entity.pickedEntity.startPosition.copy(this.entity.pickedEntity.getPosition());
						break;
}

}

This second stop is triggered when the user stops grabbing the object.

(on file first-person-camera.js)

 app.on('firstperson:interacted', async function () {
        if (this.entity.pickedEntity) {
            Ui.debug("UN picked: " + this.entity.pickedEntity.name, " THROW");
            var direction = this.entity.pickedEntity.getPosition().sub(this.entity.pickedEntity.startPosition).normalize();
            var force = direction.scale(1);

            if (this.entity.pickedEntity.rigidbody) {
                //this.entity.pickedEntity.rigidbody.enabled = true;
                this.entity.pickedEntity.rigidbody.applyImpulse(0, 0, 0);
                this.entity.pickedEntity.rigidbody.applyForce(0, 0, 0);
                this.entity.pickedEntity.rigidbody.applyTorqueImpulse(0, 0, 0);
                this.entity.pickedEntity.rigidbody.applyTorque(0, 0, 0);
                this.entity.pickedEntity.rigidbody.useGravity = true;
                this.entity.pickedEntity.rigidbody.enabled = false;
                this.entity.pickedEntity.rigidbody.enabled = true;
            }
            this.entity.pickedEntity.isPicking = false;
            this.entity.pickedEntity = null;
        }
    }, this);


When the user grabs the object, in the postUpdate() event, a block of code is executed as long as the pickedEntity is not null:

(on file first-person-camera.js)

        /*Also move picked entities*/
        if (this.entity.pickedEntity && this.cameraEntity) {
            var cameraPos = this.entity.cameraEntity.getPosition();
            var direction = this.entity.cameraEntity.forward;
            var targetPos = new pc.Vec3().add2(cameraPos, direction.scale(this.entity.pickedEntity.distance));
            if (this.entity.pickedEntity.rigidbody) {
                this.entity.pickedEntity.rigidbody.applyImpulse(0, 0, 0);
                this.entity.pickedEntity.rigidbody.applyForce(0, 0, 0);
                this.entity.pickedEntity.rigidbody.applyTorqueImpulse(0, 0, 0);
                this.entity.pickedEntity.rigidbody.applyTorque(0, 0, 0);
                this.entity.pickedEntity.rigidbody.teleport(targetPos);
                this.entity.pickedEntity.rigidbody.applyImpulse(0, 0, 0);
                this.entity.pickedEntity.rigidbody.applyForce(0, 0, 0);
                this.entity.pickedEntity.rigidbody.applyTorqueImpulse(0, 0, 0);
                this.entity.pickedEntity.rigidbody.applyTorque(0, 0, 0);

            } else {
                this.entity.pickedEntity.setPosition(targetPos);
            }
        }

Several problems arise:

  1. the picked up object should not go through collisions with static rigidbody
  2. The object should not spin or rotate on its own when going through static collisions
  3. The object when it is released, it seems that it is thrown with an astronomical force being that the forces are “off”.

Has anyone had something similar happen. Does anyone have any suggestions, I would greatly appreciate it.

thanks in advance

Hi @Xander_Dice!

Maybe my example project below can help you. (Unfortunately, this project has also problem 1).

https://playcanvas.com/project/874243/overview/drag-and-drop

Hi !! i solve it. Here is the solution:

im using Ammo.btPoint2PointConstraint combined with a “hook” entity . this hook entity creates and destroy in real time.

on the entity to be picked i put a script and these two methods:

  ///-------------------------------------------------------------
    ///ENTITY METHODS:
    ///-------------------------------------------------------------
    this.entity.pick = async function (fromEntity) {
        if (!fromEntity) return;
        if (!fromEntity.cameraEntity) return;

        var pickedEntity = this;


        pickedEntity.distance = pickedEntity.getPosition().distance(fromEntity.cameraEntity.getPosition());
        pickedEntity.startPosition = new pc.Vec2();
        pickedEntity.startPosition.copy(pickedEntity.getPosition());



        if (!pickedEntity.hookEntity) {
            pickedEntity.hookEntity = new pc.Entity();

            pickedEntity.hookEntity.addComponent("rigidbody", {
                type: pc.BODYTYPE_KINEMATIC
            });


            pickedEntity.hookEntity.addComponent("collision", {
                type: "box",
                halfExtents: new pc.Vec3(0.001, 0.001, 0.001)
            });

            /*
                        var material = new pc.StandardMaterial();
                        material.diffuse.set(1, 0, 0); // Rojo
                        pickedEntity.hookEntity.addComponent("render", {
                            type: 'sphere',
                            material: material
                        });
            */

            var pos = pickedEntity.getPosition().clone();
            pickedEntity.hookEntity.setPosition(pos);
            pickedEntity.hookEntity.rigidbody.teleport(pos);


            (pickedEntity.rigidbody || {}).type = pc.BODYTYPE_DYNAMIC;

            var rbA = pickedEntity.hookEntity.rigidbody.body;
            rbA.setCcdMotionThreshold(1);
            rbA.setCcdSweptSphereRadius(0.2);

            var rbB = pickedEntity.rigidbody.body;

            if (rbA && rbA) {
                pickedEntity.joint = new Ammo.btPoint2PointConstraint(rbA, rbB,
                    new Ammo.btVector3(0, 0, 0),
                    new Ammo.btVector3(0, 0, 0)
                );
                //this.joint.setAngularOnly(true);
                // Add joint to simulation
                pickedEntity._app.systems.rigidbody.dynamicsWorld.addConstraint(pickedEntity.joint, true);
            }


            //this._app.root.addChild(pickedEntity.hookEntity);

        }

    }

    this.entity.unpick = async function (fromEntity) {
        var pickedEntity = this;

        if ((pickedEntity.hookEntity || {}).rigidbody) {
            pickedEntity.hookEntity.rigidbody.enabled = false;
        }

        if (pickedEntity.joint) {
            this._app.systems.rigidbody.dynamicsWorld.removeConstraint(pickedEntity.joint);
            Ammo.destroy(pickedEntity.joint);
            delete pickedEntity.joint;
        }

        if (pickedEntity.hookEntity) {
            pickedEntity.hookEntity.destroy();
            delete pickedEntity.hookEntity;
        }
    }

then basicaly two event listeners:

 this.entity.on("interact", async function (fromEntity) {
        if (!fromEntity) return;
        if (!this.entity.canInteract) return;
        if (this.entity.isInteracting) return;
        this.entity.fromEntity = fromEntity;

        if (!this.interactEventBusy) {
            this.interactEventBusy = true;
                this.entity.isInteracting = true; //* IS INTERACTING MODE ON*/

                this.entity.pick(fromEntity);    // THE MAGIC

            this.interactEventBusy = false;
        }

    }, this);




    this.entity.on("interacted", async function (fromEntity) {
        if (!fromEntity) return;
        if (!this.entity.isInteracting) return;



                this.entity.unpick(fromEntity);
 
        this.entity.isInteracting = false; //* IS INTERACTING MODE OFF*/
        this.entity.fromEntity = null;

    }, this);

When user hold a key raises interact event on the target entity, when user leaves, raises intecated event.

and the last part in the “entity to be picked” script:

EntityEx.prototype.postUpdate = function (dt) {

        if (this.entity.fromEntity && this.entity.isInteracting && this.entity.fromEntity.cameraEntity) {



                    if (this.entity.hookEntity) {
                        var cameraPos = this.entity.fromEntity.cameraEntity.getPosition();
                        var direction = this.entity.fromEntity.cameraEntity.forward;
                        var targetPos = new pc.Vec3().add2(cameraPos, direction.scale(this.entity.distance));
                        if (this.entity.hookEntity.rigidbody) {
                            this.entity.hookEntity.rigidbody.teleport(targetPos);
                        } else {
                            this.entity.hookEntity.setPosition(targetPos);
                        }
                    }

        }
    }
}

this moves the hook “virtual” entity, and the atacked picked entity by the btPoint2PointConstraint.

Hope it helps some in the future !

Great! Does this method solve all your problems? It will be nice if I can see a sample project of your method as well.

yes of corse.

i update the scripts here

https://playcanvas.com/project/1115590/overview/catacumba

thanks a lot bro

1 Like