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.
- 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.
- In
GvrControllerPointer
, create a new script called - 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:
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private Throwable _grabbedThrowable;
private Vector3 _currentGrabbedLocation;
void Start ()
{
_grabbedThrowable = null;
_currentGrabbedLocation = new Vector3();
}
void Update () {
if (_grabbedThrowable != null)
{
_currentGrabbedLocation = _grabbedThrowable.transform.position;
}
}
public void HoldGameObject(GameObject throwableObject)
{
Throwable throwable = throwableObject.GetComponent<Throwable>();
if (throwable != null)
{
_grabbedThrowable = throwable;
throwableObject.transform.parent = this.gameObject.transform;
_grabbedThrowable.GetComponent<Rigidbody>().isKinematic = true;
_currentGrabbedLocation = _grabbedThrowable.transform.position;
}
}
public void ReleaseGameObject()
{
if (_grabbedThrowable != null)
{
_grabbedThrowable.transform.parent = null;
Rigidbody rigidBody = _grabbedThrowable.GetComponent<Rigidbody>();
rigidBody.isKinematic = false;
Vector3 throwVector = _grabbedThrowable.transform.position -
_currentGrabbedLocation;
rigidBody.AddForce(throwVector * 10, ForceMode.Impulse);
_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:
- As always in
Start()
, we initialized our fields, however in this case, we just set them to be null
- 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:
- 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. - 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!