In this codelab, we will make a small Augmented Reality (AR) game using Motion Tracking.

The game is a simple ball throwing and dodging game. Gameplay consists of shooting balls at floating cubes, and dodge incoming balls from the cube.

Here are some screenshots:

In order to win, the player should keep moving to dodge enemy balls while finding chances to aim and attack.

What you'll learn

Hardware you'll need

Software you'll need

Launch Unity and choose to create a new Unity project via the "New" button in the welcome dialog.

Name the project "TangoProject" and set the location to a folder of your choice. Ensure the new project is configured as 3D. Enabling Unity Analytics is optional.

Click "Create Project".

If you are unfamiliar with Unity you should first locate the "Console" tab in the user interface.

Unity displays the last 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 log and error messages.

The Scene window displays what's in the current scene, in editor mode; the Game window displays what the game camera would see. The main difference between Scene and Game window is that the scene is an editor's view, the camera can move freely while the Game window camera is usually the main camera in the scene. You can choose how to put this window. I usually put them side by side. So I can get immediately feedback when I add something to the scene.

The Hierarchy window is a tree view of current scene, it shows in text what's in the scene, and allows accurate selection/manipulation of game objects.

The Inspector window shows the detailed properties of currently selected object, especially when we select an object in Hierarchy window, or in Scene window.

The Project window contains all imported assets of the project. Something being in Project windows means it is available to be used.

Unity provides a list of default layouts, that can be switched via Layout button on the Top Right corner.

Please feel free to use any layout you prefer, or customize existing ones to suit your preference. For example use "Wide" layout, then customize it by dragging game window to the right half. As below.

First, we set Unity project's build settings before doing anything else.

Open Build Settings dialog using File > Build Settings.

Click Android if it is not already selected, and then click button Switch Platform.

When you are done, the Unity logo should be on Android platform.

Then click on the Player Settings button. In the PlayerSettings panel that appears in the Inspector, set Product Name to DefenseGame.

Scroll down to find "Resolution and Presentation > Default Orientation", and set it to Landscape Left.

Next, locate the "Other Settings > Identification" section., set "Package Name" to com.tango.codelab.defensegame, and set the "Minimum API Level" to Android 6.0.

Now we'll import the Tango SDK into the project.

In the new project, import the Tango Unity SDK via the following menu options:

Now select the downloaded TangoSDK unitypackage file(Your file may have different name as new versions being released).

After the package is loaded into the project, all items should be selected and you can just click "Import".

If everything worked correctly, you should now see a Tango option appear in the top menu,

You should also see several Tango-related folders appear under "Assets" in the Project panel.

Since we are starting from scratch, the currently opened Scene should have the name"Untitled". Save the scene as DefenseGame, using "File > Save Scene". This should change the Scene name in the Hierarchy window.

In Unity, we need to specify which Scene to build. Open the Build Settings dialog use File > Build Settings... , and add the DefenseGame scene to build list by clicking the "Add Open Scenes" button.

Now we'll add the necessary Tango prefabs that power the Tango experience to the scene. From the Project window, navigate to the Assets/TangoPrefabs/ folder and drag the Tango Camera and Tango Manager prefabs into the Hierarchy window.

Since the Tango Camera represents both the game world virtual camera and real world Tango phone camera, we can delete the default Main Camera.

Select the Tango Camera we just placed into the scene. In the Inspector window, set "Camera > Clipping Planes > Far" to 100 and "Camera > Clear Flags" to Solid Color. Then activate the "Tango AR Screen (Script)" component, and ensure that "AR Camera Post Process (Script)" is NOT activated.

As we are building an AR game we want to use real world camera capture as the game's background, so we will enable this option. Select Tango Manager, enable "Tango Application (Script) > Enable Video Overlay" option in Inspector window. The default value "Texture(ITangoCameraTexture)" for its Method property is good for us.

Tango Camera prefab can be used to represent our Tango device in virtual world. When we only use motion tracking feature, Tango device's pose will be based on START_OF_SERVICE frame, which has the same origin as Unity world space. To say it in Unity language, when we start our app, the Tango device is at Unity world space's origin; then as we move our device in real world, Tango Camera will be updated with its offset in real world, so its Unity world coordinate reflects the device's actual transform in real world.

When we design our game's virtual world, we can design around Unity world origin, looking towards Z Axis positive direction. In this game, we'll start with one target, which is located 10 meters ahead of us, so its Unity world position is (0, 0, 10).

