In this codelab, you create a cannon that will be controlled by a panel of buttons you can push. All the interaction will be done using the Google VR Unity SDK raycasters.
What you'll learn
Create a new Unity project that uses the Google VR Unity SDK.
How to import the Google VR Unity SDK package.
How to adjust the build settings to target Daydream devices.
Deploy a Daydream app onto a device.
Create a highlighting component that will notify the user when objects can be interacted with.
Create pushable buttons that will control and fire a cannon.
Tell us a little about yourself
How will you use this codelab?
Only read through itRead it and complete the exercises
How would you rate your experience with building Unity applications?
Never triedNoviceIntermediateProficient
How would you rate your experience with Google Daydream?
Never triedNoviceIntermediateProficient
How would you rate your experience writing code?
Never triedNoviceIntermediateProficient
Hardware you'll need
A development machine running Windows 7 or higher, or Mac OS.
Unity 5.6 or greater. You can download and install the latest version of Unity here. When installing Unity, make sure you install Android Build Support as well.
Download and install the latest version of Android Studio. This sets up Android tools like adb and downloads the Android SDK for you.
In order to run samples, you'll need to enable debugging over USB on your device. To do so:
Go to Settings
Go to About phone (usually at the bottom)
Tap Build number (usually at the bottom) seven times. You should see a toast saying you are now a developer.
Return to the previous screen to find Developer options at the bottom.
From the Developer options menu, find USB debugging and turn it on.
When you connect your phone to your development platform, you will need to authenticate debugging from the phone. Allowing this will enable your machine to control your device.
Download The Google VR SDK for Unity
You will need this SDK to enable Daydream development in Unity. To do so, download it as a .unitypackage to your computer.
To get started, we'll need to create a new project from scratch. Go ahead a launch Unity.
After unity boots up, you will be greeted with a welcome dialog. Click the New button at the top to setup a new project.
Set the Project name to "daydream-picking-pushing"
You can set the Location to whatever you prefer.
If this is your first time using Unity, or you are still a beginner, let's walk through some important parts of Unity.
Using the Default Layout
First off let's use the default layout for the editor. At the top right of the editor, you will see several drop downs. Click the Layout dropdown and select Default. This will arrange the editor windows for you.
Unity's Windows
In Unity, there's several windows you should be aware of. Feel free to explore the provided links, but don't worry if it feels like a lot, we'll walk you through some of the first time steps.
The Project window: this is where you can access and manage the assets that belong to your project. Assets are files on disk that represent the various aspects of your project. We'll spend a lot of time here finding assets and creating/using prefabs
The Hierarchy window: Scenes are made up of various GameObjects, this is where you will see the hierarchy of GameObjects in the current scene. You can set up parent-child relationships here.
The Inspector window: This is the window that will list the various Components of a given GameObject. We'll spend a lot of time here adding Components and editing properties. Inspector window also lets you edit properties of scene GameObjects, Project prefabs, and other various assets.
The Scene View: This is a visual representation of your scene's hierarchy.
The Game View: This is the view of the game when you are running in the editor.
The Console window: this is where you can view the errors, warnings and other messages generated by Unity. Unity displays the most recent message on the status bar at the bottom of the IDE, but you can switch to the Console tab on the bottom pane to see all messages.
Building for Android
First thing we need to do is configure Unity to build the project for Android
Click on File -> Build Settings
Change the target platform by selecting Android under the Platform menu.
Click on Switch Platform.
If everything was setup correctly, it will look like this (note the Unity symbol to the right of Android).
Configuring the Player
Click on Player Settings... at the bottom of the Build Settings window. It will update the Inspector window in the right panel with the PlayerSettings.
In the Inspector window, expand the Other Settings.
Check the box for Virtual Reality Supported.
Click on the + button and select Daydream SDK.
Set the Package Name attribute to "com.example.daydream.picking"
Finally set the Minimum API Level to 24 or greater.
Importing the Google VR SDK
If you haven't done so already, grab the the latest version of the Google VR SDK for unity. The latest .unitypackage is available to download from GitHub here.
Open the .unitypackage from Windows Explorer or MacOS Finder.
Unity will extract the package and prepare it's files for import. You'll get a confirmation dialog first that list all the files. Click Import to proceed.
After the import operation, you will now see a GoogleVR option appear in the system Menu.
Importing the Codelab Project
Now we'll repeat the process for the provided Codelab project. Importing this project into Unity will set up the editor with the proper setting and include some assets we'll use later on in the Codelab. If you haven't done so already, grab the .unitypackage from GitHub here.
Open the daydream-picking-pushing.unitypackage from Windows Explorer or MacOS Finder.
Click Import to proceed.
Open the starter scene
Now that we've imported all the assets, we'll setup our main scene. In the Project Window, select the Scene folder
Double click the Starter scene to open it. You can use the zoom slider at the bottom right to switch between icons and a list view of the assets in the folder.
In the Hierarchy window, you should just have the Main Scene with an Environment Object and a Main Camera.
The scene provided has a trio of targets atop an icy island. The Game view should look like this, which will be the perspective of the player when it is run on the headset.
The Arm Model
When using Daydream, it's best to set up an arm model to mimic where the user's hand is. An arm model is a mathematical model for approximating the location of the user's hand in virtual space. The Daydream controller only has rotational values, but we can use that in combination with the headset's information to create an accurate estimate of where the user's hand is.
Working with Prefabs
In Unity, a Prefab is a form of a template. You can create prefabs and then re-use them multiple times in a scene without having to create them over and over again. Through the course of this Codelab, we will provide some prefabs already made for you to use, and walk through the construction of one later on.
Using the SDK Prefabs
In order to do this, there are some foundational prefabs that are needed in order to set up a Daydream Arm Model.
GvrEventSystem: this is the main event system prefab that the various Unity components use to send events with. It acts as the glue between Unity's Event System, Input Module, UI and GameObjects to allow interactions with the Daydream controller.
GvrControllerMain: Used to setup the parameters of the arm model.
GvrControllerPointer: This takes the Arm Model information from the GvrControllerMain and creates a GameObject hierarchy out of it.
GvrEditorEmulator: If you are running from the editor, this prefab will make the editor mimic the VR environment, so you can get a sense of what the scene would look like when it is running through the headset.
You can read more about the Daydream controller and the provided prefabs here and here. We'll add them to the scene now.
Adding the Prefabs to the Scene
In the Project window, type "t:prefab GVR" in the search bar, which will find all prefabs with the phrase "GVR".
If you see a lot of blue cubes and can't see the names, use the zoom slider to make them larger, or shrink them down to a list.
Select the four prefabs we are using.
Drag and drop them on the Hierarchy window. Don't worry about order, it is not important in this context. In the end your hierarchy will look something like this.
Setup the Player
When creating Daydream applications, you'll want to have a Player GameObject in every scene. The Player will consist of the two elements that the user will use to interact with the scene: the camera and the controller. The camera will be used to position the viewpoint of the headset, ie- the root/head. The controller will be a hierarchy that represents the user's arm in the scene.
From the Menu, Choose GameObject -> Create Empty. You will see a new GameObject in the Hierarchy window.
In the Inspector window, rename the object "Player".
Set Position to (0, 1, 0)
In the Hierarchy window, find the Main Camera GameObject
Make the Main Camera GameObject a child of the Player GameObject by dragging onto the Player GameObject. The Player GameObject will be highlighted when it is properly dragged.
In the Hierarchy window, select the Main Camera GameObject
In the Inspector window, set Position to (0, 0, 0)
Set Clipping Planes/Near to 0.01
We also want to make the GvrControllerPointer GameObject a child of player. Drag it onto player as well.
Set it's Position to (0, 0, 0)
Your hierarchy will look like this when you are done:
Now we are ready to build and run our first Daydream APK!
Building
Connect your phone to your computer via USB.
From the menu, select File > Build Settings. In the Build Settings window, click On the Build and Run button at the bottom right.
In the file selection dialog, specify your desired location for the resulting APK file. Unity will build, install, and run the apk on your device.
Running
If you have not yet put your phone in your headset, do so now. Ensure the USB cable stays connected, and that the volume/power buttons are on the top. If you just see a black screen, double check to make sure the device is on!
Controllers
Controllers are a required component of Daydream apps, so if your device does not have a controller paired to it, you will see something like this:
Every Daydream View comes with a remote included. If you don't have access to a Daydream view, you can emulate the remote using the Controller Emulator APK.
Initial Orientation
If everything is going smoothly, you should see a landscape with a controller floating in front of you. Follow the instructions and you should then see your application.
If you don't see anything try pressing and holding the home button at the bottom of the controller. It will recenter your view based on your current orientation. You can hold the home button at anytime to recenter.
Check your Work
After you have calibrated your controller, you will see the Daydream controller being held in your hand.
Open the main scene
If you have ran into any issues, don't fret! We've supplied another scene for this point in the codelab. Even if everything is running smoothly, it's good to use at this point as we've organized the scene a little more.
Now that we've imported all the assets, we'll setup our main scene. In the Project Window, select the Scene folder
Double click the Main scene to open it. You can use the zoom slider at the bottom right to switch between icons and a list view of the assets in the folder.
In the Hierarchy window, your hierarchy should look like this:
Adding the Physics Raycaster
Before we move, we need to do some quick housekeeping. We'll need to add a raycaster to the main camera GameObject. This component will send the appropriate events to objects that are being hit by the controller's raycasts.
In the Hierarchy window, select the Player/Main Camera GameObject
At the bottom of the Inspector window, click the Add Component button
Type in "GvrPointerPhysicsRaycaster" and hit enter or click it to add it.
Creating our scripts
Next we need to make some scripts which will allow us to create custom components that will change the behavior of our objects. We'll flesh out the code in these scripts later on.
In the Project window, right click the Assets folder -> Create -> Folder.
Name the folder "Scripts"
Right click again on the Scripts folder -> Create -> C# Script
Name the script "Colorable"
In the Inspector window, verify your script was created
Later on, we'll add some more components. Since we are in the script creating mood, we'll add them now. Repeat the steps above to add three script called "Throwable", "Cannon", and "Pushable"
For this codelab, we will be making a cannon like component the user can interact with. First up we are going to create an cannonball object that we can use over and over.
Creating a Cannonball GameObject
In Unity, we need to create our Cannonball object. First we'll create the geometry.
From the Menu, Choose GameObject -> 3D Object -> Sphere. There will now be a new Sphere GameObject in the Hierarchy window.
In the Inspector window, rename the object "Cannonball"
Set Position to (-0.7, 1, 1)
Set Scale to (0.25, 0.25, 0.25)
Click the Add Component button
Type in "Rigidbody" and hit enter or click it to add it
On the Rigidbody component, Set Collision Detection to Continuous
Check your work by clicking the Play Button on the Toolbar.
While running, will see an cannonball roll in front of you in the Game view of Unity.
Creating a Prefab out of the Cannonball
Before we start with the cannon, we'll want to make the Cannonball a prefab, since we'll be creating one every time the cannon is fired.
In the Project window, right click the Assets folder -> Create -> Folder.
Name the folder "Prefabs"
In the Hierarchy window, begin to drag the Cannon GameObject
Drop the Cannonball GameObject to the Prefabs folder in the Project window.
You will now see an Cannonball prefab in the project. We can use this over and over again at runtime.
The Two States
While we interact with the Cannonball, we'll want to change it's color to indicate its state. The state will be represented by changing its color, and we'll have two states:
Highlighted represents when the raycaster is pointing at the cannonball. We'll change the cannonball's color to green in this state.
Touched represents when the raycaster is pointing at the cannonball and the user is pressing the touchpad button. We'll change the cannonball's color to blue in this state.
Adding the Colorable Component
Now that we have the raycaster, we want our cannonball to react to it. To do this, we are going to create a new component called Colorable which will listen to and respond to events fired by the raycaster.
In the Hierarchy window, select the Cannonball GameObject.
In the Inspector window, click the Add Component button
Type in "Colorable" and hit enter or click it to add it
In the Colorable component, double click the Script field to open up the scripting editor.
Now that you are in the coding editor, you will see an initial class template like so. Next let's flesh out the code!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Colorable : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
Updating the State
In order to change the color of the Cannonball, we'll need a reference to the renderer's material, so add a field of type Material.
Add two fields to store the highlighted and touched colors.
We'll also want to store the original color of the material, so cache that value privately as well.
For our final fields, we'll need to keep track of if the object is highlighted and/or touched, so add two bool fields to track that.
// for changing the color
private Material _material;
// the colors to use when highlighting/touching
public Color highlightedColor = Color.green;
public Color touchedColor = Color.blue;
// the original color of the material, which will be restored if the object isn't highlighted/touched
private Color _originalColor;
// for tracking the state
private bool _isHighlighted;
private bool _isTouched;
In the Start method, we'll want to cache the material and original color values.
// Use this for initialization
void Start () {
_material = GetComponent<Renderer>().material;
_originalColor = _material.color;
}
Next, add two setter methods for highlight and touched:
public void SetIsHighlighted(bool value) {
_isHighlighted = value;
UpdateColor();
}
public void SetIsTouched(bool value) {
_isTouched = value;
UpdateColor();
}
Now that our script is fleshed out, we need to setup the Unity GameObject to call the appropriate methods.
First we will need some using imports at the top of the file.
using UnityEngine.Events;
using UnityEngine.EventSystems;
Next we will an extension to the GameObject class to help connect the events. Add this class to the bottom of the Colorable script file. It simply extends GameObject to add a simple AddListener method for readability.
public static class EventExtensions {
public static void AddListener(this GameObject gameObject,
EventTriggerType eventTriggerType,
UnityAction action) {
// get the EventTrigger component; if it doesn't exist, create one and add it
EventTrigger eventTrigger = gameObject.GetComponent<EventTrigger>()
?? gameObject.AddComponent<EventTrigger>();
// check to see if the entry already exists
EventTrigger.Entry entry;
entry = eventTrigger.triggers.Find(e => e.eventID == eventTriggerType);
if (entry == null) {
// if it does not, create and add it
entry = new EventTrigger.Entry {eventID = eventTriggerType};
// add the entry to the triggers list
eventTrigger.triggers.Add(entry);
}
// add the callback listener
entry.callback.AddListener(_ => action());
}
}
Next, in the Colorable class, connect the events in Start method.
Now when you run, you should see the color of the cannonball change when you hover over it.
Next we'll add the ability for the user to pick up the cannonball. We'll do this by adding a new component, Throwable, which will be similar to the Colorable component.
In the Hierarchy window, select the Cannonball GameObject.
In the Inspector window, click the Add Component button
Type in "Throwable" and hit enter or click it to add it
In the Throwable component, double click the Script field to open up the scripting editor.
Holding the Cannonball
First up, when the user presses down on the touchpad, we want the cannonball to attach to their hand. We'll add a Hold and Release method to do so.
Add the using imports at the top of the file.
using UnityEngine.Events;
using UnityEngine.EventSystems;
Add the Hold method. This method will take the cannonball, attach it to the controller and disable physics.
public void Hold() {
// get the Transform component of the pointer
Transform pointerTransform = GvrPointerInputModule.Pointer.PointerTransform;
// set the GameObject's parent to the pointer
transform.SetParent(pointerTransform, false);
// position it in the view
transform.localPosition = new Vector3(0, 0, 2);
// disable physics
GetComponent<Rigidbody>().isKinematic = true;
}
Add the Release method, which will return the cannonball to world coordinate system and turn its physics back on.
public void Release() {
// set the parent to the world
transform.SetParent(null, true);
// get the rigidbody physics component
Rigidbody rigidbody = GetComponent<Rigidbody>();
// reset velocity
rigidbody.velocity = Vector3.zero;
// enable physics
rigidbody.isKinematic = false;
}
Listen for the raycaster events in Start
// Use this for initialization
void Start() {
gameObject.AddListener(EventTriggerType.PointerDown, Hold);
gameObject.AddListener(EventTriggerType.PointerUp, Release);
}
Now if you run you should be able to pickup and drop the cannonball.
Adding momentum
Once you release the cannonball, it seems to lose all momentum. This is simply because there are no forces acting on the object when it is released. In order to maintain momentum, we'll need to keep track of the velocity of the object while the user is holding it. We can do this by calculating the average velocity over time.
We'll need to keep track of two variables: the previous position and the calculated throw velocity. Add them to the Throwable script.
// the calculated velocity for when the user releases the GameObject
private Vector3 _throwVelocity;
// the position of the object during the previous frame.
private Vector3 _previousPosition;
Next we'll calculate the average velocity and save the position in Update:
// Update is called once per frame
void Update() {
// the velocity is based on the previous position
Vector3 frameVelocity = (transform.position - _previousPosition) / Time.deltaTime;
const int samples = 3;
// average the velocity calculate over the last number of frames
_throwVelocity = _throwVelocity * (samples - 1) / samples + frameVelocity / samples;
// update previous position
_previousPosition = transform.position;
}
Finally, apply the velocity by adding this code at the end of Release:
// enable physics
rigidbody.isKinematic = false;
// throw the object when releasing while held
rigidbody.AddForce(_throwVelocity, ForceMode.VelocityChange);
Apply changes to the Cannonball prefab
We have made a bunch of modifications to the Cannonball GameObject in the scene. However, we also want to apply these changes to the Cannonball prefab that we created earlier. This way when we create more cannonballs dynamically, all the changes will be present.
In the Hierarchy window, select the Cannonball GameObject.
In the Inspector window, Click the Apply button to update the prefab.
Check your work
Now when you run you should have a throwable cannonball. You can toss it around a bit, but try not to let it fall, it's the only one you have! Next up we'll add a control button to the scene that we will use to fire cannonballs.
Adding the Controls prefab to the Scene
We've provided a control platform on which to place the button. We'll add it to the scene now.
In the Project window, type "t:Prefab Controls" in the search bar, which will find the provided Controls geometry prefab.
If you see a lot of blue cubes and can't see the names, use the zoom slider to make them larger, or shrink them down to a list.
Select the Controls prefab.
Drag and drop the prefab on the Hierarchy window. In the end your hierarchy will look something like this.
Adding the Button geometry
Back in Unity, let's add some geometry to represent a cannon.
In the Hierarchy window, add a child cylinder object by right clicking on the GameObject Controls/Panel -> 3D Object -> Cube. There will now be a new Cube GameObject added as a child to Controls/Panel.
In the Inspector window, rename the GameObject "Button"
Set Scale to (0.25, 0.125, 0.25)
In the Mesh Renderer component, set Materials/Element 0 to Google Red. We are going to assign this field using the Object Picker. To open it, click the small circle next to the field.
You will now see the Object Picker. Similar to the Add Component menu, you can find the object you are looking for by typing it in. Ensure you are in the Assets tab.
Type "Google Red" to find our material. Hit enter or click it to select it.
Note the updated value of the field.
Finally add a Colorable component, click the Add Component button
Type in "Colorable" and hit enter or click it to add it.
In the Game view, you should see a blue panel with a red button on it. Let's add a little personality to the button.
Adding a Button Icon
In the Hierarchy window, add a child plane object by right clicking on the GameObject Controls/Panel/Button -> 3D Object -> Plane. There will now be a new Plane GameObject added as a child to Controls/Panel/Button.
In the Inspector window, rename the plane "Icon"
Set Position to (0, 0.51, 0)
Set Rotation to (0, 180, 0)
Set Scale to (0.1, 0.1, 0.1)
In the Mesh Renderer component, set Materials/Element 0 to fire using the Object picker
Now your button should have a blazing flame on it, a good icon for a fire button! If you run you will see that the button also changes color thanks to the Colorable component. We want the button to react more when the user clicks the touch pad, so let's make it respond to touches.
Adding the Pushable Component
In the Hierarchy window, select the Controls/Panel/Button GameObject.
In the Inspector window, click the Add Component button
Type in "Pushable" and hit enter or click it to add it
In the Pushable component, double click the Script field to open up the scripting editor.
Animating the Button
Add the using imports at the top of the file.
using UnityEngine.Events;
using UnityEngine.EventSystems;
First off we're going to need two fields, one to track the animation time, and another to track what speed the time is animating, be it positive or negative.
// the current time value
private float _animationTime = 0;
// the velocity in which the animation value will change
private float _animationVelocity;
Next up we'll add a method UpdateAnimationTime to update the animation time. We'll apply the animation velocity and clamp it to a value between 0 and 1.
private void UpdateAnimationTime() {
// if pushed, time moves forwards, if not, time moves backwards
float timestep = _animationVelocity * Time.deltaTime;
// calculate the new animation time and clamp it to [0..1]
_animationTime = Mathf.Clamp(_animationTime + timestep, 0, 1.0f);
}
Once we have our animation time, we'll update the transform to animate the button. We are going to use a unity helper function Vector3.Lerp to linearly interpolate between the original position of the object and the pushed position. We'll cache the original position and calculate the pushed position based on the transform of the object.
// store this so we can lerp between it and the pushed position
private Vector3 _originalPosition;
private void UpdateTransform() {
// we will move the object 0.5 units based on its scale
float pushDistance = 0.5f * transform.localScale.y;
// determine the direction from the object's rotation and the up vector
Vector3 pushDirection = transform.localRotation * Vector3.up;
// determine where the new position will be based on the direction and distance
Vector3 pushedPosition = _originalPosition - pushDirection * pushDistance;
// set the local position to the lerp between the original and pushed position
transform.localPosition = Vector3.Lerp(_originalPosition, pushedPosition, _animationTime);
}
To get the button to animate, we'll need to call our update methods in the Update method.
// Update is called once per frame
void Update() {
UpdateAnimationTime();
UpdateTransform();
}
Finally, in the Start method, we need to hook the component up to the raycaster events. When it receives the Down/Up command we'll set the animation velocity value to -5/5, respectively. We'll also cache the original position value.
// Use this for initialization
void Start() {
_originalPosition = transform.localPosition;
gameObject.AddListener(EventTriggerType.PointerDown, () => {
_animationVelocity = 5.0f;
});
gameObject.AddListener(EventTriggerType.PointerUp, () => {
_animationVelocity = -5.0f;
});
}
If you run now, you will notice that the button will animate when the user presses the touchpad.
Firing Events from the Button
As a last step, we'll add some events that will fire when the button is pushed.
Generally, buttons have three events, a one shot when the button is pushed, and when it is released, as well as a continuous event that is fired every frame the button is pushed.
// fired once when the button transitions to the down state
public UnityEvent onPressed;
// fired every frame the button is in the down state
public UnityEvent onDown;
// fired once when the button transitions out of the down state
public UnityEvent onReleased;
Since we are animating the button, we don't want to consider the button ‘down' until it has been depressed for a certain amount. In this case, we'll wait until the button is 90% pushed before it is considered ‘down'. We also need the previous frame's animation time to determine when the threshold is crossed to send the one-shot events.
private void CheckForEvents(float previousAnimationTime) {
// when the animation time crosses this threshold, it will be considered pushed
const float pushThreshold = 0.9f;
// calculate before and after states
bool wasDown = previousAnimationTime > pushThreshold;
bool isDown = _animationTime > pushThreshold;
// send press event if first frame pressed
if (!wasDown && isDown) {
onPressed.Invoke();
}
// always send down event if down
if (isDown) {
onDown.Invoke();
}
// send released event if first frame released
if (wasDown && !isDown) {
onReleased.Invoke();
}
}
Finally we need to add the calls to Update. Note that we are caching the value of the animation time before we update it in order to determine if the events need firing.
// Update is called once per frame
void Update() {
// store the previous animation time for later
float previousAnimationTime = _animationTime;
UpdateAnimationTime();
UpdateTransform();
CheckForEvents(previousAnimationTime);
}
Now that our events are firing, let's add a cannon that we can fire!
Adding the Cannon geometry
Back in Unity, let's add some geometry to represent a cannon.
From the Menu, Choose GameObject -> 3D Object -> Sphere. There will now be a new Sphere GameObject in the Hierarchy window.
In the Inspector window, rename the sphere Cannon
Set Position to (0, 0, 3)
Remove the Sphere Collider component by clicking the Gear Icon -> Remove Component
In the Mesh Renderer component, set Materials/Element 0 to Blue Grey using the Object Picker
In the Hierarchy window, add a child cylinder object by right clicking on the GameObject Cannon -> 3D Object -> Cylinder. There will now be a new Cylinder GameObject added as a child to Cannon.
In the Inspector window, rename the cylinder Barrel
Set Position to (0, 0.7, 0)
Set Scale to (0.5, 1, 0.5)
Remove the Capsule Collider component by clicking the Gear Icon -> Remove Component
In the Mesh Renderer component, set Materials/Element 0 to Blue Grey using the Object Picker
Finally, let's check the cannon's pivot. In the Hierarchy window, select the Cannon GameObject.
In the Inspector window, click on the Rotation/X value and drag with the mouse. Notice how the cannon rotates. Before moving on, set the Rotation to (45, 0, 0)
That about does it for the Unity side of the setup. Next we'll add a script to the cannon.
Adding the Cannon Component
In the Hierarchy window, select the Cannon GameObject.
In the Inspector window, click the Add Component button
Type in "Cannon" and hit enter or click it to add it
In the Cannon component, double click the Script field to open up the scripting editor.
Firing Cannonballs
Add a field of type GameObject to point to the cannonball prefab. This is so we can make cannonballs dynamically at runtime each time the cannon fires.
// the prefab that holds the cannonball
public GameObject cannonballPrefab;
Add a method to fire a cannonball. This will create a cannonball using the prefab, and apply a velocity based on the orientation of the cannon.
// fire a cannonball!
public void Fire() {
// create a cannonball at the current position/rotation
GameObject ball = Instantiate(cannonballPrefab,
transform.position,
transform.rotation);
// get the rigidbody physics component
Rigidbody cannonballRigidbody = ball.GetComponent<Rigidbody>();
// apply the Velocity
cannonballRigidbody.AddForce(Velocity, ForceMode.VelocityChange);
}
Add a property to calculate the velocity of the cannonball.
Let's switch back to the Unity to set up the Cannon object in the scene.
In the Hierarchy window, select the Cannon GameObject
In the Inspector window, find the Cannon Component. Note the new Cannonball Prefab field.
Now the cannon is hooked up to create cannonballs.
Now we have the button and the cannon setup. All that is left is to connect the two via events.
In the Hierarchy window, select the Controls/Panel/Button GameObject
In the Inspector window, find the Pushable component and note the three event listener fields. We'll add a listener by clicking on the plus button under the On Pressed event.
This will add a listener to the event. Next we need to assign the callback object by clicking on the small circle and to open the Object Picker.
This time we are picking an object from the Scene, so ensure the Scene tab is selected.
Type "Cannon" to find our object in the scene. Hit enter or click it to select it.
Note the updated field in the Inspector window. Add the callback by clicking No Function -> Cannon -> Fire (). In the end your component should look like this.
Now when you run you can finally fire the cannon!
Now that we have our fire button we can hit the 500 target. But we are rather restricted by just the single angle we can fire from. Let's start adding some more buttons to rotate the cannon.
Expanding the Cannon script
First up let's add some methods to the Cannon script to allow for manipulation of rotation.
In Cannon.cs, add a general Rotate method. This will allow us to rotate the cannon on the x and y axes. Note we are multiplying by delta time. Since we'll be calling this from a callback that is triggered by an event during the Update phase, we'll want to apply the appropriate timestep.
Next let's add some methods to rotate left and right. We'll also add a constant to define the rotational velocity.
private const float RotationalVelocity = 50;
public void RotateClockwise() {
Rotate(0, RotationalVelocity);
}
public void RotateCounterClockwise() {
Rotate(0, -RotationalVelocity);
}
Now let's add some more buttons!
Adding a Rotate Counter Clockwise Button
We're going to start duplicating the fire button we just created to add a left and right rotation button to the scene.
In the Hierarchy window, right click and choose Controls/Panel/Button -> Duplicate. This will create another button in the exact same position.
In the Inspector window, rename the button, "Rotate Counter Clockwise"
Set Position to (-0.25, 0, 0)
Set Scale to (0.125, 0.125, 0.125)
In the Mesh Renderer component, set Materials/Element 0 to Google Yellow using the Object Picker
Since we duplicated the button, the fire callback was also copied. Click the gray box of the callback under On Pressed () to highlight it blue.
Click the Minus button to remove the callback
Now this time, connect the On Down event to call the Cannon.RotateCounterClockwise method. Click on the plus button under the On Down event.
Set the callback object to Cannon using the Object Picker.
Note the updated field in the Inspector window. Add the callback by clicking No Function -> Cannon -> RotateCounterClockwise(). In the end your component should look like this.
Finally, let's change the icon of the button.
In the Hierarchy window, select the Controls/Panel/Rotate Counter Clockwise/Cube/Icon GameObject
In the Mesh Renderer component, set Materials/Element 0 to rotate_left using the Object Picker
In the Game view, you should now see a second button on the controls. It will also cause the cannon to rotate if you try running, but let's add the other button first!
Adding a Rotate Clockwise Button
First, rename our original Button GameObject to "Fire Button" by right clicking Controls/Panel/Button -> Rename.
Next Duplicate the new button we made by right clicking Controls/Panel/Rotate Counter Clockwise -> Duplicate
In the Inspector window, rename the duplicate, "Rotate Clockwise"
Set Position to (0.25, 0, 0)
Flip the x scale by setting Scale to (-0.125, 0.125, 0.125)
Change the event listener in the Pushable scripts to call the Cannon.RotateClockwise method.
Build and Test
Now you should have a fully controllable cannon! Next we'll add a little polish
Simulating the Trajectory
Next up we're going to add some visual feedback when aiming the cannon, as well as how an cannonball moves. First up, we'll draw a trajectory line to estimate where the cannonball will travel when fired. We'll do this with Unity's LineRenderer.
In Cannon.cs, flesh out Start to fetch and store a reference to the LineRenderer.
private LineRenderer _trajectoryLineRenderer;
// Use this for initialization
void Start() {
// get the line renderer for the trajectory simulation
_trajectoryLineRenderer = GetComponent<LineRenderer>();
}
Next, in Update, we'll want to simulate the path of the object and store the result as a list of points in the LineRenderer. The calculation takes the position and rotation of the cannon and to estimate where the cannonball will travel. It does this by stepping forward in time and calculating the new position and velocity.
// Update is called once per frame
private void Update() {
const int numberOfPositionsToSimulate = 50;
const float timeStepBetweenPositions = 0.2f;
// setup the initial conditions
Vector3 simulatedPosition = transform.position;
Vector3 simulatedVelocity = Velocity;
// update the position count
_trajectoryLineRenderer.positionCount = numberOfPositionsToSimulate;
for (int i = 0; i < numberOfPositionsToSimulate; i++) {
// set each position of the line renderer
_trajectoryLineRenderer.SetPosition(i, simulatedPosition);
// change the velocity based on Gravity and the time step.
simulatedVelocity += Physics.gravity * timeStepBetweenPositions;
// change the position based on Gravity and the time step.
simulatedPosition += simulatedVelocity * timeStepBetweenPositions;
}
}
Adding the Line Renderer in Unity
Back in Unity, we need to add the LineRenderer to our Cannon GameObject.
In the Hierarchy window, select the Cannon GameObject.
In the Inspector window, click the Add Component button
Type in "Line Renderer" and hit enter or click it to add it
In the Line Renderer component Set the Materials/Element 0 to ControllerLaser using the Object Picker.
Set Width to 0.2
Next, click on the white box next to Color to edit the gradient.
Creating a Color Gradient
Now we're going to make the laser look nice by using a Color Gradient.
The last step will have brought up the Gradient editor. The bottom markers are for colors, and the top markers are for alpha values.
Click on the left side color marker to edit that color
Click on the Color box, which defaults to white.
This will bring up the color editor
Set the (R, G, B) values to (0, 255, 0), which is pure green (or any color you'd like!).
Next, we'll make the color fade out as time passes. Close the color editor and your gradient will have changed. Click on the top right marker to edit the end alpha value.
The color field will have been replaced with an alpha slider. Set the alpha value to zero and you will see a nice gradient fade out the green color.
In the end, your component should look like this. Double check your Color field!
If you run now, you will see a nice green laser rendering from the cannon.
Adding a Trail Renderer to the Cannonballs
When you fire a cannonball it's hard to keep track of it. We can add a TrailRenderer component rather easily to help out with that. A TrailRenderer is just a LineRenderer that updates over time based on the object's position. We'll add one to the Cannonball prefab. A lot of these steps will be similar to the trajectory renderer.
In the Hierarchy window, select the Cannonball GameObject.
In the Inspector window, click the Add Component button
Type in "Trail Renderer" and hit enter or click it to add it
Set the Materials/Element 0 to ControllerLaser using the Object Picker
Set Width to 0.2
Set Time to 2
Make the Color field a blue gradient similar to the one we just created for the cannon. Use RGB value (0, 0, 255) for the color. In the end, your component should look like this:
Click the Apply button to update the prefab.
Speaking of which, we probably don't need our cannonball floating around anymore, so you can remove it from the scene. In the Hierarchy window, right click on the GameObject Cannonball -> Delete.
Now that you have a trail renderer, you will see more clearly where the cannonball is moving!
This concludes the codelab, but here are some tasks you can try to go a little further.
Here's some code to add to Cannon.cs
private const float ForceChangeVelocity = 20;
public void IncreaseForce() {
_force += Time.deltaTime * ForceChangeVelocity;
}
public void DecreaseForce() {
_force -= Time.deltaTime * ForceChangeVelocity;
}
public void RotateUp() {
Rotate(RotationalVelocity, 0);
}
public void RotateDown() {
Rotate(-RotationalVelocity, 0);
}
Make the controls larger, and add more buttons to the controls. There's some extra icons and color provided.
Try to make it looks like this!
If you want to just skip to the good stuff, we've included a completed prefab, Complex Panel. Just drag it to the Hierarchy window. You still need to wire everything up!
You did it! You've finished the codelab and successfully created a scene in Unity with some interesting interactions for the player using the Daydream controller.
Beyond
If you are looking for some more interesting things to do try:
Expose all the constants as fields to tweak in the editor.
Look into using Unity's Animation system instead of a mathematical lerp.
Add other types of controls: levers, knobs, etc
Adding sound effects to the scene.
Create a button that user can press that starts a timer and keeps score of each target the user hits.
Additionally, if you want to explore the Daydream platform further, check out our documentation here.
Tell us how it went!
Were you able to complete the codelab?
Yes!Yes, with some issues.Nope!
What did you think about the amount of code?
Just RightToo LittleToo Much
What did you think about the amount of Unity setup?