Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / game / Unity

Day 66 of 100 Days of VR: Picking up and Throwing Objects In Unity - Part 1

0.00/5 (No votes)
27 May 2018CPOL5 min read 1.8K  
We spent the past 2 days looking at how we can create an outline effect on our game object, now it’s time to move on to the fun part. Implementing the ability to throw game objects!

We spent the past 2 days looking at how we can create an outline effect on our game object, now it’s time to move on to the fun part. Implementing the ability to throw game objects!

The basic idea of it is simple. We have our Ball game object and we want to pick it up and throw it.

The interesting part is when we pick up the ball, how do we go about taking our throwing motion and propelling our ball into a certain direction.

Let’s find out how!

Grabbing and Throwing Objects

Part of the answer to the question I posed earlier is that we need to take advantage of Unity’s physics system!

To do that, we need to add a RigidBody component to our game object so Unity will use its physics system on our Ball.

Let’s add it in.

  1. In Ball, click Add New Component and select.

Now that we have a RigidBody, our game object will be affected by the game’s physics engine, such as gravity.

The next thing we need to think about before we jump into the code is how are we going to be able to detect when we selected a game object to throw?

To do that, we’re going to use the Event System that we already set. Specifically, we want the event to be PointerDown and PointerUp. When we’re holding down on the game object, we’re grabbing it and we let go, we would release the object that we’re holding on to.

At this point, we would normally think we should create a function in our existing Throwable script and attach that to our event.

However, let’s think a bit more about this. Our Throwable script doesn’t have access to the information needed on the controller and it shouldn’t.

Unity is great in that we can pretty much cram everything we want into one script and have references to everything, however that would create a jumble mess of spaghetti code. We can do better than that.

Instead what we’re going to do is create a PlayerController class to help divide some of our code to take care of selecting and releasing throwable game objects.

We’re going to attach this script to our GvrControllerPointer game object.

  1. In GvrControllerPointer, create a new script called
  2. I’ll give warning in other times, but in Player we should disable the Box Collider and the Mesh Renderer, from the initial cube we used, otherwise they’ll interfere with the controller.

Here’s the complete script for PlayerController.cs:

C#
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Throwable _grabbedThrowable;     // The object we're grabbing
    private Vector3 _currentGrabbedLocation; // The tracked location of our object 
                                             // for us to throw

    void Start ()
    {
        _grabbedThrowable = null;
        _currentGrabbedLocation = new Vector3();
    }
    
    void Update () {
        // If we're holding something, we want to keep track of its position
        // so we can later calculate the vector to throw our ball in.
        if (_grabbedThrowable != null)
        {
            _currentGrabbedLocation = _grabbedThrowable.transform.position;
        }
    }

    // Called by the Event System when we click on an object, receives a game object to hold.
    // The object given must have a throwable object, otherwise we don't do anything
    public void HoldGameObject(GameObject throwableObject)
    {
        Throwable throwable = throwableObject.GetComponent<Throwable>();
        if (throwable != null)
        {
            _grabbedThrowable = throwable;
            throwableObject.transform.parent = this.gameObject.transform;  // Set object as 
                                                    // a child so it'll follow our controller
            _grabbedThrowable.GetComponent<Rigidbody>().isKinematic = true; // Stops physics 
                                                    // from affecting the grabbed object
            _currentGrabbedLocation = _grabbedThrowable.transform.position; // Track the 
                                             // location of our object so we can throw it later
        }
    }

    // Called by the Event System when we release our click on a game object.
    // Release our held object and throw it based off our controller motino
    public void ReleaseGameObject()
    {
        // Only throw an object if we're holding onto something
        if (_grabbedThrowable != null)
        {
            _grabbedThrowable.transform.parent = null; // Un-parent throwable object 
                                                   // so it doesn't follow the controller
            Rigidbody rigidBody = _grabbedThrowable.GetComponent<Rigidbody>();
            rigidBody.isKinematic = false; // Re-enables the physics engine.
            Vector3 throwVector = _grabbedThrowable.transform.position - 
                         _currentGrabbedLocation; // Get the direction that we're throwing
            rigidBody.AddForce(throwVector * 10, ForceMode.Impulse); // Throws the ball 
                                                                     // by sending a force
            _grabbedThrowable = null;
        }
    }
}

As always, A LOT of time was spent trying to create this simple looking script. Let’s go through it. Later, we’re going to clean this up a bit.

Variables Used

This script only introduces 2 fields that we need to be aware of:

  • private Throwable _grabbedThrowable; – Holds a reference to the Throwable script of the object we’re grabbing
  • private Vector3 _currentGrabbedLocation; – Keeps a reference of the last location the game object we’re holding on to, so we can later use it to calculate the direction to throw our object when we release it.

Both fields will be used to help us throw the game object that we select.

Walking Through the Code

Let’s walk through the code:

  1. As always in Start(), we initialized our fields, however in this case, we just set them to be null
  2. The real starting point for this code is in HoldGameObject() this will be the function that we will call for our PointerDown. We want to be able to receive the game object that we selected (we’ll see how that’s done later) and then, we want to adjust some of the settings with the game object so that we can throw.

There are 2 important settings we need to make to the give game object that we receive in HoldGameObject() and that’s the parent of the object and the isKinemetic setting on our Rigid Body.

We would set the parent object of our game object to our controller. This is the equivalent of us making the ball a child of our GvrControllerPointer game object in the game hierarchy.

What this means is that, now whenever we move the controller, the ball would stay in the same position relative to where the controller is pointing to, meaning we give the illusion of being able to carry the ball.

At this point, we can carry the ball, but because of the Rigid Body, we’ll see that gravity would force the ball back down to the ground. That’s where the kinematics setting from the rigid body comes to play. We need to enable it so we can ignore physics and drag the ball around.

Now continuing walking through the code:

  1. Once we have been given a game object with a throwable script component, in Update(), we’ll start to track the position of our throwable game object. This will be needed to calculate the Vector to throw our game object.
  2. Finally, we’ll call ReleaseGameObject() when the player lets go of the pointer/mouse. What happens here is that we would first change the game object’s settings back to normal (isKinematic and parent object), then we use its current position and the previous position that we’ve being tracking to calculate the delta of the direction of where the ball should be thrown at based off the controller’s motion. We would multiply that with a force value (10) to help send it flying. We also apply the ForceMode impulse to create an instance force impulse to the throwable game object.

And with this, we now have a very simple script that would allow us to throw the game object!

Conclusion

That’s it for today! At this point, after we hook up the game objects to the script, we can start throwing our ball around!

However, before moving on, I want to take a quick second and look at the code we wrote. Right now, the code is a bit sloppy, we’re grabbing components from our throwable object and changing it directly. In this scenario, it might be okay since we only have 2 scripts, but for larger codebases, it could become a mess.

In the next post, we’re going to clean up the script a bit and then finish our throwing implementation! Like always, I’ll see you then!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)