Now we’re on part 2 of throwing a game object in VR. In the previous post, we almost finished being able to grab and throw our Ball
game object in a script.
All that was left was to connect our Public
variables. However, before we set that up, I wanted to refactor the code a bit.
Like I have mentioned at the end of the previous post, our code is getting messy where we’re calling scripts from other scripts. The code still works, but if we ever decided to change the way that script works, we could potentially break or cause unintended side effects.
So today, the game plan is to:
- Refactor our code to be cleaner
- Finish setting up our script
Let’s get started!
Refactoring Our Code to be Cleaner
To make our code cleaner, we’re going to apply the concept of Separation of Concerns, where each script should only know information about itself and rely on the functions of other scripts to do what they’re supposed to do.
Specifically, let’s move some of the code in our PlayerController
to Throwable
.
For the most part, we’re going to move the code we wrote in PlayerController
that directly depends on the components in Throwable
into Throwable
.
PlayerController
doesn’t need to know the details of how throwing a game object works. It just needs to know when it selects it and when it’s released. We can move everything else into the throwable
script.
Here’s what the Throwable
script should look like with the other changes:
using UnityEngine;
public class Throwable : MonoBehaviour
{
private Material _outlineMaterial;
private Rigidbody _rigidbody;
private Vector3 _currentGrabbedLocation;
private bool _isGrabbed;
private const string OutlineWidthKey = "_Outline";
private const float OutlineWidthValue = 0.03f;
void Start ()
{
_outlineMaterial = GetComponent<Renderer>().materials[1];
_outlineMaterial.SetFloat(OutlineWidthKey, 0);
_rigidbody = GetComponent<Rigidbody>();
_currentGrabbedLocation = new Vector3();
_isGrabbed = false;
}
void Update()
{
if (_isGrabbed)
{
_currentGrabbedLocation = transform.position;
}
}
public void ShowOutlineMaterial()
{
_outlineMaterial.SetFloat(OutlineWidthKey, OutlineWidthValue);
}
public void HideOutlineMaterial()
{
_outlineMaterial.SetFloat(OutlineWidthKey, 0);
}
public void GetGrabbed(GameObject controllerObject)
{
transform.parent = controllerObject.transform;
_rigidbody.isKinematic = true;
_isGrabbed = true;
}
public void GetReleased()
{
if (_isGrabbed)
{
transform.parent = null;
_rigidbody.isKinematic = false;
Vector3 throwVector = transform.position - _currentGrabbedLocation;
_rigidbody.AddForce(throwVector * 10, ForceMode.Impulse);
_isGrabbed = false;
}
}
}
I won’t go through the new Throwable
code, but as you can see, we created 2 new functions: GetGrabbed()
and GetReleased()
which does pretty much exactly the same thing as HoldGameObject()
and ReleaseGameObject()
from PlayerController
.
Here’s what PlayerController
looks like now:
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private Throwable _grabbedThrowable;
void Start ()
{
_grabbedThrowable = null;
}
public void HoldGameObject(GameObject throwableObject)
{
Throwable throwable = throwableObject.GetComponent<Throwable>();
if (throwable != null)
{
_grabbedThrowable = throwable;
_grabbedThrowable.GetGrabbed(gameObject);
}
}
public void ReleaseGameObject()
{
if (_grabbedThrowable != null)
{
_grabbedThrowable.GetReleased();
_grabbedThrowable = null;
}
}
}
As you can see, here we’ve cleaned up our PlayerController
script quite a bit now. Now the only thing we do with the throwable
script is that we would tell it that we pick it up and when we release our grip on it. Throwable
would take care of the rest of the work involved.
Setting Up the Ball Game Object to Use the PlayerController
Now that we’ve cleaned up our script a bit, let’s add these function to our Ball
’s event system.
- In the Event System in
Ball
, add a Pointer Down event and a Pointer Up. - In Pointer Down, select
GvrControllerPointer
as our game object and select PlayerController
> HoldGameObject
HoldGameObject()
takes in a GameObject
. We’ll pass the ball
itself as a variable to pick up. Select it in the game hierarchy. I tested what happens if we were to make a prefab of the ball
and use it, and it looks like each prefab instance is passed incorrectly. - For Pointer Up, select
GvrControllerPointer
as the game object to grab a script from and select PlayerController
> RelaseGameObject
- Extra Note: If you haven’t already, don’t forget to remove the Box Collider and Mesh Renderer on the
Player
game object, otherwise it might interfere with the remote controller.
Now with the event system in place, we can grab and throw our ball
game object. Here’s what our Event System looks like:

And here’s what it’ll look like now in our game:

We might want to tweak the force we apply to the ball, but at the most basic level, this is the code needed to grab and throw a game object.
Conclusion
Another day and another feature completed! We now have a fully functioning grab and throw script that allows us to throw our ball!
The cool thing about what we did with our script is that we’re not only limited to a sphere game object. Any game object we want to be able to throw, we can add the Throwable
script (along with the Outline material and Rigidbody) and we can throw it! That’s nice and re-usable!
Now there are things that can be improved on like, what if we don’t want to rely on the laser to highlight a game object, but instead rely on proximity to the remote controller?
For that, we can’t depend on Unity’s event system anymore and we must create our own detection system which can be achieved with colliders and triggers, however, I’ll save that for a different day.
So, what’s next? Before we finish the Google Daydream series, there’s one more set of features that I want to experiment with. Menu creation! Stay tuned for more!