Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Grab an object & hit a wall make me fly away

Discussion in 'Scripting' started by Thibault-Potier, Apr 26, 2015.

  1. Thibault-Potier

    Thibault-Potier

    Joined:
    Apr 10, 2015
    Posts:
    206
    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 :

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class GrabAndDrop : MonoBehaviour {
    5.  
    6.     GameObject grabbedObject;
    7.     float grabbedObjectSize;
    8.  
    9.     // Use this for initialization
    10.     void Start () {
    11.    
    12.     }
    13.  
    14.     GameObject GetMouseHoverObject(float range){
    15.         Vector3 position = transform.position;
    16.         RaycastHit raycastHit;
    17.         Vector3 target = position + Camera.main.transform.forward * range;
    18.  
    19.         if (Physics.Linecast (position, target, out raycastHit)) {
    20.             return raycastHit.collider.gameObject;
    21.         } else
    22.             return null;
    23.     }
    24.  
    25.     void TryGrabObject(GameObject grabObject){
    26.         if (grabObject == null || !CanGrab(grabObject))
    27.             return;
    28.  
    29.         grabbedObject = grabObject;
    30.         grabbedObjectSize = grabObject.GetComponent<Collider> ().bounds.size.magnitude;
    31.     }
    32.  
    33.     void DropObject()
    34.     {
    35.         if (grabbedObject == null)
    36.             return;
    37.         if (grabbedObject.GetComponent<Rigidbody> () != null)
    38.             grabbedObject.GetComponent<Rigidbody> ().velocity = Vector3.zero;
    39.         grabbedObject = null;
    40.  
    41.     }
    42.  
    43.     bool CanGrab(GameObject candidate){
    44.         return candidate.GetComponent<Rigidbody> () != null;
    45.     }
    46.  
    47.  
    48.     // Update is called once per frame
    49.     void Update () {
    50.         if (Input.GetKeyDown (KeyCode.E)) {
    51.             if (grabbedObject == null)
    52.                 TryGrabObject (GetMouseHoverObject (5));
    53.             else
    54.                 DropObject ();
    55.         }
    56.  
    57.         if(grabbedObject != null){
    58.             Vector3 newposition = transform.position + Camera.main.transform.forward*grabbedObjectSize/2;
    59.             grabbedObject.transform.position = newposition;
    60.         }
    61.  
    62.     }
    63. }
    64.  
     
  2. Schneider21

    Schneider21

    Joined:
    Feb 6, 2014
    Posts:
    3,512
    Switching the object you're holding to kinematic will stop physics from being calculated on it.
     
  3. Thibault-Potier

    Thibault-Potier

    Joined:
    Apr 10, 2015
    Posts:
    206
  4. Thibault-Potier

    Thibault-Potier

    Joined:
    Apr 10, 2015
    Posts:
    206
    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 :/

    How can i fix that ?
     
  5. PvTGreg

    PvTGreg

    Joined:
    Jan 29, 2014
    Posts:
    365
    instead of turning on iskinmatic you could try turning off use gravity. just a guess but it might work
     
  6. TheSniperFan

    TheSniperFan

    Joined:
    Jul 18, 2013
    Posts:
    712
    A couple of things.
    1. You want to keep kinematics enabled and disable gravity instead. This ensures that the collisions with other objects are correct.
    2. 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.
    3. 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.
    4. Here's the algorithm to prevent objects from going through walls:

    1. Disable collision.
    2. Move the object to the origin of your raycast (Camera position)
    3. Raycast in the desired direction from each point of the bounding box (8 racists in 3d).
    4. Find the shortest hit distance
    5. Move the object by this distance along the desired direction
    6. Enable collision
     
    Last edited: Apr 27, 2015
  7. Thibault-Potier

    Thibault-Potier

    Joined:
    Apr 10, 2015
    Posts:
    206
    thx, i'll try that
     
  8. TheSniperFan

    TheSniperFan

    Joined:
    Jul 18, 2013
    Posts:
    712
    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?
     
  9. Thibault-Potier

    Thibault-Potier

    Joined:
    Apr 10, 2015
    Posts:
    206
    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
     
  10. TheSniperFan

    TheSniperFan

    Joined:
    Jul 18, 2013
    Posts:
    712
    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).

    Code (CSharp):
    1. // This collides with everything, grabbable or not
    2. Physics.Linecast (position, target, out raycastHit))
    3.  
    4. // This ONLY collides with objects on layer 8.
    5. // Your level and objects that cannot be grabbed don't exist for your Linecast
    6. 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. ;)


    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class GrabAndDrop : MonoBehaviour {
    5.     private Transform transform;
    6.     private Rigidbody grabbedBody;
    7.  
    8.     private void Awake() {
    9.         transfrom = GetComponent<Transform>();
    10.     }
    11.  
    12.     private void TryGrabObject() {
    13.         Vector3 position = transform.position;
    14.         RaycastHit raycastHit;
    15.         Vector3 target = position + Camera.main.transform.forward * range;
    16.  
    17.         if (Physics.Linecast(position, target, out raycastHit, 1 << 8)) {
    18.             grabbedBody = raycastHit.collider.gameobject.GetComponent<Rigidbody>();
    19.         }
    20.     }
    21.  
    22.     private void DropObject() {
    23.         grabbedBody.velocity = Vector3.zero;
    24.         grabbedBody.angularVelocity = Vector3.zero;
    25.         grabbedBody = null;
    26.     }
    27.  
    28.     private void Update() {
    29.         if (Input.GetKeyDown(KeyCode.E)) {
    30.             if (!grabbedBody) {
    31.                 TryGrabObject();
    32.             }
    33.             else {
    34.                 DropObject();
    35.             }
    36.         }
    37.         else {
    38.             // Move the object with my algorithm from earlier
    39.         }
    40.     }
    41. }

    I don't guarantee that I haven't made any mistake because I did not test this code.
     
    Thibault-Potier likes this.
  11. Thibault-Potier

    Thibault-Potier

    Joined:
    Apr 10, 2015
    Posts:
    206
    Thanks a billion time for this lesson ;)
     
  12. MD_Reptile

    MD_Reptile

    Joined:
    Jan 19, 2012
    Posts:
    2,664
    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.
     
    TheSniperFan likes this.
  13. TheSniperFan

    TheSniperFan

    Joined:
    Jul 18, 2013
    Posts:
    712
    Whoa. :eek:
    SwiftKey, what the F***?