Advanced object pick up

Hi everyone first time posting here! Hope this is the right place to ask this question.

We (my team and I) are in need of some help, as we are making a horror game for a jam that ends in about 2 weeks. Our game is rather simple, pick up items, drop items off at set location, try not to die in the process.

We know of simple ways to have the player pick up items, however most simple methods involve the item disappearing into some invisible inventory. What we are wanting to do is something more advanced. Something that shows off the model to the player for closer inspection

Go to 1:32

This video from Allison Road shows off exactly what we are looking for. From what I can tell objects can be picked up and rotated in front of the camera, then placed back down to their original location.

Any clues how to achieve this effect?

Btw we are rather new to unity, so we may need a bit of explaining while we get familiar.*

A way too achieve this would be to either attach an empty gameobject to your character where you want the object to float or use the foward vector of the player to position the object.

Then have a script casting a ray from the camera to the center of the screen or the mouse (depending how you interact) you can get the hit object and if you press e store its original position and rotation, then move it to the location infront of you and make it a child object. If you also store a reference to the object you can do interactions with it while it floats infront of you.

2 Likes

What you want to do is have either the Camera or some other reference point for instance the barrel of a gun, to have the raycast begin.

With this simple GrabScript I can set the ‘origin’ to a fixed transform (if this is meant to be moved with parent I suggest parenting it). There is a property called ‘Origin’ that will check if ‘origin’ is assigned, if its NULL it will return the Camera’s transform and we will Recast from that.

‘raycastDistance’ is the maxDistance the raycast will go.
‘ObjectGrabbedEvent’ a UnityEvent event that will get fired when this event is invoked.
‘ObjectDroppedEvent’ a UnityEvent event that will get fired when this event is invoked.
‘grabObject’ the KeyCode to be used for Input (I used Mouse0 which is the left click).
‘grabableObjectLayer’ a filter to be used when raycasting, this is great so you don’t get a Transform you don’t want.
‘m_objectGrabbed’ cached reference to the object grabbed.

GrabScript.cs

using UnityEngine;
using System.Collections;

public class GrabScript : MonoBehaviour {
    [SerializeField] Transform origin; // Use this if you want to specify where you want the raycast to start firing. If not it will default to the Camera.
    [SerializeField] float raycastDistance; // The distance the ray cast will go from the origin/camera point.
    [SerializeField] ObjectGrabbedEvent onObjectGrabbed; // Events you can use to register when an object is grabbed.
    [SerializeField] ObjectDroppedEvent onObjectDropped; // Events you can use to register when an object is dropped.
    [SerializeField] KeyCode grabObject; // Hard coded keycode for grabbing an object.
    [SerializeField] LayerMask grabableObjectLayer;

    GameObject m_objectGrabbed;

    void Update() {
        if(Input.GetKeyDown(this.grabObject)) {
            RaycastHit hit;

            if(Physics.Raycast(this.Origin.position, this.Origin.forward, out hit, this.raycastDistance, this.grabableObjectLayer)) {
                this.m_objectGrabbed = hit.collider.gameObject;

                this.onObjectGrabbed.Invoke(this.m_objectGrabbed);
            }
        }

        if(Input.GetKeyUp(this.grabObject)) {
            if(this.m_objectGrabbed != null) {
                this.onObjectDropped.Invoke(this.m_objectGrabbed);

                this.m_objectGrabbed = null;
            }
        }
    }

    protected Transform Origin {
        get {
            if(this.origin == null) {
                return Camera.main.transform;
            } else {
                return this.origin;
            }
        }
    }

    public ObjectGrabbedEvent ObjectGrabbedEvent {
        get {
            return this.onObjectGrabbed;
        } set {
            this.onObjectGrabbed = value;
        }
    }

    public ObjectDroppedEvent ObjectDroppedEvent {
        get {
            return this.onObjectDropped;
        } set {
            this.onObjectDropped = value;
        }
    }
}

Custom events to be used with UnityEngine.Events namespace. By serializing them, they will show up in the inspector very convenient.

UnityEvents.cs

using UnityEngine;
using UnityEngine.Events;
using System.Collections;

[System.Serializable]
public class ObjectGrabbedEvent : UnityEvent<GameObject> { }

[System.Serializable]
public class ObjectDroppedEvent : UnityEvent<GameObject> { }

‘finalPosition’ the final transform for the object to move to.
‘speed’ how fast it moves to and from
‘rotationSpeed’ how fast it rotates to and from.
‘originalPosition’ cached position from where the object was grabbed.
‘originalRotation’ cached Quaternion from where the object was grabbed.
‘m_objectGrabbed’ cached reference to the gameObject grabbed.

GrabListener.cs

using UnityEngine;
using System.Collections;

public class GrabListener : MonoBehaviour {
    [SerializeField] Transform finalPosition;
    [SerializeField] float speed = 2.0f;
    [SerializeField] float rotationSpeed = 10.0f;

    Vector3 originalPosition;
    Quaternion originalRotation;
    GameObject m_objectGrabbed;

    public void ObjectGrabbed(GameObject objectGrabbed) {
        this.m_objectGrabbed = objectGrabbed;

        this.originalPosition = this.m_objectGrabbed.transform.position;
        this.originalRotation = this.m_objectGrabbed.transform.rotation;

        this.StopCoroutine("ReturnObjectBackPosition");
        this.StopCoroutine("ReturnObjectBackRotation");

        this.StartCoroutine("BringObjectForwardPosition");
        this.StartCoroutine("BringObjectForwardRotation");
    }

    public void ObjectDropped(GameObject objectDropped) {
        this.StopCoroutine("BringObjectForwardPosition");
        this.StopCoroutine("BringObjectForwardRotation");

        this.StartCoroutine("ReturnObjectBackPosition");
        this.StartCoroutine("ReturnObjectBackRotation");
    }

    IEnumerator BringObjectForwardPosition() {
        while(this.m_objectGrabbed.transform.position != this.finalPosition.position) {
            this.m_objectGrabbed.transform.position = Vector3.MoveTowards(this.m_objectGrabbed.transform.position, this.finalPosition.position, this.speed * Time.deltaTime);

            yield return null;
        }
    }

    IEnumerator BringObjectForwardRotation() {
        while(this.m_objectGrabbed.transform.rotation != this.finalPosition.rotation) {
            this.m_objectGrabbed.transform.rotation = Quaternion.RotateTowards(this.m_objectGrabbed.transform.rotation, this.finalPosition.rotation, this.rotationSpeed * Time.deltaTime);

            yield return null;
        }
    }

    IEnumerator ReturnObjectBackPosition() {
        while(this.m_objectGrabbed.transform.position != this.originalPosition) {
            this.m_objectGrabbed.transform.position = Vector3.MoveTowards(this.m_objectGrabbed.transform.position, this.originalPosition, this.speed * Time.deltaTime);

            yield return null;
        }
    }

    IEnumerator ReturnObjectBackRotation() {
        while(this.m_objectGrabbed.transform.rotation != this.originalRotation) {
            this.m_objectGrabbed.transform.rotation = Quaternion.RotateTowards(this.m_objectGrabbed.transform.rotation, this.originalRotation, this.rotationSpeed * Time.deltaTime);

            yield return null;
        }
    }
}

Hope this helps.

2197488–145862–Object Grab.unitypackage (4.38 KB)

2 Likes

Sorry for the late response guys, and thanks! We will look into the suggested solutions