Search Unity

Carrying rigidbodies

Discussion in 'Scripting' started by pauliina, Jan 18, 2016.

  1. pauliina

    pauliina

    Joined:
    Nov 15, 2015
    Posts:
    35
    Hi! I'm having a hard time understanding when to have what settings when it comes to rigidbodies etc. I've read the documentation, I've read in forums and I've googled it, but for some reason I still don't understand what to do in my situation. So, I'm making a game in 3D where the player can pick up a box. The goal is for it to be like in Portal. When it's picked up, I don't want it to be able to move or turn around, so I did some code so that when it's picked up it's kinematic, and when you drop it it isn't, and instead it has gravity (so that it actually drops to the floor, and doesn't stay in the air). This seems to work great for what I need, except that when it's picked up it goes through walls and floors. If I remove the kinematic, it doesn't go through walls/floors, but it doesn't stay at the same place if I go into a wall. Then, the box moves closer to the player and you can like make it fly away?? So, what do I do to make the box stay where it is at all times when being lifted, but not going through walls?

    Also, I don't know how to make it so that you can only pick up one box at a time. Because right now, when you press E, all boxes gets picked up. I want to have like, a raycast or collider/collision to detect that you're touching the box or is close to it, but I've tried everything I can find online, and nothing works. All codes I've tried makes it so that the box doesn't even get lifted.

    Here's my code:

    Code (CSharp):
    1. public class Pickup : MonoBehaviour {
    2.  
    3.     bool carrying = false;
    4.     public new Rigidbody rigidbody;
    5.  
    6.     // Use this for initialization
    7.     void Start () {
    8.         this.rigidbody = this.GetComponent<Rigidbody>();
    9.     }
    10.  
    11.         // Update is called once per frame
    12.         void Update () {
    13.  
    14.         //carrying
    15.         if (gameObject.transform.parent == Camera.main.transform) {
    16.             carrying = true;
    17.         } else if (gameObject.transform.parent == null) {
    18.             carrying = false;
    19.         }
    20.  
    21.             // pick up box
    22.             if (Input.GetKeyDown(KeyCode.E) && !carrying) {
    23.             gameObject.transform.parent = Camera.main.transform;
    24.             rigidbody.isKinematic = true;
    25.             rigidbody.useGravity = false;
    26.         }
    27.  
    28.         // drop box
    29.         if (Input.GetKeyDown(KeyCode.E) && carrying) {
    30.             transform.parent = null;
    31.             rigidbody.isKinematic = false;
    32.             rigidbody.useGravity = true;
    33.         }
    34.     }
    35. }
     
  2. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    have you simply tried to attach it to the transform as a child and disable the rigidbody. When you drop it, you enable the rigidbody and detach it. This should accomplish what you are asking.
     
  3. mickmarona

    mickmarona

    Joined:
    Apr 7, 2015
    Posts:
    44
    I'd put an empty child gameobject onto the player indicating where I'd want the carried object to attempt to move towards, and have it lerp there with gravity turned off. This should cause the object to collide with things and stop when it hits an obstacle on the way to the target position. The kinematic setting will cause the rigidbody to ignore physics, so you shouldn't use it in this case.
     
  4. pauliina

    pauliina

    Joined:
    Nov 15, 2015
    Posts:
    35
    Hmm, how do I do this? Sounds promising. I don't fully understand it though (particularly the "attach it to the transform as a child"). Maybe I should mention that I'm using a Character controller, if that changes anything.
     
  5. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    To do this, we will need to recognize that Unity wont just let you turn rigidbodies off. which is sad.

    However, you can copy them, then disable them and remove the rigidbody.

    The next thing you will have to remember is that this object MUST use rigidbody movement and CANNOT be a CharacterController or numeric controlled object in any way.

    Given that, this code "should" work:


    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PickupController : MonoBehaviour
    5. {
    6.     private GameObject carrying;
    7.     private GameObject carryingHidden;
    8.  
    9.     // Use this for initialization
    10.     void Start()
    11.     {
    12.     }
    13.  
    14.     // Update is called once per frame
    15.     void Update()
    16.     {
    17.         Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
    18.         Rigidbody rigidbody;
    19.         if (carrying != null) {
    20.             // set the cursor as needed.
    21.             //http://docs.unity3d.com/ScriptReference/Cursor.SetCursor.html
    22.             //Cursor.SetCursor(cursorDropTexture, Vector2.zero, CursorMode.Auto);
    23.  
    24.             if (Input.GetKeyDown(KeyCode.E)) {
    25.                 // reposition the hidden object back to the original.
    26.                 carryingHidden.transform.position = carrying.transform.position;
    27.                 carryingHidden.transform.rotation = carrying.transform.rotation;
    28.  
    29.                 Destroy(carrying);
    30.                 carryingHidden.SetActive(true);
    31.  
    32.                 // drop any movement.
    33.                 rigidbody = carryingHidden.GetComponentInChildren<Rigidbody>();
    34.                 if (rigidbody != null) {
    35.                     rigidbody.velocity = Vector3.zero;
    36.                     rigidbody.angularVelocity = Vector3.zero;
    37.                 }
    38.  
    39.                 // clear the variables
    40.                 carrying = null;
    41.                 carryingHidden = null;
    42.             }
    43.             // get out, so we dont pick up something else this frame.
    44.             return;
    45.         }
    46.  
    47.         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    48.         RaycastHit hit;
    49.         if (Physics.Raycast(ray, out hit)) {
    50.             // set the cursor to the default
    51.            
    52.             if (hit.collider.gameObject.CompareTag("Collectible")) {
    53.                 //http://docs.unity3d.com/ScriptReference/Cursor.SetCursor.html
    54.                 //Cursor.SetCursor(cursorPickupTexture, Vector2.zero, CursorMode.Auto);
    55.  
    56.                 if (Input.GetKeyDown(KeyCode.E)) {
    57.                     // collect the object we want.
    58.                     carryingHidden = hit.collider.gameObject;
    59.  
    60.                     // copy that object.
    61.                     carrying = (GameObject)Instantiate(carryingHidden, carryingHidden.transform.position, carryingHidden.transform.rotation);
    62.                     carryingHidden.SetActive(false);
    63.  
    64.                     // destroy any rigid bodies.
    65.                     Rigidbody[] bodies = carrying.GetComponentsInChildren<Rigidbody>();
    66.                     foreach (Rigidbody body in bodies) {
    67.                         Destroy(body);
    68.                     }
    69.  
    70.                     // parent the object.
    71.                     carrying.transform.parent = transform;
    72.  
    73.                     // set the cursor as needed.
    74.                     //http://docs.unity3d.com/ScriptReference/Cursor.SetCursor.html
    75.                     //Cursor.SetCursor(cursorDropTexture, Vector2.zero, CursorMode.Auto);
    76.                 }
    77.             }
    78.         }
    79.     }
    80. }
     
  6. pauliina

    pauliina

    Joined:
    Nov 15, 2015
    Posts:
    35
    I tried to do a lerp, but I just don't understand how to do it when it's towards a gameobject and not coordinates. I tried googling it, but I just end up with errors because I have a transform to a Vector3 or similar. So, how would I go about this?


    Tbh, this is way to complex for my current knowledge of programming. I don't understand most parts of it. I kinda hoped there would be a simple way of going about this, but maybe there isn't? I tried understanding and putting in your code, but it didn't work. I don't know how to do this at all since I am using a Character Controller for the player.
     
  7. pauliina

    pauliina

    Joined:
    Nov 15, 2015
    Posts:
    35
    I'm really trying to understand the code, as I can't find any other way of doing it. But I have no idea what the whole "set cursor as needed" means. Why do we change the cursor so often? What does that do? And why do we have to have rigidbodies, but then turn them off, and then on again? It seems so complicated.

    And it feels so sad that it has to be so complicated, when the code I have atm is looking perfect (except for going through walls) and is very simple. I thought I'd just have to add a couple of lines of code to make it work, but it seems like I have to find a completely different way of doing it.
     
  8. Hustenbonbon

    Hustenbonbon

    Joined:
    Jan 21, 2016
    Posts:
    1
    Lerping towards another object:
    Code (CSharp):
    1. GameObject b;
    2. transform.position = Vector3.Lerp(transform.position, b.transform.position, Time.deltaTime);
    (You should only do this when the RigidBody is kinematic)

    Setting another GameObject as parent:
    Code (CSharp):
    1. GameObject b;
    2. transform.SetParent(b.transform);
    Of course, instead of b, you should have a real GameObject you get from somewhere.
    No solution for your overall problem, but I thought I could answer your direct questions.
     
  9. mickmarona

    mickmarona

    Joined:
    Apr 7, 2015
    Posts:
    44
    You could try manipulating the rigidbody's velocity directly while it's under player control; you can get a direction for the object to move in by subtracting its position from the target's position, then setting the rb's velocity to the direction multiplied by a movement speed. Inevitably the distance between the object and the target will equate to zero, thus it moves nowhere when it's where it's supposed to be, while still stopping when it hits colliders.

    Code (CSharp):
    1. Vector3 dir = pickup.position - target.position;
    2. rigidbody.velocity = dir * speed;
    Might have to swap out what gets subtracted from what, but it should do what you need.
     
  10. pauliina

    pauliina

    Joined:
    Nov 15, 2015
    Posts:
    35
    Thanks! Just a question though, where would I put this code? What should I keep from my old code, and what can be deleted? (I don't understand if this is for the picking up or carrying, but I'm guessing the first?) And also, how do I write the target position? Thanks in advance!
     
  11. pauliina

    pauliina

    Joined:
    Nov 15, 2015
    Posts:
    35
    I've tried this a couple of times now, but I can't seem to get it to work, as I don't fully understand where to place it and if to remove some other code, and if so, what. I think it might be able to work, I just haven't done it right I guess. Because when I still parent the box to the camera, it looks like it could be possible, but it floats around a bit and when I press E it flies away. And, it never drops to the ground. And, it rotates a lot as soon as you pick it up.. If I remove the code that parents the box to the camera, it flies away immediately. And as soon as it touches a wall or the ground or whatever, it just flies away further. Could someone try and help me out? So far, my original code is the best, because at least then I can pick up one box, keep it there and then drop it, and that looks great, but, with that code it goes through walls... so, I don't knoww.

    EDIT: Here's what the code looks like when I tried to put in your code. This code is not working properly though, but maybe you can see why, as I can't.

    Code (CSharp):
    1.   bool carrying = false;
    2.     public new Rigidbody rigidbody;
    3.  
    4.     public Transform target;
    5.     public int speed;
    6.  
    7.     // Use this for initialization
    8.     void Start()
    9.     {
    10.         this.rigidbody = this.GetComponent<Rigidbody>();
    11.     }
    12.  
    13.     // Update is called once per frame
    14.     void Update()
    15.     {
    16.  
    17.         //carrying
    18.         if (gameObject.transform.parent == Camera.main.transform)
    19.         {
    20.             carrying = true;
    21.         }
    22.         else if (gameObject.transform.parent == null)
    23.         {
    24.             carrying = false;
    25.         }
    26.  
    27.         // pick up box
    28.         if (Input.GetKeyDown(KeyCode.E) && !carrying)
    29.         {
    30.             gameObject.transform.parent = Camera.main.transform;
    31.             Vector3 dir = rigidbody.position - target.position;
    32.             rigidbody.velocity = dir * speed;
    33.         }
    34.  
    35.         // drop box
    36.         if (Input.GetKeyDown(KeyCode.E) && carrying)
    37.         {
    38.             transform.parent = null;
    39.          
    40.         }
    41.     }
    42. }
     
  12. pauliina

    pauliina

    Joined:
    Nov 15, 2015
    Posts:
    35

    I'm now trying this again, as nothing seems to work out for me. However, I don't understand the whole "set the cursor as needed". I don't know what is needed, heh. I don't know what is supposed to happen there, or why, and what the cursor is/does. Could someone explain this, and/or give an example of what I could put in to the code where you wrote "set the cursor as needed" and "set the cursor to the default"? Thanks!

    Also, I get the error "The referenced script on this Behaviour (Game Object 'Cube') is missing!" when I tried putting in this code. But then, maybe that's just because I haven't written out all the if-statements where it's something with cursors, as I don't understand that part at all.
     
  13. Ysgramor

    Ysgramor

    Joined:
    Jan 23, 2014
    Posts:
    69
    attach object as child of player and then destroy the object rigidbody then set the object local position according ur desired position with player, when the object detach, add again the rigidbody
     
  14. pauliina

    pauliina

    Joined:
    Nov 15, 2015
    Posts:
    35
    I think that's what bigmisterb did, but I don't have enough knowledge to understand that code, so I haven't been able to get it to work yet. I don't know how to "set the object local position" nor the desired position. Or how to detach or add rigidbodies.
     
  15. pauliina

    pauliina

    Joined:
    Nov 15, 2015
    Posts:
    35
    Hmm, I managed to destroy the rigidbody when it's being picked up, and then I add it again once it's being dropped, and it seems to work great, except that it's still going through walls. How come? I thought getting rid of the rigidbody would remove that problem. It has a box collider and all, so it should be working, right?

    How do I "set the object local position according ur desired position with player"?
     
    Last edited: Jan 27, 2016
  16. pauliina

    pauliina

    Joined:
    Nov 15, 2015
    Posts:
    35
    Also, I don't understand why, but when I pick up the box, all boxes gets picked up, even if they're not nearby. I'm using raycast to see when a box is close, and it works as long as I only have one box in the level. But when I add more boxes it doesn't work. First of all, all boxes gets picked up at once, but also, I can only choose to pick up the first box, the other boxes don't work? I duplicated out the boxes, but I'm guessing that's the problem? How else do I go about having several boxes that work the same way? I feel so dumb.
     
  17. Ysgramor

    Ysgramor

    Joined:
    Jan 23, 2014
    Posts:
    69
    if ur player has rigidbody then all of its children who has collider will not going through other collider, since ure attach that object to player child then it'll not collide with wall

    the easiest way of setting ur local position with player is add some empty gameobject which attached to player then set that empty GO according ur desired position then attach ur object to that empty GO when picked.

    if ure didnt know some of script etc, just search here http://docs.unity3d.com/ScriptReference/

    maybe u can show ur code so the other here can solve ur problem.
     
    Last edited: Jan 28, 2016
  18. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    SetCursor sets the mouse on the screen. Setting it to Auto every frame means that you swap it out to the correct cursor for the envronment (usually a pointer) By setting it to the texture, you replace the pointer with a texture. This means that when you pick up an item, it changes the cursor to a special texture, then back when you drop the item.