In Hierarchy window, create a cube, using menu "GameObject > 3D Object > Cube"

Select the newly created Cube, rename it to Monster. Set its properties in Inspector window.

To give the box some identity, we assign it a rendering material. In Inspector window, expand Mesh Renderer component, Materials property, click the target button on the right of Element 0, to open Select Material dialog.

We'll use the checker_texture, which is from a Tango SDK examples. We can find it by typing its name in Select Material dialog.

Now we have a visible target, we can quickly test it. There are two ways to test an Unity app,

  1. Test in Play mode in Unity editor
  2. Test on device

Testing in the Unity Editor is much faster, so we recommend doing that whenever possible. To do this, we simply click the Play button in Unity editor, it is usually located on the top, in the middle of Unity Editor.

While in play mode, the preview window is the Game window. You should see the cube in the center of Game window. Tango Unity SDK will provide a virtual room to simulate AR background. Here is what you are likely to see.

Next, we can test it on Tango device. Connect Tango phone to your computer, and build and run the app using menu "File > Build & Run". This will build current project, deploy it to your phone, and run it. Note that your phone must be setup for Android development, if you skipped it, please follow the steps in "Software you'll need" section. When the screen prompts you to save the build, type in a filename for the build, such as "build.apk", it will be created in Unity project's root directory.

When the game runs on phone, we should see a checker box ahead of us. And we can move around it.

Now that we have a monster target, we want it to be more than static: Let it throw balls at us actively.

We are going to add a script to the monster, make it throwing balls at us at certain pattern. For starters, it will throw 1 ball per second, for 3 times, then wait for 3 seconds, and throw 3 balls at once.

To do this, we will start writing our first script. Add a new script component to Monster, call it Monster.cs. As below:

  1. Select Monster in Hierarchy window
  2. Click the Add Component button in Inventory window
  3. Type Monster, hit choose "New Script" option.

  1. Press Enter again which will trigger the "Create and Add" button.

  1. This will create a Monster.cs script at Assets root folder, and add it to our Monster object. In actual project, we probably don't want to keep any file in the Assets the root folder. Let's create a new folder under Assets, and we simply call it DefenseGame. We'll use it to store all assets we created for this codelab. Right click on Assets in Project window, choose Create > Folder in context menu, and name it DefenseGame.
  2. Drag Monster.cs script into DefenseGame folder.

Now we can double click on the Monster script to open in in MonoDevelop-Unity. This script file is newly created, almost empty except for the default function stubs. Add the code below as a coroutine.

Monster.cs

  IEnumerator Throw() {
    while (true) {
      yield return new WaitForSeconds (1);
      ThrowAt (new Vector3(-1, 0, 0) + target.transform.position);
      yield return new WaitForSeconds (1);
      ThrowAt (target.transform.position);
      yield return new WaitForSeconds (1);
      ThrowAt (new Vector3(1, 0, 0) + target.transform.position);
      yield return new WaitForSeconds (3);
      ThrowAt (new Vector3(-1, 0, 0) + target.transform.position);
      yield return new WaitForSeconds (0.2f);
      ThrowAt (target.transform.position);
      yield return new WaitForSeconds (0.2f);
      ThrowAt (new Vector3(1, 0, 0) + target.transform.position);

      yield return new WaitForSeconds (2);
    }
  }

  void ThrowAt(Vector3 target) {
    var direction = (target - transform.position).normalized;
    var newBall = Object.Instantiate<GameObject> (ballPrefab, transform.position, Quaternion.identity);
    var ballRigidbody = newBall.GetComponent<Rigidbody>();
    ballRigidbody.velocity = direction * 5; // 5 seems to be a magic number that as a human I can dodge the ball.
  }

Throw is a simple coroutine with an infinite loop. Every iteration, it will wait for 1 second, throw at target + (-1, 0, 0), then it will wait for 1 second, throw at target, then wait 1 second, throw at target + (1, 0, 0). The small offset are introduced to add some fun, as player could be moving. After that the Monster will wait for 3 seconds, throw 3 balls at the same 3 locations, with 0.2s interval. Feel free to change the throwing pattern if you would like to.

ThrowAt is a function that implements the throwing logic. It simply creates a new ball GameObject from ballPrefab. Then calculate its target direction and set its speed to 5. Yes, 5 is a hard-coded magic value in this demo. I tested and found this value good enough for people to perform dodging.

