Grab an object & hit a wall make me fly away

Hi
I’ve implemented a script which allows me to grab objects. But when i hit something with the object i’m holding, its propulsing me in the opposite direction. How can i fix this ?

Is there a way to diseable the physics of the object i’m holding ?
Should i just drop the object i’m holding in case of collision ?

I’m getting stuck here. Help !

here is my code so far :

using UnityEngine;
using System.Collections;

public class GrabAndDrop : MonoBehaviour {

    GameObject grabbedObject;
    float grabbedObjectSize;

    // Use this for initialization
    void Start () {
   
    }

    GameObject GetMouseHoverObject(float range){
        Vector3 position = transform.position;
        RaycastHit raycastHit;
        Vector3 target = position + Camera.main.transform.forward * range;

        if (Physics.Linecast (position, target, out raycastHit)) {
            return raycastHit.collider.gameObject;
        } else
            return null;
    }

    void TryGrabObject(GameObject grabObject){
        if (grabObject == null || !CanGrab(grabObject))
            return;

        grabbedObject = grabObject;
        grabbedObjectSize = grabObject.GetComponent<Collider> ().bounds.size.magnitude;
    }

    void DropObject()
    {
        if (grabbedObject == null)
            return;
        if (grabbedObject.GetComponent<Rigidbody> () != null)
            grabbedObject.GetComponent<Rigidbody> ().velocity = Vector3.zero;
        grabbedObject = null;

    }

    bool CanGrab(GameObject candidate){
        return candidate.GetComponent<Rigidbody> () != null;
    }


    // Update is called once per frame
    void Update () {
        if (Input.GetKeyDown (KeyCode.E)) {
            if (grabbedObject == null)
                TryGrabObject (GetMouseHoverObject (5));
            else
                DropObject ();
        }

        if(grabbedObject != null){
            Vector3 newposition = transform.position + Camera.main.transform.forward*grabbedObjectSize/2;
            grabbedObject.transform.position = newposition;
        }

    }
}

Switching the object you’re holding to kinematic will stop physics from being calculated on it.

Thx !

It works fine now, exept that my grabbed object is now able to pass throught other object, like wall. I can drop it under the ground per examble, which is very problematic.

It works fine when i hit a rigidbody, but if the object i hit is not a rigidbody, the collide box is not working :confused:

How can i fix that ?

instead of turning on iskinmatic you could try turning off use gravity. just a guess but it might work

A couple of things.

  • You want to keep kinematics enabled and disable gravity instead. This ensures that the collisions with other objects are correct.

  • You need to cancel the velocity and torque of the object when you pick it up. Otherwise, if you grab a moving object and let go, it will continue moving as if you haven’t caught it.

  • There are some performance optimizations you should do. I will come back to this later, once I get back from University. I really don’t want to write this on my smartphone.

  • Here’s the algorithm to prevent objects from going through walls:

  • Disable collision.

  • Move the object to the origin of your raycast (Camera position)

  • Raycast in the desired direction from each point of the bounding box (8 racists in 3d).

  • Find the shortest hit distance

  • Move the object by this distance along the desired direction

  • Enable collision

thx, i’ll try that

Earlier I talked about some optimizations, but after reading through your code again, I realize that there is a chance that don’t apply in your case. The reason for this is that you apparently want to allow the player to pick up every object that has a rigidbody.
Two simple questions:
Will there be a lot of them?
Are the objects currently in the default layer?

There is only 3 identicals objects i want to grab in my game. In the first place i wanted to create a tag for grabable object but since you can only put one tag on a single object, i chose a easyer solution.

“Are the objects currently in the default layer?” I’m afraid i don’t understand this question : p

I see. What you should have used is layers.
Under Edit/Project Settings/Tags & Layers choose layers and add a layer like “Grabbable” or something.
Then set those objects you can pick up to that layer. You can find the setting right next to the tag, underneath their names.

Layers have various powerful uses. The first one is that you can use the layer collision matrix (Edit/Project Settings/Physics), which let’s you define which layers collide with each other. Say you don’t want that grabbable objects collide with each other, because the player could abuse this to stack them and jump out of your level.
You simply untick the checkbox “Grabbable - Grabbable” and they won’t collide with each other anymore.

Another one is when using ray-/sphere/…-casts. You can use layer masks to define what layers your ray-/sphere/…-casts collide with. Say your “Grabbable” layer is layer number 8 (in the list where you created it).

// This collides with everything, grabbable or not
Physics.Linecast (position, target, out raycastHit))

// This ONLY collides with objects on layer 8.
// Your level and objects that cannot be grabbed don't exist for your Linecast
Physics.Linecast (position, target, out raycastHit, 1 << 8))

The difference is that now you know that your Linecast will either hit an object that you can definitively pick up, or nothing. This means that you can now safely merge some funtions and remove CanGrab(), because as soon as »something« is hit, it is guaranteed to be grabbable. :wink:

Quickly written prototype

using UnityEngine;
using System.Collections;

public class GrabAndDrop : MonoBehaviour {
    private Transform transform;
    private Rigidbody grabbedBody;

    private void Awake() {
        transfrom = GetComponent<Transform>();
    }

    private void TryGrabObject() {
        Vector3 position = transform.position;
        RaycastHit raycastHit;
        Vector3 target = position + Camera.main.transform.forward * range;

        if (Physics.Linecast(position, target, out raycastHit, 1 << 8)) {
            grabbedBody = raycastHit.collider.gameobject.GetComponent<Rigidbody>();
        }
    }

    private void DropObject() {
        grabbedBody.velocity = Vector3.zero;
        grabbedBody.angularVelocity = Vector3.zero;
        grabbedBody = null;
    }

    private void Update() {
        if (Input.GetKeyDown(KeyCode.E)) {
            if (!grabbedBody) {
                TryGrabObject();
            }
            else {
                DropObject();
            }
        }
        else {
            // Move the object with my algorithm from earlier
        }
    }
}

I don’t guarantee that I haven’t made any mistake because I did not test this code.

1 Like

Thanks a billion time for this lesson :wink:

Oh man that line cracked me up - sorry to go off topic but very humorous autocorrect there. What to do about all those 3d racists! Hahaha mannn.

1 Like

Whoa. :hushed:
SwiftKey, what the fuck?