We also need to declare the variables used by those 2 functions. Add these lines at the beginning of class Monster.

Monster.cs

public GameObject ballPrefab;
public GameObject target;

ballPrefab should be a prefab of the ball that Monster can throw, and target is a GameObject representing our device. If you remember what we talked about Tango Camera, the target is the Tango Camera.

Save the script. And move back to Unity window, wait for a few seconds, the Monster.cs will be compiled, and we shall see new properties that we added. Note, we need to select Monster object in Hierarchy window to see the properties of it in Inspector window.

Now, quickly from Hierarchy window, drag Tango Camera into the Target slot above while Inspector window is still linked with Monster object.

We need to give Monster a ball Prefab. Let's create one. We'll simply create a big red sphere object. Prefab is a unity term for pre-made game object, it's mainly used as template to create new game objects.

In hierarchy window, use menu "GameObject > 3D Object > Sphere", to create a new Sphere. And right click to rename it to MonsterBall. In Inspector window, set its position to (0, 0, 0) and scale to (0.1, 0.1, 0.1). That will make it of diameter of 0.1 m. That should be big enough to be seen by human.

The default sphere object has collider and mesh, which are good for us. We'll just change its color to Red. To do this, we need to create a new material. It's super easy.

In Project window, double click on DefenseGame folder to open it. Click the Create button to top left of Project window, choose Create > Material to create a new Material, name it MonsterBallMaterial, then hit enter. To rename it, you can just hit Enter while highlighting it.

That's it. I said it's easy.

Now back to MonsterBall object, select it, and change its Element 0 Materials to MonsterBallMaterial, by clicking the target button on the right, and find MonsterBallMaterial in the drop down list.

After that, we'll see MonsterBallMaterial component in Monster object's Inspection window, where we can adjust its color. Expand MonsterBallMaterial, click on the White box on the right of Albedo, select a red color.

Now that we have the MonsterBall, let's make it a prefab. Simply drag MonsterBall into our asset folder, Assets/DefenseGame. We'll notice in Hierarchy window, MonsterBall object becomes blue, which means it is from a prefab. Now we can just delete it from the scene. Select MonsterBall in Hierarchy window, and delete it.

Now we assign MonsterBall prefab to Monster. In Hierarchy window, select Monster object, from Project window drag the MonsterBall perfab we just created to Inspector window Ball Prefab property. (Hint: While dragging MonstallBall to Inspector window, you cannot release mouse left button, or Inspector window will be switched to be properties of MonstallBall object)

We are almost done with Monster's throwing. We just need to make the monster call Throw coroutine. Go back to MonoDevelop-Unity, add this line in Monster.cs, Start function.

Monster.cs

    StartCoroutine (Throw());

Our MonsterBall is more or less done. One more thing before we can run the script in editor is physics. In this simple game, we'll rely on Unity's built-in physics system to move balls and detect hits. To do this, we need to give the ball a RigidBody component. RigitBody is unity Physics engine's basic building block, a RigidBody will have velocity, mess etc; and its movement is fully controlled by Unity. In ThrowAt function, we already assumed the ball will have a RigidBody component in this line of code:

Monster.cs

var ballRigidbody = newBall.GetComponent<Rigidbody>();

So now let's give the ball prefab a RigidBody component. Select MonsterBall prefab in Project window, Assets/DefenseGame folder, at the bottom of Inspector window, use AddComponent button to add a RigidBody component.

We will ignore Gravity for now to keep things simple, so balls travels in straight line. Uncheck the "Use Gravity" checkbox in RigidBody component; for the rest parameters we will leave them to default value for now.

Finally let's try running the game in Unity Editor, click the Play button to start the game.

Do you see the Monster throwing red balls at you? No? Chances are the Monster is throwing at other directions(which you can verify by looking at Monster in Editor window, double click Monster to make Editor window focuses on Monster object). This is an interesting side effect and can be easily fixed. The fact that we are starting the ball from the Monster's position, makes them collide. To fix this issue, let's designate a special position where the balls came from. I'll call it BallStart.

Right click on Monster, choose 3D Object > Sphere to create a sphere as child. Rename it to BallStart.

Set its properties as below,

Transform > Position: (0, 0 , 1.0)

Transform > Scale: (0.1, 0.1, 0.1)

Scale to 0.1, so the BallStart is of 0.1 m in size. The expected result is that the BallStart is ahead of the Monster object, in Z positive direction (with bigger Z value).

And we can make it look like a normal MonsterBall, by setting its material to MonsterBallMaterial. The steps is exactly the same as above how we set MonstallBall's material to MonstallBallMaterial.

To avoid collision, let's remove its collider component. To do so, click on the gear icon on the right of Sphere collider, choose Remove component.

The final BallStart object look like this in Inspector window.

Note, we put Monster at Z:10, while camera is at origin Z:0, so we can turn the Monster 180 degree along Y axis to make it face the origin(By default the Monster faces Z positive direction), where Tango Camera will be initially. Set the Y rotation to 180 for Monster object. Later we'll add code to rotate Monster, for now let's just hard-code this parameter.

A top-down view in Unity Scene window, that illustrates current setup, is as below.

Now we can update Monster.cs script, to take a reference of the BallStart transform, and throw from this position. Add below code to Monster.cs.

Monster.cs

   private Transform ballStart;

Assign it in Start function by looking for this child by name.

Monster.cs

  void Start () {
    ballStart = transform.Find ("BallStart");
    StartCoroutine (Throw());
  }

And update ThrowAt function to below.

Monster.cs

  void ThrowAt(Vector3 target) {
    var dir = (target - ballStart.position).normalized;
    var newBall = Object.Instantiate<GameObject> (ballPrefab, ballStart.position, Quaternion.identity);
    var ballRigidbody = newBall.GetComponent<Rigidbody>();
    ballRigidbody.velocity = dir * 5; // 5 seems to be a magic number that as a human I can dodge the ball.
  }

Now, let's try running the game in Unity editor again. Click the Play button. We should now be able to see the the Monster throwing towards us.

Now that we have a monster, let's give it a worthy opponent, the player!

Let's create a Capsule, rename it to Player. Capsule is a commonly used geometry to do physics for characters in 3D games. Note, the player should be a direct child of the DefenseGame scene.

Let's set's position to (0, 0, 0), if those values are not already 0.

As we mentioned before, supported by Tango's Motion Tracking capability, Tango Camera reflects the player's movement in real world, so we can make it control the position of virtual world player. We are going to use its transform to update the Player's transform. To do this is easy, we simply set Tango Camera's transform to be the parent of Player's transform, and Unity will do the rest job. We would need a custom script to add this logic. Let's add a Player.cs component to the Player object.

Select Player object, in Inspector window, click Add Component button to add New Script component, Player. Then drag Player.cs from Assets root folder to Assets/DefenseGame folder, as we did for Monster.cs. Double click on Player script, to open it in MonoDevelop-Unity.

As below, add a variable to store a reference to tangoCamera, and in the Start function, set tangoCamera's transform as parent transform.

Player.cs

  public Camera tangoCamera;

  // Use this for initialization
  void Start () {
    transform.parent = tangoCamera.transform;
  }

Save the script, and go back to Unity editor. Wait for a while for the Tango Camera property to appear in Inspector window (with Player object being selected in Hierarchy window).

Then we drag Tango Camera object from Hierarchy window to this property slot.

That's it, we can click Play button in Unity Editor to run the game. Now that our player has a collider, the incoming ball will eventually stop in front of us. We can also use WASD keys and mouse cursor while in Play mode to simulate the movement of Tango Camera, and you shall see the capsule object move in Unity's Scene view.

At this time, you can also build and run your game on Tango device, you shall be able to move around and use the device to collide with balls.

Now we have a monster throwing balls at player, we have player that can block balls. It's only fair to let player throw back towards the monster. We are going to enable player to throw when the player uses one finger to touch anywhere on the screen.

To handle screen touch, let's add a new UI element, called EventSystem. Just use menu "GameObject > UI > Event System", we can create one.

Then let's add these code in Player.cs.

Player.cs

public GameObject ballPrefab;
private float lastThrowTime_;

  void Start () {
    transform.parent = tangoCamera.transform;
    lastThrowTime_ = 0; // Add this line in existing Start function
  }

  // Update is called once per frame
  void Update () {
    bool shouldAttack = false;

    if (Input.touchCount == 1) {
      Touch t = Input.GetTouch (0);
      if (t.phase == TouchPhase.Stationary || t.phase == TouchPhase.Moved) {
        shouldAttack = true;
      }
    }

    #if UNITY_EDITOR
    if (Input.GetButton("Jump")) shouldAttack = true;
    #endif

    if (shouldAttack) ThrowBall ();
  }

  void ThrowBall() {
    if (Time.time - lastThrowTime_ < 0.1f) // throw 10 times a second
      return;

    lastThrowTime_ = Time.time;

    // Throw a ball from player to, camera front.
    var playerBall = Instantiate(ballPrefab, transform.position + transform.forward * 0.6f, transform.rotation); // forward 0.6f, so it doesn't collide with player capsule
    var ballRigidBody = playerBall.GetComponent<Rigidbody> ();
    ballRigidBody.velocity = transform.forward * 5; // Again the magic number, 5 for ball speed
  }

There're 2 parts in these code.

  1. We detect user touch and if user is putting a finger on the screen, we set shouldAttack flag to true
  2. ThrowBall, similar to the code in ThrowAt in Monster.cs, but we limit the attack rate to 10 balls per second by enforcing at 0.1 second delay of each attack.

To make it easier to test in Unity Editor's Play mode, we also check "Jump" button (which is the space key by default) and throw if it's pressed. ThrowBall function of player doesn't need to take a target position as in Monster's ThrowAt functhon, because player's target direction is decided by player's own rotation, which is controlled by the way player rotates the device.

The ballPrefab serves the same purpose as the one in Monster.cs. There's a little trick I added to avoid the ball initial collision issue (remember we had that when adding Monster ball?), I moved the ball's starting position 0.6 meter forward, which is just 0.1 meter away from the edge of player's capsule.

lastThrowTime_ is used to control the throw rate. When ThrowBall is called, we check the last time when a ball is throwed, if it's within 0.1 seconds, we skip this function.

Now we save the Player.cs and move back to Unity Editor, wait for the script to be compiled and we can see BallPrefab property to appear in Inspector window (with Player object being selected in Hierarchy window). If it didn't, check Console window to see if there're any compile errors. Then we can make a BallPrefab for player. We want player's Ball to be

  1. Of different color,
  2. Smaller and lighter.

So it's distinguishable to Monster's ball and doesn't significantly affect the trajectory of Monster ball. To do so, we can start by duplicating MonsterBallPrefab.

In Project window, open Assets/DefenseGame folder, drag MonsterBall into Hierarchy window, then rename the new MonsterBall object in Hierarchy to PlayerBall, then drag it back to Assets/DefenseGame to make it a new prefab, and we can delete the PlayerBall object in Hierarchy window. Basically we just created a new Prefab from an existing Prefab. In Project window, select Assets/DefenseGame/PlayerBall, set its transform scale to (0.05, 0.05, 0.05).

And set its RigidBody > Mass to 0.125 (as the radius is ½ of MonsterBall, the Mass is ⅛ ).

To set it to different color, we need to create a new material. Let's do this prefab duplication on a different way. In Project window, select Assets/DefenseGame/MonsterBallMaterial, use ctrl + D (command + D on mac) to duplicate it. And rename the new material to PlayerBallMaterial (to rename, hit Enter key while selecting it in Project window), and in Inspector window, set property "PlayerBallMaterial > Main Maps > Albedo" to Blue color. Then in Project window, select Assets/DefenseGame/PlayerBall, change its material to PlayerBallMaterial.

At last, we assign PlayerBall to Player object. To do this, select Player object in Hierarchy window, from Project window drag Assets/DefenseGame/PlayerBall object into "Player (Script) > Ball Prefab" property in Inspector window.

Now we can save the scene, and click Play button in Unity Editor to test player throwing editor mode. Press Space key to throw, and WASD keys to move players, as in a typical FPS game.

If testing in Unity Editor works, you can proceed to build and run on Tango device. Connect Tango phone to your computer, use menu "File > Build & Run" to build and deploy to device.

Well done. Now you should have a basic game running. The player and monster can throw balls at each other, and the player can move phone to dodge attacking balls.

We disabled gravity for the balls. Could you make the game more challenging by supporting gravity for the throwing physics?

You've finished the codelab, successfully creating a Tango based AR game. If you couldn't get the codelab working somehow, you can try download our pre-made Unity package https://goo.gl/EDU6u9 and import it into your Unity project (you still need to import Tango Unity SDK and do project build settings to build the project). You can also download the final apk file of this codelab here https://goo.gl/AWSg1T, and run it on your phone.

If you want to explore the Google Tango platform further then check out our documentation here.

Thank you, and please let us know how we can improve the codelabs. Happy developing :)