Holistic Game Development 2nd Ed C# Listings

Major differences between UnityScript (aka JavaScript in Unity) and C#:

  • For all C# code ensure a new C# Script is created instead of JavaScript. The C# file will have a .cs on the end.
  • C# code will be contained within a class. It doesn’t matter what you call the class except that the name should be meaningful. The class code contains the code inside it whereas JavaScript doesn’t require the container.
  • The filename of the .cs file should be EXACTLY the same as the class name. E.g. if the class is:
  • public class spin : MonoBehaviour
    {
        //your code
    }

    Then the filename should be spin.cs.

    Chapter 1

    Step 16 p. 25

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class spin : MonoBehaviour {

        // Use this for initialization
        void Start () {
           
        }
       
        // Update is called once per frame
        void Update () {
            transform.Rotate(Vector3.up * 10);
        }
    }

    Listing 1.7 A short program with comments

    // Update is called once per frame
    void Update () {
        //rotate around the vertical axis with a speed of 10
        transform.Rotate(Vector3.up * 10);
    }

    Section 1.5.3 Functions

    document.write(“Hello Unity”); in JavaScript
    Debug.Log(“Hello Unity”); in C#

    Listing 1.8 Code syntax for an empty function.

    void myFunctionName(input list)
    {
    }

    Listing 1.9 An example of declaring variables of differing types.
    (Note in C# a float with a decimal place requires a ‘f’ on the end of the value.

    int x = 10; //an integer called x with the value 10
    float y = 5.6f; //a float called y with the value 5.6 v
    bool isSpinning = true; //a Boolean value set to true
    char ch = ‘a’; // a character called ch with a value ‘a’
    string myName = “Penny”; // a string called myName with the value Penny

    Immediately below Listing 1.9

    var x: int; //in JavaScript

    is equivalent to using

    int x; //in C#

    Listing 1.10 JavaScript to Change the x Axis Scale of a GameObject on Game Start

    private float objScaleX = 0.5f;

    void Start ()
    {
        transform.localScale = new Vector3 (objScaleX, transform.localScale.y, transform.localScale.z);
    }

    Listing 1.11 A Script to Modify X, Y, and Z Scales of a Game Object

    float objScaleX = 2.0f;
    float objScaleY = 0.2f;
    float objScaleZ = 0.5f;

    void Start ()
    {
        transform.localScale = new Vector3 (objScaleX, objScaleY, objScaleZ);
    }

    Listing 1.12 Script to Grow a Game Object by 0.05 in Scale in Each Game Update

    float growthRate = 0.05f;
    void Update ()
    {
        transform.localScale = new Vector3 (objScaleX + growthRate, objScaleY + growthRate, objScaleZ + growthRate);
    }

    Listing 1.13 A Script to Move a Game Object in a Circle

    float radius = 5;
    void Update ()
    {
        transform.position = new Vector3(radius * Mathf.Sin(Time.fixedTime), radius * Mathf.Cos(Time.fixedTime), 0);
    }

    Listing 1.14 An if-else Statement

    C# syntax is exactly the same as JavaScript

    Listing 1.15 An Example Script Using an if-else Statement

    int x = 5;
    int y = 10;
    if( x > y)
    {
        Debug.Log(“X is greater than Y”);
    }
    else
    {
        Debug.Log(“Y is greater than or equal to X”);
    }

    Listing 1.16 Making a Game Object Fall to a Certain Position and Then Stop

    float speed = 0.1f;
    int groundLevel = -4;
    void Update ()
    {
        if(transform.position.y > groundLevel)
        {
            //keep moving down
            transform.Translate(0,0,-speed);
        }
    }

    Listing 1.17 A Script to Make a Game Object Fall Down to a Certain Height and Then Grow

    float speed = 0.1f;
    float growthRate = 0.01f;
    float groundLevel = -4;
    void Update ()
    {
        if(transform.position.y > groundLevel)
        {
            //keep moving down
            transform.Translate(0,0, -speed);
        }
        else
        {
            transform.localScale = new Vector3(transform.localScale.x + growthRate, 1,1);
        }
    }

    Listing 1.18 JavaScript for Printing Numbers between 1 and 5

    int i = 1;
    Debug.Log(i);
    i = i + 1;
    Debug.Log(i);
    i = i + 1;
    Debug.Log(i);
    i = i + 1;
    Debug.Log(i);
    i = i + 1;
    Debug.Log(i);
    i = i + 1;

    Listing 1.19 A for Loop

    C# is exactly the same as JavaScript

    Listing 1.20 A for Loop to Print out Numbers between 1 and 5

    for( int i = 1; i < = 9; i++)
    {
        Debug.Log(i);
    }

    Listing 1.21 Creating a Stack of Cubes with a for Loop

    void Start ()
    {
        GameObject aP;
        for(int i = 1; i <= 9; i++)
        {
            aP = GameObject. CreatePrimitive(PrimitiveType. Cube);
            aP.transform.position = new Vector3(0, i, 0);
        }
    }

    Listing 1.22 A Script That Creates One Column and One Row of Cubes

    void Start ()
    {
        GameObject aP;
        for(int i = 1; i < = 9; i++)
        {
            aP = GameObject.CreatePrimitive(PrimitiveType.Cube);
            aP.transform.position = new Vector3(0, i * 2, 0);
        }
        for(int j = 1; j <= 9; j++)
        {
            aP = GameObject.CreatePrimitive(PrimitiveType.Cube);
            aP.transform.position.x = new Vector3(j*2, 0, 0);
        }
    }

    Listing 1.23 A Matrix of Cubes Created Entirely with Script

    void Start ()
    {
        GameObject aP;
        int numRows= 9;
        int numCols = 9;
        for(int row = 1; row < = numRows; row++)
        {
            for(int col = 1; col < = numCols; col++)
            {
                aP = GameObject.CreatePrimitive(PrimitiveType.Cube);
                aP.transform.position.x = new Vector3(col*2, row*2, 0);
            }
        }
    }

    Listing 1.24 Storing Game Objects in an Array

    void Start ()
    {
        GameObject[] aP = new GameObject[9];
        for(int i = 0 ; i < 9 ; i++)
        {
            aP[i] = GameObject.CreatePrimitive(PrimitiveType.Cube);
            aP[i].transform.position = new Vector3(0,i + 1,0);
        }
    }

    Listing 1.25 Setting an Array of Cubes to the Color Red

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class CubeArray : MonoBehaviour {

        GameObject[] aP = new GameObject[9];
        void Start ()
        {
            for(int i = 0; i < 9; i++)
            {
                aP[i] = GameObject.CreatePrimitive(PrimitiveType.Cube);
                aP[i].transform.position = new Vector3(0,i + 1,0);
            }
        }

        void Update ()
        {
            for(int i = 0; i < 9; i++)
            {
                aP[i].GetComponent<Renderer>().material.color = Color.red;
            }
        }
    }

    Listing 1.26 Script to Change Cubes to Random Colors in Each Main Loop

    void Update ()
    {
        for(int i = 0; i < 9; i++)
        {
            aP[i].GetComponent<Renderer>().material.color = new Color(Random.Range(0.0f,1.0f), Random.Range(0.0f,1.0f), Random.Range(0.0f,1.0f));
        }
    }

    Listing 1.27 Changing the Location of a Game Object with Script

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class ChangeLocation : MonoBehaviour {
        GameObject gameObj;
        void Start()
        {
            gameObj = GameObject.CreatePrimitive(PrimitiveType.Capsule);
            gameObj.transform.position = new Vector3(1,5,2);
        }
    }

    Listing 1.28 Adding a Rigidbody to a Game Object Using Script

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class ChangeLocation : MonoBehaviour {
        GameObject gameObj;
        void Start()
        {
            gameObj = GameObject.CreatePrimitive(PrimitiveType.Capsule);
            gameObj.transform.position = new Vector3(1,5,2);
            gameObj.AddComponent<Rigidbody>();
        }
    }

    Listing 1.29 Modifying the Physics Material of a Game Object

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class ChangeLocation : MonoBehaviour {
        GameObject gameObj;
        void Start()
        {
            gameObj = GameObject.CreatePrimitive(PrimitiveType.Capsule);
            gameObj.transform.position = new Vector3(1,5,2);
            gameObj.AddComponent<Rigidbody>();
            PhysicMaterial material = new PhysicMaterial();
            material.bounciness = 1;
            gameObj.GetComponent<Collider>().material = material;
        }
    }

    Listing 1.30 Script to modify Properties of a Game Object to Which it is attached

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class ChangeLocation : MonoBehaviour {

        Color myColor = Color.red;
        void Start()
        {
            this.gameObject.AddComponent<Rigidbody>();
            PhysicMaterial material = new PhysicMaterial();
            material.bounciness = 0.5f;
            this.GetComponent<Collider>().material = material;
            this.collider.material = material;
            this.GetComponent<Renderer>().material.color = myColor;
            this.renderer.material.color = myColor;
        }
    }

    Listing 1.31 Exposing a Variable for Bounciness

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class bouncy : MonoBehaviour {

        Color myColor = Color.red;
        public float bouncyAmount = 0.5f;
        void Start()
        {
            this.gameObject.AddComponent<Rigidbody>();
            PhysicMaterial material = new PhysicMaterial();
            material.bounciness = bouncyAmount;
            this.GetComponent<Collider>().material = material;
            this.GetComponent<Collider>().material = material;
            this.GetComponent<Renderer>().material.color = myColor;
            this.GetComponent<Renderer>().material.color = myColor;
        }
    }

    Chapter 2

    Listing 2.1 Script to Make a Game Object Move in a Circular Path Around Its Starting Position

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class orbit : MonoBehaviour {

        float radius = 30;
        Vector3 startPosition;
        int speed = 3;

        void Start() {
            startPosition = transform.position;
        }

        void Update ()
        {
            transform.position = new Vector3(radius * Mathf.Sin(Time.fixedTime * speed) +
                startPosition.x,
                transform.position.y,
                radius * Mathf.Cos(Time.fixedTime * speed) +
                startPosition.z);
        }

    }

    Section 2.3.3 Translation, Rotation and Scaling

    The difference between JavaScript and C# in this section is that C# cannot set x, y and z values separately as JavaScript allows.

    this.transform.position.x += 3;
    this.transform.position.y += 5;
    this.transform.position.z += 8;

    Must be written in one line as:

    this.transform.Translate(3,5,8);

    The same applies for setting localScale and rotation.

    Section 2.3.4 Polygons and Normals

    Hands-On Meshes and Normals

    //CrumpleMesh.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class CrumpleMesh : MonoBehaviour {

        public float scale = 1.0f;
        public float speed = 0.5f;
        public bool recalculateNormals = false;

        Vector3[] baseVertices;
        Perlin noise;

        void Start ()
        {
            noise = new Perlin ();
        }

        void Update () {
            Mesh mesh = GetComponent<MeshFilter>().mesh;
           
            if (baseVertices == null)
            baseVertices = mesh.vertices;

            Vector3[] vertices = new Vector3[baseVertices.Length];
           
            float timex = Time.time * speed + 0.1365143f;
            float timey = Time.time * speed + 1.21688f;
            float timez = Time.time * speed + 2.5564f;
            for (int i=0;i<vertices.Length;i++)
            {
                Vector3 vertex = baseVertices[i];

                vertex.x += noise.Noise(timex + vertex.x,
                    timex + vertex.y,
                    timex + vertex.z) * scale;
                vertex.y += noise.Noise(timey + vertex.x, timey +
                    vertex.y,
                    timey + vertex.z) * scale;
                vertex.z += noise.Noise(timez + vertex.x,
                    timez + vertex.y,
                    timez + vertex.z) * scale;
               
                vertices[i] = vertex;
            }
           
            mesh.vertices = vertices;
           
            if (recalculateNormals)
            mesh.RecalculateNormals();
            mesh.RecalculateBounds();
        }
    }

    Section 2.4 Two-Dimensional Games in a 3D Game Engine

    Listing 2.2 Script to make one game object face another

    //Attack.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Attack : MonoBehaviour {

        public GameObject target;
        public float turnSpeed = 5.0f;

        void LookAt2D(Vector3 targetPos)
        {  
            Vector3 dir = targetPos - this.transform.position;  
            float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90;
            Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);  
            this.transform.rotation = Quaternion.Slerp(transform.rotation, q,
                Time.deltaTime * turnSpeed);
        }

        void Update ()
        {  
            LookAt2D(target.transform.position);
        }
    }

    Listing 2.3 Script to make an object move toward its target.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Attack : MonoBehaviour {

        public GameObject target;
        public float turnSpeed = 5.0f;
        public float flightSpeed = 0.3f;

        void LookAt2D(Vector3 targetPos)
        {  
            Vector3 dir = targetPos - this.transform.position;  
            float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90;
            Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);  
            this.transform.rotation = Quaternion.Slerp(transform.rotation, q,
                Time.deltaTime * turnSpeed);
        }

        void Update ()
        {  
            LookAt2D(target.transform.position);
            this.transform.Translate(Vector3.up * flightSpeed);
        }
    }

    Listing 2.4 Testing rocket’s distance to planet

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Attack : MonoBehaviour {

        public GameObject target;
        public float turnSpeed = 5.0f;
        public float flightSpeed = 0.3f;

        float distanceToTarget;
        string state = "ATTACK";

        void LookAt2D(Vector3 targetPos)
        {  
            Vector3 dir = targetPos - this.transform.position;  
            float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90;
            Quaternion q = Quaternion.AngleAxis(angle, Vector3.forward);  
            this.transform.rotation = Quaternion.Slerp(transform.rotation, q,
                Time.deltaTime * turnSpeed);
        }

        void Update ()
        {  
            distanceToTarget = (target.transform.position -
                this.transform.position).magnitude;
            if(distanceToTarget > 10)  
            {    
                state = "ATTACK";  
            }  
            else if (distanceToTarget < 2)  
            {    
                state = "RETREAT";  
            }  
            if(state == "ATTACK")  
            {    
                LookAt2D(target.transform.position);    
                this.transform.Translate(Vector3.up * flightSpeed);  
            }  
            else  
            {    
                this.transform.Translate(Vector3.up * flightSpeed);  
            }
        }
    }

    Listing 2.5 MoveBullet.cs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class MoveBullet : MonoBehaviour {

        float speed = 0.1f;

        void OnBecameInvisible()
        {
            Destroy(this.gameObject);
        }

        void Update ()
        {
            this.transform.Translate(Vector3.up * speed);
        }
    }

    Listing 2.6 Giving the script access to the bullet prefab

    public class Attack : MonoBehaviour {

    ...
    public float flightSpeed = 0.3f;

    public GameObject bullet;

    ...

    void Update ()
    {  
        Instantiate(bullet, this.transform.position, this.transform.rotation);
        distanceToTarget = (target.transform.position -
            this.transform.position).magnitude;
        if(distanceToTarget > 10)  
        ...

    Listing 2.7 Controlling the shooting based on the rocket’s facing direction.

        ...
        void Update ()
        {  
            //MOVE INSTANTIATE LINE FROM HERE TO BELOW
            distanceToTarget = (target.transform.position -
                this.transform.position).magnitude;
            if(distanceToTarget > 10)  
            {    
                state = "ATTACK";  
            }  
            else if (distanceToTarget < 2)  
            {    
                state = "RETREAT";  
            }  
            if(state == "ATTACK")  
            {    
                LookAt2D(target.transform.position);    
                this.transform.Translate(Vector3.up * flightSpeed);
                    Vector3 vectorToTarget = target.transform.position -
                this.transform.position;    
                if(Vector3.Angle(vectorToTarget, this.transform.up) < 30)
                {
                    Instantiate(bullet, this.transform.position,
                        this.transform.rotation);
                }

            }  
            else
    ...

    Listing 2.8 Adding 2D collision detection function.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class MoveBullet : MonoBehaviour {

        float speed = 0.1f;
        public GameObject explosion;

        void OnCollisionEnter2D(Collision2D collisionObj)
        {
            if (collisionObj.gameObject.name == "Earth")
            {
                Instantiate(explosion,this.transform.position, this.transform.rotation);
            }
        }

        void OnBecameInvisible()
        {
            Destroy(this.gameObject);
        }

        void Update ()
        {
            this.transform.Translate(Vector3.up * speed);
        }
    }

    Section 2.5.1 The Law of Gravity

    Equation 2.4

    transform.Translate(0,0,-1);

    Listing 2.9 Script to create a sphere as a projectile on a left mouse click
    Fire.cs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Fire : MonoBehaviour {

        void Update ()
        {
            if(Input.GetButtonDown("Fire1"))
            {
                Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
                GameObject sphere =
                GameObject.
                CreatePrimitive(PrimitiveType.Sphere);
                sphere.transform.position = ray.origin;
                sphere.AddComponent<Rigidbody>();
                sphere.GetComponent<Rigidbody>().AddForce(ray.direction * 1000);
            }
        }
    }

    Listing 2.10 Script to change the mass of a Rigidbody
    Fire.cs

    void Update ()
    {
        if(Input.GetButtonDown("Fire1"))
        {
            ...
            sphere.AddComponent<Rigidbody>();
            sphere.GetComponent<Rigidbody>().mass = 10;
            sphere.GetComponent<Rigidbody>().AddForce(ray.direction * 1000);
        }
    }

    Listing 2.11 Instantiating a game object and shooting it forward relative to the creator.

    //Fire.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Fire : MonoBehaviour {

        public GameObject bulletObject;
        void Update ()
        {
            if(Input.GetButtonDown("Fire1"))
            {
                GameObject newBullet = Instantiate(bulletObject,
                    this.transform.position,
                    this.transform.rotation);
                newBullet.GetComponent<Rigidbody>().AddForce(
                    this.transform.forward * 500);
            }
        }
    }

    Listing 2.12 Turn off an object’s physics on a collision.

    //Blob.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Blob : MonoBehaviour {

        void OnCollisionEnter(Collision collision)
        {
            if(collision.gameObject.name !=
                "First Person Controller")
            {
                GetComponent<Rigidbody>().isKinematic = true;
            }
        }

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
           
        }
    }

    Listing 2.13 Causing a squash effect by changing an object’s scale

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Blob : MonoBehaviour {

        void OnCollisionEnter(Collision collision)
        {
            if(collision.gameObject.name !=
                "First Person Controller")
            {
                GetComponent<Rigidbody>().isKinematic = true;
                Destroy (this.GetComponent<Collider>());
                ContactPoint contact = collision.contacts[0];
                Quaternion rot = Quaternion.FromToRotation(Vector3.up,
                    contact.normal);
                this.transform.position = contact.point;
                this.transform.rotation = rot;
                this.transform.localScale = new Vector3(
                    this.transform.localScale.x *
                    collision.relativeVelocity. magnitude/5.0f,
                    this.transform.localScale.y * 0.2f,
                    this.transform.localScale.z *
                    collision.relativeVelocity.magnitude/5.0f);
            }
        }

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
           
        }
    }

    Listing 2.14 Creating a timed explosion

    //Blob.cs
    public class Blob : MonoBehaviour {

        public GameObject exp;
        float timeToExplode = 5.0f;

        void Explosion()
        {
            Instantiate(exp, this.transform.position, this.transform.rotation);
            Destroy(this.gameObject,1);
        }

        void OnCollisionEnter(Collision collision)
        {
            if(collision.gameObject.name !=
                "First Person Controller")
            {
                ...
                this.transform.localScale = new Vector3(
                    this.transform.localScale.x *
                    collision.relativeVelocity. magnitude/5.0f,
                    this.transform.localScale.y * 0.2f,
                    this.transform.localScale.z *
                    collision.relativeVelocity.magnitude/5.0f);

                Invoke("Explode", timeToExplode);
            }
        }
        ...

    Listing 2.15 Destroying another object in an explosion.

    //Blob.cs
    public class Blob : MonoBehaviour {

        public GameObject exp;
        float timeToExplode = 5.0f;
        GameObject stuckOn;

        void Explosion()
        {
            Instantiate(exp, this.transform.position, this.transform.rotation);
            if(stuckOn && stuckOn.name == "Door")
            {
                Destroy(stuckOn);
            }

            Destroy(this.gameObject,1);
        }

        void OnCollisionEnter(Collision collision)
        {
            if(collision.gameObject.name !=
                "First Person Controller")
            {
                stuckOn = collision.gameObject;
                GetComponent<Rigidbody>().isKinematic = true;
                Destroy (this.GetComponent<Collider>());
                ...

    Listing 2.17 LOD Code

    //LODManager.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class LODManager : MonoBehaviour {

        public Mesh lod1;
        public Mesh lod2;
        public float lodDist1 = 80;
        public float lodDist2 = 120;
        public float updateInterval = 1.0f;
        public int currentLOD = 1;
        MeshFilter meshFilter;
        Transform thisTransform;

        void Awake()
        {
            meshFilter = GetComponent<MeshFilter>() as MeshFilter;
            thisTransform = transform;
            float startIn = Random.Range(0.0f, updateInterval);
            InvokeRepeating("UpdateLOD",startIn,updateInterval);
        }

        void UpdateLOD()
        {
            float distanceFromObject = Vector3.Distance(this.transform.position,
                Camera.main.transform.position);
            if (distanceFromObject < lodDist1)
            {
                if(currentLOD != 1)
                {
                    currentLOD = 1;
                    meshFilter.mesh = lod1;
                }
            }
            else if (distanceFromObject < lodDist2)
            {
                if(currentLOD != 2)
                {
                    currentLOD = 2;
                    meshFilter.mesh = lod2;
                }
            }
            else
            {
                currentLOD = 0;
                meshFilter.mesh = null;
            }
        }
    }

    Listing 2.18 A quick and easy script to create a virtual city from one building object.

    //InstantCity.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class InstantCity : MonoBehaviour {

        public GameObject building;
        void Start()
        {
            for(int i = 0; i < 20; i++)
            {
                for(int j = 0; j < 20; j++)
                {
                    Vector3 newPos =
                    new Vector3(
                        i*Random.Range(100,200),0,
                        j*Random.Range(100,200));
                    Instantiate(building, newPos,Quaternion.identity);
                }
            }
        }
    }

    Listing 2.19 Scrolling a Texture over the Surface of an Object

    //Scrolling.cs     
    using UnityEngine;
    using System.Collections;

    public class scrolling : MonoBehaviour {
        Vector2 uvSpeed = new Vector2( 0.0f, -1.0f );
        Vector2 uvOffset = Vector2.zero;
       
        void LateUpdate()
        {
            uvOffset += ( uvSpeed * Time.deltaTime );
            this.GetComponent<Renderer>().materials[0].
            SetTextureOffset("_MainTex", uvOffset);                
        }
    }

    Listing 2.20 Script to Create a Billboard from a Quad

    //FaceCamera.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class FaceCamera : MonoBehaviour {

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
            //note the minus in here as a Unity Quad has it’s Z axis facing in the opposite
            //direction to its textured side.
            this.transform.LookAt(-Camera.main.transform.position);
        }
    }

    Listing 2.21 Billboarding script that allows the x rotation to be turned off

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class FaceCamera : MonoBehaviour {

        public bool stayUpright = true;
        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
            this.transform.LookAt(-Camera.main.transform.position);
            if(stayUpright)
            this.transform.eulerAngles = new Vector3(0,
                this.transform.eulerAngles.y,
                this.transform.eulerAngles.z);
        }
    }

    Chapter 3

    Listing 3.1 Code to scroll a texture over the surface of a mesh.

    //Scrolling.cs     
    using UnityEngine;
    using System.Collections;

    public class scrolling : MonoBehaviour {
        Vector2 uvSpeed = new Vector2( 0.0f, -1.0f );
        Vector2 uvOffset = Vector2.zero;

        void LateUpdate()
        {
            uvOffset += ( uvSpeed * Time.deltaTime );
            this.GetComponent<Renderer>().materials[0].
                SetTextureOffset("_MainTex", uvOffset);                
        }
    }

    Listing 3.2 Code to scroll a texture over the surface of a mesh

    //Walk.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Walk : MonoBehaviour {

        public float speed = 0.1f;
        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
            if(Input.GetKey("right"))
            {
                this.transform.Translate(speed,0,0);
            }
           
            if(Input.GetKey("left"))
            {
                this.transform.Translate(-speed,0,0);
            }
        }
    }

    Listing 3.3 Script to Control a Model’s Movement and Animation

    //AnimControls.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class AnimControls : MonoBehaviour {

        Animator anim;
        float speed = 0.05f;
        float rotSpeed = 50.0f;

        // Use this for initialization
        void Start () {
            anim = gameObject.GetComponent<Animator>();
        }

        // Update is called once per frame
        void Update () {
            if(Input.GetKey("up"))
            {
                anim.Play("walking",0);
                this.transform.position += this.transform.forward * speed;
            }
            else if(Input.GetKey("down"))
            {
                anim.Play("walking",0);
                this.transform.position -= this.transform.forward * speed;
            }
            else if(Input.GetKeyUp("up") || Input.GetKeyUp("down"))
            {
                anim.Play("idle",0);
            }

        }
    }

    Listing 3.4 Updated AnimControls

    //AnimControls.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class AnimControls : MonoBehaviour {

        Animator anim;
        float speed = 0.05f;
        float rotSpeed = 50.0f;

        // Use this for initialization
        void Start () {
            anim = gameObject.GetComponent<Animator>();
        }

        // Update is called once per frame
        void Update () {
            if(Input.GetKey("up"))
            {
                anim.SetBool("amWalking",true);
                this.transform.position += this.transform.forward * speed;
            }
            else if(Input.GetKey("down"))
            {
                anim.SetBool("amWalking",true);
                this.transform.position -= this.transform.forward * speed;
            }
            else if(Input.GetKeyUp("up") || Input.GetKeyUp("down"))
            {
                anim.SetBool("amWalking",false);
            }

        }                  
    }

    Listing 3.5 Updated AnimControls

    //AnimControls.cs
    ...
    float rotSpeed = 50.0f;

    ...

    // Update is called once per frame
    void Update () {
        ...

        if(Input.GetKey("left"))
        {
            transform.Rotate(-Vector3.up * Time.deltaTime * rotSpeed);
        }
        else if(Input.GetKey("right"))
        {
            transform.Rotate(Vector3.up * Time.deltaTime * rotSpeed);
        }
    }

    Listing 3.6 Controlling the movement of a sprite with the arrow keys

    //SpriteManagement.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class SpriteManagement : MonoBehaviour {

        float speed = 0.01f;

        // Update is called once per frame
        void Update () {

            if(Input.GetKey (KeyCode.UpArrow))
            {  
                this.transform.Translate(0,speed,0);
            }
            else if(Input.GetKey (KeyCode.DownArrow))
            {
                this.transform.Translate(0,-speed,0);
            }
            else if(Input.GetKey (KeyCode.LeftArrow))
            {
                this.transform.Translate(-speed,0,0);
            }
            else if(Input.GetKey (KeyCode.RightArrow))
            {
                this.transform.Translate(speed,0,0);
            }
        }
    }

    Listing 3.7 Creating an animation array.

    public class SpriteManagement : MonoBehaviour {

    float speed = 0.01f;
    public GameObject[] anims;

    // Update is called once per frame
    void Update () {
    ...

    Listing 3.8 Creating class structures for strong values

    // Updated SpriteManagement.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class SpriteManagement : MonoBehaviour {

        float speed = 0.01f;
        public GameObject[] anims;
        int currentAnim = -1;

        // Use this for initialization
        void Start () {
            TurnAllAnimationsOff();
        }

        void TurnAllAnimationsOff()
        {
            foreach(GameObject i in anims)
            {
                i.SetActive(false);
            }
        }

        // Update is called once per frame
        void Update () {
            if(currentAnim != -1)
            //if there is a current animation set its speed to 1
            anims[currentAnim].GetComponent<Animator>().speed = 1;

            if(Input.GetKey (KeyCode.UpArrow))
            {
                //before turning on this animation
                //turn off the previous if it is a different one
                if(currentAnim != 0 && currentAnim != -1)
                    anims[currentAnim].SetActive(false);
               
          //move the character
          this.transform.Translate(0,speed,0);

            //make the appropriate sprite active and start playing
            anims[0].SetActive(true);

                //update the number of the current animation
                currentAnim = 0;
            }
            else if(Input.GetKey (KeyCode.DownArrow))
            {
                if(currentAnim != 1 && currentAnim != -1)
                anims[currentAnim].SetActive(false);
                this.transform.Translate(0,-speed,0);
                anims[1].SetActive(true);
                currentAnim = 1;
            }
            else if(Input.GetKey (KeyCode.LeftArrow))
            {
                if(currentAnim != 2 && currentAnim != -1)
                anims[currentAnim].SetActive(false);
                this.transform.Translate(-speed,0,0);
                anims[2].SetActive(true);
                currentAnim = 2;
            }
            else if(Input.GetKey (KeyCode.RightArrow))
            {
                if(currentAnim != 3 && currentAnim != -1)
                anims[currentAnim].SetActive(false);
                this.transform.Translate(speed,0,0);
                anims[3].SetActive(true);
                currentAnim = 3;
            }
            else
            {
                //if there is no key being pressed, set the current animation speed to 0
                //in otherwords, pause it.
                if(currentAnim != -1)
                anims[currentAnim].GetComponent<Animator>().speed = 0;
            }
        }
    }

    Chapter 4

    Listing 4.1 Code to destroy an object when it moves out of the camera’s view.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class DestroyWhenGone : MonoBehaviour {

        void OnBecameInvisible()
        {
            DestroyImmediate(this.gameObject); 
        }

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
           
        }
    }

    Listing 4.2 Spawning Objects at Random Intervals

    //Spawn.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Spawn : MonoBehaviour {

        public GameObject ball;
        public Material[] materialArray;

        // Update is called once per frame
        void Update () {
            if(Random.Range(0,200) < 1)
            {
                GameObject sphere = Instantiate(ball, new Vector3(0,5,0),
                    Quaternion.identity);
            }
        }
    }

    Listing 4.3 Setting a random value for the position of game objects.

    //Spawn.cs
    // Update is called once per frame
    void Update () {
        if(Random.Range(0,200) < 1)
        {
            Vector3 ballStartPosition = new Vector3(0,8,Random.Range(-4,4));
            GameObject sphere = Instantiate(ball,ballStartPosition,
                Quaternion.identity);
        }
    }

    Listing 4.4 Coloring a game object using an array of materials.

    //Spawn.cs
    void Update () {
        if(Random.Range(0,200) < 1)
        {
            Vector3 ballStartPosition = new Vector3(0,8,Random.Range(-4,4));
            GameObject sphere = Instantiate(ball,ballStartPosition,
                Quaternion.identity);

            sphere.GetComponent<Renderer>().material =
            materialArray[Random.Range(0,materialArray.Length)];
            sphere.GetComponent<Renderer>().material.shader =
            Shader.Find("Diffuse");
        }
    }

    Listing 4.5 Code to convert the mouse position on the screen to viewport and world coordinates.

    //DisplayMousePos.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class DisplayMousePos : MonoBehaviour {

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
            Debug.Log("Screen to Viewport " +
                Camera.main.ScreenToViewportPoint(Input.mousePosition));
            Debug.Log("Screen to World " +
                Camera.main.ScreenToWorldPoint(Input.mousePosition));
        }
    }

    Listing 4.6 Creating a draggable object.

    //ClickNDrag.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class ClickNDrag : MonoBehaviour {

        GameObject focusObj = null;
        Vector3 lastMousePosition;
        Vector3 deltaMousePosition;
        float mouseSensitivity = 1000.0f;

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
            if( Input.GetButtonDown("Fire1"))
            {
                focusObj = null;
                //cast a ray
                Ray ray = Camera.main.ScreenPointToRay
                (Input.mousePosition);
                RaycastHit hit;
               
                //if the ray hits an object and that object is a ball
                if(Physics.Raycast (ray, out hit, 100) &&
                    hit.transform.gameObject.tag == "ball")
                {
                    //take hold of it with the focusObj variable
                    focusObj = hit.transform.gameObject;
                   
                    //remember the location of the mouse
                    lastMousePosition = Input.mousePosition;
                }
            }

            //if the fire button is down
            if( focusObj && Input.GetButton("Fire1"))
            {
                //calculate how far the the mouse has moved across the screen
                deltaMousePosition = Input.mousePosition - lastMousePosition;

                //use this value to set the position of the object
                focusObj.transform.Translate(0,0,
                    deltaMousePosition.x/mouseSensitivity);
               
                //remember the location of the mouse
                lastMousePosition = Input.mousePosition;
            }
           
            //if the fire button is released
            if( focusObj && Input.GetButtonUp("Fire1"))
            {
                //forget about the object that was clicked on
                focusObj = null;
            }
        }
    }

    Listing 4.7 Script to register a collision on a triggering collider.

    //StopBalls.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class StopBalls : MonoBehaviour {

        void OnTriggerEnter (Collider obj)
        {
            obj.gameObject.tag = "Untagged";   
        }

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
           
        }
    }

    Listing 4.8 Code to test the colour of a game object against a variable value.

    //CountBalls.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class CountBalls : MonoBehaviour {

        public Material colorMatch;
        public int score = 0;
        void OnTriggerEnter (Collider obj)
        {
            if(obj.gameObject.GetComponent<Renderer>().material.color ==
                colorMatch.color)
            {
                score = score + 1; 
            }
        }

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
           
        }
    }

    Listing 4.9 Gathering scores from each box for a single score.

    //Score.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Score : MonoBehaviour {

        public int score = 0;
        public GUIStyle scoreStyle;
        public GameObject[] scoringObjects;
        int maxBalls = 10;

        void OnGUI ()
        {
            score = 0;
            for(var i = 0; i < scoringObjects.Length; i++)
            {
                //extract the score from the object and tally
                score += scoringObjects[i].GetComponent<CountBalls>().score;   
            }


            GUI.BeginGroup (new Rect (Screen.width - 85, 5, 80, 80));
            GUI.Box (new Rect (0,0,80,60), "Score");
            GUI.Label (new Rect (0, 20, 80, 30), string.Format("{0:0}", score), scoreStyle);
            GUI.EndGroup ();


            int totalBalls =
            scoringObjects[0].GetComponent<CountBalls>().score +
            scoringObjects[1].GetComponent<CountBalls>().score +
            scoringObjects[2].GetComponent<CountBalls>().score +           
            scoringObjects[3].GetComponent<CountBalls>().score;

            if(totalBalls >= maxBalls)
            {
                PlayerPrefs.SetInt("LastScore",score);
                Application.LoadLevel("gameover");
            }

        }

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
           
        }
    }

    Listing 4.10 Setting player preferences in code.

    //MainMenu.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class MainMenu : MonoBehaviour {

        void OnGUI ()
        {
            // Make a group on the center of the screen
            GUI.BeginGroup (new Rect (Screen.width / 2 - 50, Screen.height / 2 - 60,
                100, 120));
            // All rectangles are now adjusted to the group. (0,0)
            //is the topleft corner of the group.

            // We'll make a box so you can see where the group is on-screen.
            GUI.Box (new Rect (0,0,100,120), "Main Menu");
            if(GUI.Button (new Rect (10,40,85,30), "Play Level 1"))
            {
                PlayerPrefs.SetInt("Level", 1);
                Application.LoadLevel("maingame"); 
            }
           
            if(GUI.Button (new Rect (10,80,85,30), "Play Level 2"))
            {
                PlayerPrefs.SetInt("Level", 2);
                Application.LoadLevel("maingame"); 
            }


            // End the group we started above. This is very important to remember!
            GUI.EndGroup ();
        }

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
           
        }
    }

    Listing 4.11 A start function that loads the player preference and uses it to set the difficulty of the game.
    To Spawn.cs add the Start function.

    // Use this for initialization
    void Start () {
        int playerlevel = PlayerPrefs.GetInt("Level");
        if(playerlevel == 1)
        {
            GameObject.Find("Cutoff").transform.position = new Vector3(0,1,0);
        }
        else if(playerlevel == 2)
        {
            GameObject.Find("Cutoff").transform.position = new Vector3(0,3,0);
        }
    }

    Listing 4.12 Displaying a game over screen with the score.

    //ShowScore.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class ShowScore : MonoBehaviour {
        public Texture2D goImage;

        void OnGUI ()
        {
            string scoreText = "You Scored " + PlayerPrefs.GetInt("LastScore");
            GUI.BeginGroup (new Rect (Screen.width / 2 - 100,
                Screen.height / 2 - 100, 200, 200));
            GUI.Box (new Rect (0,0,200,200), goImage);
            GUI.Label (new Rect (55, 15, 100, 30), scoreText);
            if(GUI.Button (new Rect (25,165,150,30), "Back to Menu"))
            {
                Application.LoadLevel("mainmenu"); 
            }
            GUI.EndGroup ();
        }

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
           
        }
    }

    Listing 4.13 Code to gather a total count of balls in each box.

    Already added in the code in Listing 4.9

    Listing 4.14 Rotating a game object around its axes with the arrow keys.

    void Update () {
        if (Input.GetKey ("up")) //if up key is pressed
        {
            //rotate upward around the side axis
            this.transform.RotateAround (this.transform.position,this.transform.right,
                20 * Time.deltaTime);
        }
        if (Input.GetKey ("down"))
        {
            //rotate downward around the side axis
            this.transform.RotateAround (this.transform.position,this.transform.right,
                -20 * Time.deltaTime);
        }
        if (Input.GetKey ("right"))
        {
            this.transform.RotateAround (this.transform.position,this.transform.forward,
                -20 * Time.deltaTime);
        }
        if (Input.GetKey ("left"))
        {
            this.transform.RotateAround (this.transform.position,this.transform.forward,
                20 * Time.deltaTime);
        }
    }

    Listing 4.15 Code to instantiate an object and shoot it from another game object.

    public class aim : MonoBehaviour {

        public GameObject cannonball;

        // Use this for initialization
        void Start () {
           
        }

        // Update is called once per frame
        void Update () {
            if (Input.GetKey ("up")) //if up key is pressed
            {
                //rotate upward around the side axis
                this.transform.RotateAround (this.transform.position,this.transform.right,
                    20 * Time.deltaTime);
            }
            if (Input.GetKey ("down"))
            {
                //rotate downward around the side axis
                this.transform.RotateAround (this.transform.position,this.transform.right,
                    -20 * Time.deltaTime);
            }
            if (Input.GetKey ("right"))
            {
                this.transform.RotateAround(this.transform.position,
                    this.transform.forward,
                    -20 * Time.deltaTime);
            }
            if (Input.GetKey ("left"))
            {
                this.transform.RotateAround
                (this.transform.position,this.transform.forward,
                    20 * Time.deltaTime);
            }

            if(Input.GetKeyUp ("space"))
            {
                GameObject cb = Instantiate(cannonball,
                    this.transform.position, this.transform.rotation);
                cb.GetComponent<Rigidbody>().AddForce(this.transform.up * 10000);
            }
        }
    }

    Listing 4.16 Creating an explosion on impact.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class explode : MonoBehaviour {

        public GameObject explosion;
        public float explosionLife = 5.0f;
        public float detailLevel = 1.0f;
        public float countdown = 5.0f;
        Quaternion explosionDirection;
        Vector3 explosionLocation;

        void OnCollisionEnter(Collision collision)
        {
            GetComponent<Rigidbody>().isKinematic = true;
            Destroy (this.GetComponent<Collider>());
            ContactPoint contact = collision.contacts[0];
            Quaternion rot = Quaternion.FromToRotation(Vector3.up, contact.normal);
            explosionDirection = rot;
            float offsetSize = (explosion.GetComponent("Detonator") as Detonator).size /
            3.0f;
            Vector3 explosionLocation = contact.point + ((Vector3.Scale(contact.normal,
                new Vector3(offsetSize,offsetSize,offsetSize))));
            float timeSet = Time.fixedTime + countdown;
            bool explosionActivated = true;
            if(collision.gameObject.name != "Terrain")
            {
                Destroy(collision.gameObject,1);
            }
            Explode();
            Destroy(this.gameObject);
        }

        void Explode()
        {
            GameObject exp = Instantiate (explosion,explosionLocation,
                explosionDirection);
            (exp.GetComponent("Detonator") as Detonator).detail = detailLevel;
            Destroy(exp, explosionLife);
        }
    }

    Listing 4.17 Creating a visual meter for setting cannon strength.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class strengthMeter : MonoBehaviour {

        public static float shotStrength;
        void OnGUI ()
        {
            GUI.Box (new Rect (0,0,220,40), "Force");
            shotStrength = Slider (new Rect (10,20,200,30), shotStrength);
        }

        float Slider (Rect screenRect, float strength)
        {
            strength = GUI.HorizontalSlider (screenRect, strength, 0.0f, 1.0f);
            return strength;
        }
    }

    Listing 4.18 Script to build up firing strength when space is down and to fire when space is released.

    void Update ()
    {
        if (Input.GetKey ("up")) //if up key is pressed
        {
            //rotate upward around the side axis
            this.transform.RotateAround (this.transform.position,
                this.transform.right, 20 * Time.deltaTime);
        }
        ...
        if (Input.GetKey ("left"))
        {
            this.transform.RotateAround (this.transform.position,
                this.transform.forward,
                20 * Time.deltaTime);
        }

        if(Input.GetKey("space"))
        {
            //each loop the space is down increase the strength
            strengthMeter.shotStrength =
            strengthMeter.shotStrength + 0.01f;
        }

        if(Input.GetKeyUp ("space"))
        {
            GameObject cball = Instantiate(cannonball,
                this.transform.position, this.transform.rotation);
            //use built up strength to influence the shot
            float strength = strengthMeter.shotStrength * 10000;
            cball.GetComponent<Rigidbody>().AddForce(this.transform.up *
                strength);
            //set strength back to 0 after a shot
            strengthMeter.shotStrength = 0;
        }
    }

    Listing 4.19 Call a game over screen.
    a) C# version of the waypoints.js script

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class waypoints : MonoBehaviour {

        public int currentWP = 0;

        //the array of waypoints in order of visiting
        //can be made up of any game objects
        Public GameObject[] wps;

        int speed = 5;
        int rotationSpeed = 2;

        //how close to get to the waypoint to consider having reached it
        float accuracy = 5.0f;

        void Update ()
        {
            if(wps.Length == 0) return;
            if(Vector3.Distance(wps[currentWP].transform.position,
                transform.position) < accuracy)
            {
                currentWP++;
                if(currentWP >= wps.Length)
                {
                    currentWP = 0;
                }  
            }
           
            //rotate towards target
            Vector3 direction = wps[currentWP].transform.position -
            transform.position;
            transform.rotation = Quaternion.Slerp(transform.rotation,
                Quaternion.LookRotation(direction),
                rotationSpeed * Time.deltaTime);
            transform.Translate(0, 0, Time.deltaTime * speed);
        }
    }

    b) finishline.cs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class finishLine : MonoBehaviour {

        string winner = "";
        Vector3 playerLocation;
        Vector3 npcLocation;

        void Start()
        {
            //remember location and orientation of both cars at
            //the start
            playerLocation = GameObject.Find("Car").transform.position;
            npcLocation = GameObject.Find("Player2").transform.position;
        }

        void OnTriggerEnter(Collider collision)
        {
            //if there is no winner yet
            if(winner == "")
            {
                //make this one the winner
                winner = collision.gameObject.name;
            }
        }

        void OnGUI ()
        {
            if(winner != "")
            {
                GUI.BeginGroup(new Rect(Screen.width/2-100,
                    Screen.height/2-100,200,200));
                GUI.Box (new Rect (0,0,200,200), "Game Over");
                GUI.Label(new Rect (20,20,200,100), "Winner: " + winner);
                if(GUI.Button (new Rect (50,60,100,30), "Play Again"))
                {
                    //reset the game
                    winner = "";
                    GameObject.Find("Car").transform.position = playerLocation;
                    GameObject.Find("Player2").transform.position = npcLocation;
                    (GameObject.Find("Player2").GetComponent("waypoints")
                        as waypoints).currentWP = 0;
                }
                GUI.EndGroup ();
            }
        }
    }

    Listing 4.20 Code to decline the health bar.

    //ginterface.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;

    public class ginterface : MonoBehaviour {

        static public float gHealth = 100.0f;
        public Slider health;

        void Update ()
        {
            gHealth -= 0.1f;
            if(gHealth > 100) gHealth = 100;
            health.value = gHealth;
        }
    }

    Listing 4.21 Triggering a death animation.

    //grannyWalker.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class grannyWalker : MonoBehaviour {

        Animator anim;
        float speed= 0.1f;

        void Start ()
        {
            anim = gameObject.GetComponent<Animator>();
        }

        void Update ()
        {

            if(ginterface.gHealth <= 0)
            {
                anim.SetTrigger("dead");
                return;
            }
           
            if(Input.GetKey("left"))
            {
                this.transform.Rotate(Vector3.up, -3);
            }
            else if(Input.GetKey("right"))
            {
                this.transform.Rotate(Vector3.up, 3);
            }
            else if(Input.GetKey("up"))
            {
                anim.SetBool("running",true);
                this.transform.position += this.transform.forward * speed;
            }
            else if(Input.GetKey("down"))
            {
                anim.SetBool("running",true);
                this.transform.position -= this.transform.forward * speed;
            }
            else if(Input.GetKeyUp("up") || Input.GetKeyUp("down"))
            {
                anim.SetBool("running",false);
            }
        }
    }

    Listing 4.22 Code to increase health bar.

    //pickup.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class pickup : MonoBehaviour {

        void OnTriggerEnter(Collider other)
        {
            if(other.gameObject.name == "Sporty_Granny")
            {
                ginterface.gHealth += 50;
                this.GetComponent<AudioSource>().Play();
                Destroy(this.gameObject);
            }
        }
    }

    Listing 4.23 Code to increase health and play sound.

    //pickup.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class pickup : MonoBehaviour {

        void OnTriggerEnter(Collider other)
        {
            if(other.gameObject.name == "Sporty_Granny")
            {
                ginterface.gHealth += 50;
                GameObject.Find("PickupSound").
                GetComponent<AudioSource>().Play();
                Destroy(this.gameObject);
            }
        }
    }

    Listing 4.24 Code to randomly drop chests on the ground plane.

    //dropChests.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class dropChests : MonoBehaviour {

        public GameObject chestObj;
        public int numberOfChests = 50;

        void Start ()
        {
            for(int i = 0; i < numberOfChests; i++)
            {
                Vector3 pos = new Vector3(Random.Range(-100,100),
                    0.14f, Random.Range(-100,100));
                Instantiate(chestObj, pos, Quaternion.identity);
            }

        }
    }

    Listing 4.25 A script to decrease the player health while they remain inside a collider.

    //firehit.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class firehit : MonoBehaviour {

        void OnTriggerStay(Collider other)
        {
            if(other.gameObject.name == "Sporty_Granny")
            {
                ginterface.gHealth -= 2;
            }
        }
    }

    Listing 4.26 Creating a HUD radar to track game objects with the tag orb.

    //radar.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class radar : MonoBehaviour {

        public Texture orbspot;
        public Transform playerPos;
        float mapScale = 0.5f;
        float radarSpotX;
        float radarSpotY;
        float radarWidth = 100f;
        float radarHeight = 100f;

        void OnGUI ()
        {
            GUI.BeginGroup (new Rect (10, Screen.height-radarHeight-10,
                radarWidth, radarHeight));
            GUI.Box (new Rect (0, 0, radarWidth, radarHeight), "Radar");
            DrawSpotsForOrbs();
            GUI.EndGroup();
        }

        void DrawRadarBlip(GameObject go, Texture spotTexture)
        {
            Vector3 gameObjPos = go.transform.position;
            //find distance between object and player
            float dist = Vector3.Distance(playerPos.position, gameObjPos);
            //find the horizontal distances along the
            //x and z between player and object
            float dx = playerPos.position.x - gameObjPos.x;
            float dz = playerPos.position.z - gameObjPos.z;
            //determine the angle of rotation between the
            //direction the player is facing and the location
            //of the object
            float deltay = Mathf.Atan2(dx, dz) *
            Mathf.Rad2Deg-270-playerPos.eulerAngles.y;

            //orient the object on the radar according to the
            //direction the player is facing
            radarSpotX = dist * Mathf.Cos(deltay * Mathf.Deg2Rad) * mapScale;
            radarSpotY = dist * Mathf.Sin(deltay * Mathf.Deg2Rad) * mapScale;
            //draw a spot on the radar
            GUI.DrawTexture( new Rect(radarWidth/2.0f + radarSpotX,
                radarHeight/2.0f + radarSpotY, 2, 2),
            spotTexture);
        }

        void DrawSpotsForOrbs()
        {
            GameObject[] gos;
            //look for all objects with a tag of orb
            gos = GameObject.FindGameObjectsWithTag("orb");
            double distance = Mathf.Infinity;
            Vector3 position = transform.position;
            foreach(GameObject go in gos)
            {
                DrawRadarBlip(go,orbspot);
            }
        }
    }

    Chapter 5

    Listing 5.1 & 5.2 Basic line of sight script.

    //lineOfSight.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class lineOfSight : MonoBehaviour {

        public Transform target; //the enemy
        float seeRange = 20.0f; //maximum attack distance –
        //will attack if closer than
        //this to the enemy
        float shootRange = 8.0f;
        float keepDistance = 2.0f; //closest distance to get to enemy
        float rotationSpeed = 2.0f;
        float sightAngle = 60f;
        float speed = 0.1f;
        string state = "PATROL";

        Animator anim;
        public GameObject magic;

        void Start()
        {
            anim = gameObject.GetComponent<Animator>();
            magic = GameObject.Find("Magic");
            magic.GetComponent<ParticleSystem>().Stop();
            Patrol();
        }

        void TurnOnMagic()
        {
            magic.GetComponent<ParticleSystem>().Play();
        }

        void TurnOffMagic()
        {
            magic.GetComponent<ParticleSystem>().Stop();
        }

        void Update ()
        {
            if(anim.GetCurrentAnimatorClipInfo(0)[0].clip.name ==
                "Standing_Walk_Forward")
            speed = 0.1f;
            else
            speed = 0.0f;
           
            if (CanSeeTarget ())
            {
                if(CanShoot())
                {
                    state = "SHOOTING";
                    anim.SetBool("isWalking",false);
                    anim.SetBool("isAttacking",true);
                    Shoot();
                }
                else
                {
                    state = "PURSUE";
                    anim.SetBool("isWalking",true);
                    Pursue();
                }
            }
            else
            {
                state = "PATROL";
                anim.SetBool("isWalking",false);
                anim.SetBool("isAttacking",false);
                Patrol();
            }
        }

        void Patrol ()
        {
        //stand around
        }

        bool CanSeeTarget ()
        {
        Vector3 directionToTarget = target.position - transform.Find("Eyes").position;
        float angle = Vector3.Angle(directionToTarget,
            this.transform.Find("Eyes").forward);
        if (Vector3.Distance(transform.Find("Eyes").position, target.position) >
            seeRange || angle > sightAngle)
        return false;
        return true;
        }

        bool CanShoot()
        {
        if (Vector3.Distance(transform.Find("Eyes").position, target.position) >
            shootRange)
        return false;
        return true;
        }

        void Pursue()
        {
        Vector3 position = target.position;
        Vector3 direction = position - transform.Find("Eyes").position;
        direction.y = 0;
            // Rotate towards the target
            transform.Find("Eyes").rotation = Quaternion.Slerp
            (transform.Find("Eyes").rotation, Quaternion.LookRotation(direction),
                rotationSpeed * Time.deltaTime);
            transform.eulerAngles = new Vector3(0,transform.eulerAngles.y, 0);
            // Move the character
            if(direction.magnitude > keepDistance)
            {
                direction = direction.normalized * speed;
                transform.position += direction;
            }
        }

        void Shoot()
        {
            Vector3 position = target.position;
            Vector3 direction = position - transform.Find("Eyes").position;
            direction.y = 0;
            // Rotate towards the target
            transform.rotation = Quaternion.Slerp(transform.rotation,
                Quaternion.LookRotation(direction),
                rotationSpeed * Time.deltaTime);
            transform.eulerAngles = new Vector3(0, transform.
                eulerAngles.y, 0);
        }
    }

    Listing 5.3 A breadth-first search algorithm.
    No change
    Listing 5.4 A depth-first search algorithm.
    No change

    Listing 5.5 Initialising waypoints in a graph object.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class patrol : MonoBehaviour {

        public GameObject[] waypoints;
        Graph graph = new Graph();
        int currentWP = 0;
        GameObject currentNode;

        int speed = 8;
        int rotationSpeed = 5;
        float accuracy = 1.0f;


        // Use this for initialization
        void Start () {
            if(waypoints.Length > 0)
            {
                // add all the waypoints to the graph
                for(int i = 0; i < waypoints.Length; i++)
                {
                    graph.AddNode(waypoints[i], true, true);
                }
               
                //create edges between the waypoints
                graph.AddEdge(waypoints[0], waypoints[1]);
                graph.AddEdge(waypoints[1], waypoints[2]);
                graph.AddEdge(waypoints[2], waypoints[3]);
                graph.AddEdge(waypoints[3], waypoints[4]);
                graph.AddEdge(waypoints[4], waypoints[5]);
                graph.AddEdge(waypoints[5], waypoints[6]);
                graph.AddEdge(waypoints[6], waypoints[7]);
                graph.AddEdge(waypoints[7], waypoints[8]);
                graph.AddEdge(waypoints[8], waypoints[0]);
               
            }
            currentNode = waypoints[0];
        }

        // Update is called once per frame
        void Update () {
            graph.debugDraw();
        }
    }

    Listing 5.6 Ordering a guard to traverse waypoints.

    public GameObject[] waypoints;
    ...

        void OnGUI ()
        {
            GUI.Box (new Rect (10,10,100,90), "Guard's Orders");

            if (GUI.Button (new Rect (20,65,80,20), "Patrol"))
            {
                graph.AStar(waypoints[0],waypoints[8]);

                this.GetComponent<Animation>().Play("run");
                this.GetComponent<Animation>()["run"].wrapMode = WrapMode.Loop;
            }
        }

    ...    

        void Update () {
            graph.debugDraw();
            //if there is no path or at the end don't do anything
            if(graph.getPathLength() == 0 || currentWP == graph.getPathLength())
            {
                this.GetComponent<Animation>().Play("idle");
                return;
            }  

            //the node we are closest to at this moment
            currentNode = graph.getPathPoint(currentWP);

            //if we are close enough to the current waypoint move to next
            if(Vector3.Distance(
                graph.getPathPoint(currentWP).transform.position,
                transform.position) < accuracy)
            {
                currentWP++;
            }

            //if we are not at the end of the path
            if(currentWP < graph.getPathLength())
            {
              //keep on movin'
              Vector3 direction = graph.getPathPoint(currentWP).transform.position -
              transform.position;
              transform.rotation = Quaternion.Slerp(transform.rotation,
                Quaternion.LookRotation(direction),
                rotationSpeed * Time.deltaTime);
              transform.Translate(0, 0, Time.deltaTime * speed);
             }
        }

    Listing 5.7 Testing A* pathfinding by given movement comments to a character.

    ...
    void OnGUI ()
    {
        GUI.Box (new Rect (10,10,100,90), "Guard's Orders");

        if (GUI.Button (new Rect (20,65,80,20), "Front Door"))
        {
            graph.AStar(currentNode,waypoints[0]);
            currentWP = 0;
           
            this.GetComponent<Animation>().Play("run");
            this.GetComponent<Animation>()["run"].wrapMode = WrapMode.Loop;
        }
        if (GUI.Button (new Rect (20,90,80,20), "Driveway"))
        {
            graph.AStar(currentNode,waypoints[9]);
            currentWP = 0;
           
            this.GetComponent<Animation>().Play("run");
            this.GetComponent<Animation>()["run"].wrapMode = WrapMode.Loop;
        }
       
        if (GUI.Button (new Rect (20,115,80,20), "Front"))
        {
            graph.AStar(currentNode,waypoints[1]);
            currentWP = 0;
           
            this.GetComponent<Animation>().Play("run");
            this.GetComponent<Animation>()["run"].wrapMode = WrapMode.Loop;
        }
    }

    // Use this for initialization
    void Start () {
        if(waypoints.Length > 0)
        {
            // add all the waypoints to the graph
            for(int i = 0; i < waypoints.Length; i++)
            {
                graph.AddNode(waypoints[i], true, true);
            }

            //create edges between the waypoints
            graph.AddEdge(waypoints[0], waypoints[1]);
            graph.AddEdge(waypoints[1], waypoints[2]);
            graph.AddEdge(waypoints[2], waypoints[3]);
            graph.AddEdge(waypoints[3], waypoints[4]);
            graph.AddEdge(waypoints[4], waypoints[5]);
            graph.AddEdge(waypoints[5], waypoints[6]);
            graph.AddEdge(waypoints[6], waypoints[7]);
            graph.AddEdge(waypoints[7], waypoints[8]);
            graph.AddEdge(waypoints[8], waypoints[0]);

            //and back the other way
            graph.AddEdge(waypoints[1], waypoints[0]);
            graph.AddEdge(waypoints[2], waypoints[1]);
            graph.AddEdge(waypoints[3], waypoints[2]);
            graph.AddEdge(waypoints[4], waypoints[3]);
            graph.AddEdge(waypoints[5], waypoints[4]);
            graph.AddEdge(waypoints[6], waypoints[5]);
            graph.AddEdge(waypoints[7], waypoints[6]);
            graph.AddEdge(waypoints[8], waypoints[7]);
            graph.AddEdge(waypoints[0], waypoints[8]);

            //create edges to extra to waypoints
            graph.AddEdge(waypoints[0], waypoints[8]);
            graph.AddEdge(waypoints[0], waypoints[9]);
            graph.AddEdge(waypoints[9], waypoints[9]);
            graph.AddEdge(waypoints[5], waypoints[8]);
            //and back again
            graph.AddEdge(waypoints[8], waypoints[0]);
            graph.AddEdge(waypoints[9], waypoints[0]);
            graph.AddEdge(waypoints[9], waypoints[9]);
            graph.AddEdge(waypoints[8], waypoints[5]);

        }
        currentNode = waypoints[0];
    }

    Listing 5.8 Code for simple finite state machine.
    First line changes from

    function FSM()

    To

    void FSM()

    Listing 5.9 Setting up a waypoint system with automatic waypoint collection.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class patrol : MonoBehaviour {

        Graph graph = new Graph();
        int currentWP = 0;
        GameObject currentNode;
        int speed = 8;
        int rotationSpeed = 5;
        float accuracy = 1;


        void CreateBiPath(string a, string b)
        {
            GameObject w1 = GameObject.Find(a);
            GameObject w2 = GameObject.Find(b);
           
            if(w1 && w2) //if both objects exist
            {
                //create edges between the waypoints
                //in both directions
                graph.AddEdge(w1, w2);
                graph.AddEdge(w2, w1);
            }

        }
        // Use this for initialization
        void Start () {
            GameObject[] gos;
            gos = GameObject.FindGameObjectsWithTag("waypoint");
           
            foreach (GameObject go in gos)
            {
                graph.AddNode(go, true, true);
            }
           
            CreateBiPath("Sphere3","Sphere2");
            CreateBiPath("Sphere2","Sphere1");
            CreateBiPath("Sphere1","Sphere4");
            CreateBiPath("Sphere3","Sphere4");
            CreateBiPath("Sphere4","Sphere5");
            CreateBiPath("Sphere5","Sphere6");
            CreateBiPath("Sphere6","Sphere7");
            CreateBiPath("Sphere7","Sphere8");
            CreateBiPath("Sphere8","Sphere9");
            CreateBiPath("Sphere9","Sphere10");
            CreateBiPath("Sphere10","Sphere11");
            CreateBiPath("Sphere11","Sphere12");
            CreateBiPath("Sphere12","Sphere13");
            CreateBiPath("Sphere13","Sphere14");
            CreateBiPath("Sphere14","Sphere15");
            CreateBiPath("Sphere15","Sphere17");
           
            currentNode = GameObject.Find("Sphere2");
        }

        // Update is called once per frame
        void Update () {
            graph.debugDraw();
        }
    }

    Listing 5.10 & 5.11 Adding a FSM function and Extending with more states

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class patrol : MonoBehaviour {

        Graph graph = new Graph();
        int currentWP = 0;
        GameObject currentNode;
        int speed = 8;
        int rotationSpeed = 5;
        float accuracy = 1;

        string prevState = "";
        string state = "idle";
        string eventname = "enter";
        GameObject goalLocation;

        public Transform target;
        float seeRange = 10;
        float shootRange = 5;
        float keepDistance = 1;
        float heightOffset = 0.3f;

        void CreateBiPath(string a, string b)
        {
            GameObject w1 = GameObject.Find(a);
            GameObject w2 = GameObject.Find(b);
           
            if(w1 && w2) //if both objects exist
            {
                //create edges between the waypoints
                //in both directions
                graph.AddEdge(w1, w2);
                graph.AddEdge(w2, w1);
            }

        }

        bool CanSeeTarget ()
        {
            if (Vector3.Distance(transform.position, target.position) > seeRange)
            return false;
            return true;
        }

        bool CanShootTarget()
        {
            if(!CanSeeTarget()) return false;
            if (Vector3.Distance(transform.position, target.position) > shootRange)
            return false;
            return true;
        }

        // Use this for initialization
        void Start () {
            GameObject[] gos;
            gos = GameObject.FindGameObjectsWithTag("waypoint");
           
            foreach (GameObject go in gos)
            {
                graph.AddNode(go, true, true);
            }
           
            CreateBiPath("Sphere3","Sphere2");
            CreateBiPath("Sphere2","Sphere1");
            CreateBiPath("Sphere1","Sphere4");
            CreateBiPath("Sphere3","Sphere4");
            CreateBiPath("Sphere4","Sphere5");
            CreateBiPath("Sphere5","Sphere6");
            CreateBiPath("Sphere6","Sphere7");
            CreateBiPath("Sphere7","Sphere8");
            CreateBiPath("Sphere8","Sphere9");
            CreateBiPath("Sphere9","Sphere10");
            CreateBiPath("Sphere10","Sphere11");
            CreateBiPath("Sphere11","Sphere12");
            CreateBiPath("Sphere12","Sphere13");
            CreateBiPath("Sphere13","Sphere14");
            CreateBiPath("Sphere14","Sphere15");
            CreateBiPath("Sphere15","Sphere17");
           
            currentNode = GameObject.Find("Sphere2");
        }

        void FSM()
        {
            Vector3 direction;
            Vector3 position;
           
            if(state == "patrol")
            {
                if(prevState != state)
                {
                    print("patrol " + currentNode.name);
                    graph.AStar(currentNode,goalLocation);
                    graph.printPath();
                    currentWP = 0;
                   
                    this.GetComponent<Animation>().Play("run");
                    this.GetComponent<Animation>()["run"].wrapMode =
                    WrapMode.Loop;
                    eventname = "update";
                    prevState = state;
                }
                else if (eventname == "update")
                {
                    if(graph.getPathLength() == 0 ||
                        currentWP == graph.getPathLength())
                    {
                        state = "idle";
                        eventname = "enter";
                        return;
                    }

                    //the node we are closest to at this moment
                    currentNode = graph.getPathPoint(currentWP);

                    if(Vector3.Distance(
                        graph.getPathPoint(currentWP).transform.position,
                        transform.position) < accuracy)
                    {
                        currentWP++;
                    }

                    //if we are not at the end of the path
                    if(currentWP < graph.getPathLength())
                    {
                        //keep on movin'
                        direction =
                        graph.getPathPoint(currentWP).transform.position -
                        transform.position;
                        transform.rotation = Quaternion.Slerp(transform.rotation,
                            Quaternion.LookRotation(direction),
                            rotationSpeed * Time.deltaTime);
                        transform.Translate(0, 0, Time.deltaTime * speed);
                    }

                }
                else if (eventname == "exit")
                {
                   
                }  
            }
            else if(state == "attack")
            {
                if(prevState != state)
                {
                    this.GetComponent<Animation>().CrossFade("shoot");
                    this.GetComponent<Animation>()["shoot"].wrapMode =
                    WrapMode.Loop;
                    eventname = "update";  
                }
                else if(eventname == "update")
                {
                    position = target.position;
                    direction = position - transform.position;
                    direction.y = 0;
                    // Rotate towards the target
                    transform.rotation = Quaternion.Slerp(transform.rotation,
                        Quaternion.LookRotation(direction), rotationSpeed *
                        Time.deltaTime);
                    transform.position = new Vector3(transform.position.x,
                        target.position.y + heightOffset,
                        transform.position.z);
                }
               
            }
            else if(state == "pursue")
            {
                if(prevState != state)
                {
                    this.GetComponent<Animation>().CrossFade("run");
                    this.GetComponent<Animation>()["run"].wrapMode =
                    WrapMode.Loop;
                    eventname = "update";  
                }
                else if(eventname == "update")
                {
                    direction = target.position - transform.position;
                    direction.y = 0;
                    // Rotate towards the target
                    transform.rotation = Quaternion.Slerp(transform.rotation,
                        Quaternion.LookRotation(direction),
                        rotationSpeed * Time.deltaTime);

                    // Move the character
                    if(direction.magnitude > keepDistance)
                    {
                        transform.Translate(0, 0, Time.deltaTime * speed);
                    }
                    transform.position = new Vector3(transform.position.x,
                        target.position.y + heightOffset,
                        transform.position.z);
                }
               
            }
            else if(state == "idle")
            {
                print("play idle");
                this.GetComponent<Animation>().Play("idle");
                eventname = "update";
                prevState = state; 

                if(eventname == "update")
                {
                   
                    //just remain idle 
                    if(Random.Range(0,10) < 5)
                    {
                        state = "patrol";
                        eventname = "enter";

                        if(currentNode == GameObject.Find("Sphere17"))
                        goalLocation = GameObject.Find("Sphere2");
                        else
                        goalLocation = GameObject.Find("Sphere17");
                    }
                }
               
            }
        }

        // Update is called once per frame
        void Update () {
            graph.debugDraw();
            if(CanShootTarget())
            {
                prevState = state;
                state = "attack";
            }
            else if(CanSeeTarget())
            {
                prevState = state;
                state = "pursue";
            }
            else if(state != "patrol")
            {
                prevState = state;
                state = "idle";
            }

            FSM();
        }
    }

    Listing 5.12 Recording player movement with breadcrumbs

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class breadcrumbs : MonoBehaviour {

        public ArrayList crumbs = new ArrayList();
        Vector3 lastPos;

        public void RemoveBreadCrumb()
        {      
            Destroy(crumbs[0] as GameObject);
            crumbs.RemoveAt(0);
        }

        void Update ()
        {
            if(lastPos != this.transform.position)
            {
                GameObject bc = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                bc.transform.position = this.transform.position;
                Destroy(bc.GetComponent<Collider>());
                bc.transform.localScale = new Vector3(0.5f,0.5f,0.5f);
                bc.GetComponent<Renderer>().material.color = Color.green;
                crumbs.Add(bc);
            }
            lastPos = this.transform.position;
           
            if(crumbs.Count > 100)
            {
                RemoveBreadCrumb();
            }
        }
    }

    Listing 5.13 Adding breadcrumb following code to the NPC.

    ...
    else if(state == "pursue")
    {
    if(prevState != state)
    {
        this.GetComponent<Animation>().CrossFade("run");
        this.GetComponent<Animation>()["run"].wrapMode = WrapMode.Loop;
        eventname = "update";  
    }
    else if(eventname == "update")
    {
        position = (target.gameObject.GetComponent<breadcrumbs>().
            crumbs[0] as
            GameObject).transform.position;
        if(Vector3.Distance(position, this.transform.position) < 2)
        {
            target.gameObject.GetComponent<breadcrumbs>().
            RemoveBreadCrumb();
        }

        direction = target.position - transform.position;
        direction.y = 0;
        ...

    Listing 5.14 Finding the closest waypoint to set NPC back to patrol.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class patrol : MonoBehaviour {

        Graph graph = new Graph();
        int currentWP = 0;
        GameObject currentNode;
        int speed = 8;
        int rotationSpeed = 5;
        float accuracy = 1;

        string prevState = "";
        string state = "idle";
        string eventname = "enter";
        GameObject goalLocation;

        public Transform target;
        float seeRange = 10;
        float shootRange = 5;
        float keepDistance = 1;
        float heightOffset = 0.3f;

        void CreateBiPath(string a, string b)
        {
            GameObject w1 = GameObject.Find(a);
            GameObject w2 = GameObject.Find(b);

            if(w1 && w2) //if both objects exist
            {
                //create edges between the waypoints
                //in both directions
                graph.AddEdge(w1, w2);
                graph.AddEdge(w2, w1);
            }

        }

        bool CanSeeTarget ()
        {
            if (Vector3.Distance(transform.position, target.position) > seeRange)
            return false;
            return true;
        }

        bool CanShootTarget()
        {
            if(!CanSeeTarget()) return false;
            if (Vector3.Distance(transform.position, target.position) > shootRange)
            return false;
            return true;
        }

        // Use this for initialization
        void Start () {
            GameObject[] gos;
            gos = GameObject.FindGameObjectsWithTag("waypoint");
           
            foreach (GameObject go in gos)
            {
                graph.AddNode(go, true, true);
            }
           
            CreateBiPath("Sphere3","Sphere2");
            CreateBiPath("Sphere2","Sphere1");
            CreateBiPath("Sphere1","Sphere4");
            CreateBiPath("Sphere3","Sphere4");
            CreateBiPath("Sphere4","Sphere5");
            CreateBiPath("Sphere5","Sphere6");
            CreateBiPath("Sphere6","Sphere7");
            CreateBiPath("Sphere7","Sphere8");
            CreateBiPath("Sphere8","Sphere9");
            CreateBiPath("Sphere9","Sphere10");
            CreateBiPath("Sphere10","Sphere11");
            CreateBiPath("Sphere11","Sphere12");
            CreateBiPath("Sphere12","Sphere13");
            CreateBiPath("Sphere13","Sphere14");
            CreateBiPath("Sphere14","Sphere15");
            CreateBiPath("Sphere15","Sphere17");
           
            currentNode = GameObject.Find("Sphere2");
        }

        GameObject findClosestWP()
        {
            GameObject[] gos;
            gos = GameObject.FindGameObjectsWithTag("waypoint");
            GameObject closest = gos[0];
           
            foreach (GameObject go in gos)
            {
                if(Vector3.Distance(closest.transform.position, this.transform.position) >
                    Vector3.Distance(go.transform.position,this.transform.position))
                {
                    closest = go;
                }
            }
            return closest;
        }

        void FSM()
        {
            Vector3 direction;
            Vector3 position;
           
            if(state == "patrol")
            {
                if(prevState != state)
                {
                    print("patrol " + currentNode.name);
                    graph.AStar(currentNode,goalLocation);
                    graph.printPath();
                    currentWP = 0;
                   
                    this.GetComponent<Animation>().Play("run");
                    this.GetComponent<Animation>()["run"].wrapMode =
                    WrapMode.Loop;
                    eventname = "update";
                    prevState = state;
                }
                else if (eventname == "update")
                {
                    if(graph.getPathLength() == 0 || currentWP ==
                        graph.getPathLength())
                    {
                        state = "idle";
                        eventname = "enter";
                        return;
                    }

                    //the node we are closest to at this moment
                    currentNode = graph.getPathPoint(currentWP);

                    if(Vector3.Distance(graph.getPathPoint(currentWP).
                        transform.position, transform.position) < accuracy)
                    {
                        currentWP++;
                    }

                    //if we are not at the end of the path
                    if(currentWP < graph.getPathLength())
                    {
                        //keep on movin'
                        direction =
                        graph.getPathPoint(currentWP).transform.position -
                        transform.position;
                        transform.rotation = Quaternion.Slerp(transform.rotation,
                            Quaternion.LookRotation(direction),
                            rotationSpeed * Time.deltaTime);
                        transform.Translate(0, 0, Time.deltaTime * speed);
                    }

                }
                else if (eventname == "exit")
                {
                   
                }  
            }
            else if(state == "attack")
            {
                if(prevState != state)
                {
                    this.GetComponent<Animation>().CrossFade("shoot");
                    this.GetComponent<Animation>()["shoot"].wrapMode =
                    WrapMode.Loop;
                    eventname = "update";  
                }
                else if(eventname == "update")
                {
                    position = target.position;
                    direction = position - transform.position;
                    direction.y = 0;
                    // Rotate towards the target
                    transform.rotation = Quaternion.Slerp(transform.rotation,
                        Quaternion.LookRotation(direction), rotationSpeed *
                        Time.deltaTime);
                    transform.position = new Vector3(transform.position.x,
                        target.position.y + heightOffset,
                        transform.position.z);
                }
               
            }
            else if(state == "pursue")
            {
                if(prevState != state)
                {
                    this.GetComponent<Animation>().CrossFade("run");
                    this.GetComponent<Animation>()["run"].wrapMode =
                    WrapMode.Loop;
                    eventname = "update";  
                }
                else if(eventname == "update")
                {
                    position = (target.gameObject.GetComponent<breadcrumbs>().
                        crumbs[0] as GameObject).transform.position;
                    if(Vector3.Distance(position, this.transform.position) < 2)
                    {
                        target.gameObject.GetComponent<breadcrumbs>().
                        RemoveBreadCrumb();
                    }

                    direction = target.position - transform.position;
                    direction.y = 0;
                    // Rotate towards the target
                    transform.rotation = Quaternion.Slerp(transform.rotation,
                        Quaternion.LookRotation(direction),
                        rotationSpeed * Time.deltaTime);

                    // Move the character
                    if(direction.magnitude > keepDistance)
                    {
                        transform.Translate(0, 0, Time.deltaTime * speed);
                    }
                    transform.position = new Vector3(transform.position.x,
                        target.position.y + heightOffset,
                        transform.position.z);
                }
               
            }
            else if(state == "idle")
            {
                print("play idle");
                this.GetComponent<Animation>().Play("idle");
                eventname = "update";
                prevState = state; 

                if(eventname == "update")
                {
                   
                    //just remain idle 
                    if(Random.Range(0,10) < 5)
                    {
                        state = "patrol";
                        eventname = "enter";
                        currentNode = findClosestWP();
                        if(currentNode == GameObject.Find("Sphere17"))
                        goalLocation =  
                        GameObject.Find("Sphere2");
                        else
                        goalLocation = GameObject.Find("Sphere17");
                    }
                }
               
            }
        }

        // Update is called once per frame
        void Update () {
            graph.debugDraw();
            if(CanShootTarget())
            {
                prevState = state;
                state = "attack";
            }
            else if(CanSeeTarget())
            {
                prevState = state;
                state = "pursue";
            }
            else if(state != "patrol")
            {
                prevState = state;
                state = "idle";
            }

            FSM();
        }
    }


    <b>Listings 5.15 to 5.20</b>
    <code lang="csharp">
    //flock.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class flock : MonoBehaviour {

        float speed = 0.001f;
        float rotationSpeed = 5.0f;
        Vector3 averageHeading;
        Vector3 averagePosition;

        float neighbourDistance = 2.0f;

        void Start()
        {
            speed = Random.Range(0.1f,1f);
        }

        void Update ()
        {
            if(Random.Range(0,5) < 1)
            ApplyRules();
            transform.Translate(0, 0, Time.deltaTime * speed);
        }

        void ApplyRules()
        {
            GameObject[] gos;
            gos = GameObject.FindGameObjectsWithTag("Seagull");
           
            Vector3 vcentre = Vector3.zero;
            Vector3 vavoid = Vector3.zero;
            float gSpeed = 0;
           
            Vector3 wind = new Vector3(1,0,1);
            Vector3 goalPos = globalFlock.goalPos;
           
            float dist = 0;

            int groupSize = 0;
            foreach (GameObject go in gos)
            {
                if(go != this.gameObject)
                {
                    dist = Vector3.Distance(go.transform.position,
                        this.transform.position);
                    if(dist <= neighbourDistance)
                    {
                        vcentre += go.transform.position;  
                        groupSize++;   
                       
                        if(dist < 0.5f)    
                        {
                            vavoid = vavoid + (this.transform.position -
                                go.transform.position);
                        }
                       
                        gSpeed = gSpeed + go.GetComponent<flock>().speed;
                    }
                }
            }
           
            if(groupSize != 0)
            {
                vcentre = vcentre/groupSize + wind + (goalPos -
                    this.transform.position);
                speed = gSpeed/groupSize;
               
                var direction = (vcentre + vavoid) - transform.position;
                if(direction != Vector3.zero)
                transform.rotation =
                Quaternion.Slerp(transform.rotation,
                    Quaternion.LookRotation(direction),
                    rotationSpeed * Time.deltaTime);

            }
        }
    }
    //globalFlock.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class globalFlock : MonoBehaviour {

        public GameObject gull;

        static public Vector3 goalPos;

        void Start()
        {
            //create seagulls
            for(int i = 0; i < 100; i++)
            {
                Vector3 pos = new
                Vector3(Random.Range(-10,10),0,Random.Range(-10,10));
                Instantiate(gull,pos, Quaternion.identity);
            }  
           
            goalPos = new Vector3(0,0,0);
        }

        void Update ()
        {
            if(Random.Range(0,10000) < 50)
            {
                goalPos = new
                Vector3(Random.Range(-1.0f,1.0f),0,
                    Random.Range(-1.0f,1.0f));
            }
           
        }
    }

    Listing 5.21 Implementing a fuzzy logic engine in Unity
    (Includes C# code for all scripts necessary to make it work)

    //AI.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class AI : MonoBehaviour {

        public Transform target;        //the enemy
        float seeRange = 100.0f; //maximum attack distance ?
                                        //will attack if closer than
                                        //this to the enemy
                                        float shootRange = 20.0f;
        float keepDistance = 20.0f; //closest distance to get to enemy
        float safeDistance = 200.0f;
        float rotationSpeed = 5.0f;
        float sightAngle = 30f;
        float speed = 0.01f;
        string state = "PATROL";

        void Start()
        {
            Patrol();
            this.GetComponent<Animation>()["shoot"].wrapMode = WrapMode.Loop;
            this.GetComponent<Animation>()["run"].wrapMode = WrapMode.Loop;
            this.GetComponent<Animation>()["idle"].wrapMode = WrapMode.Loop;
        }

        void Update ()
        {
            this.GetComponent<fuzzyBrain>().UpdateStatus();
           
            if(this.GetComponent<fuzzyBrain>().moodValue < 20)
            {
                state = "RUNAWAY";
                GetComponent<Animation>().CrossFade("run");
                speed = 0.20f;
                RunAway();
                return;
            }
           
            if (CanSeeTarget ())
            {
                if(this.GetComponent<fuzzyBrain>().moodValue < 50)
                {
                    state = "SHOOTING";
                    GetComponent<Animation>().CrossFade("shoot");
                    speed = 0.00f;
                    Shoot();
                }
                else if (this.GetComponent<fuzzyBrain>().moodValue < 80)
                {
                    state = "PURSUE";
                    GetComponent<Animation>().CrossFade("run");
                    speed = 0.08f;
                    Pursue();
                }
            }
            else
            {
                state = "PATROL";
                if (!GetComponent<Animation>().IsPlaying("idle"))
                {
                    GetComponent<Animation>().Play ("idle");
                    speed = 0.00f;
                }  
                Patrol();
            }
           
        }

        void Patrol ()
        {
            //stand around
        }


        bool CanSeeTarget ()
        {
            var directionToTarget = target.position - transform.position;
            if (Vector3.Distance(transform.position, target.position) > seeRange)
            return false;
           
            return true;
        }

        bool CanShoot()
        {
            if (Vector3.Distance(transform.position, target.position) > shootRange)
            return false;
           
            return true;
        }


        void Pursue()
        {
            var position = target.position;
            var direction = position - transform.position;
            direction.y = 0;
           
            // Rotate towards the target
            transform.rotation = Quaternion.Slerp (transform.rotation,
                Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
           
            transform.eulerAngles = new Vector3(0,transform.eulerAngles.y, 0);

            // Move the character
            if(direction.magnitude > keepDistance)
            {
                direction = direction.normalized * speed;              
                transform.position += direction;
            }
            else
            {
                GetComponent<Animation>().Play ("idle");
                speed = 0.00f;
            }
        }

        void RunAway()
        {
            var position = target.position;
            var direction = transform.position - position;
            direction.y = 0;
           
            // Rotate away from the target
            transform.rotation = Quaternion.Slerp (transform.rotation,
                Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
            transform.eulerAngles = new Vector3(0,transform.eulerAngles.y, 0);

            // Move away the character
            if(direction.magnitude < safeDistance)
            {
                direction = direction.normalized * speed;              
                transform.position += direction;
            }
            else
            {
                GetComponent<Animation>().Play ("idle");
                speed = 0.00f;
            }
        }

        void Shoot()
        {
            var position = target.position;
            var direction = position - transform.position;
            direction.y = 0;
           
            // Rotate towards the target
            transform.rotation = Quaternion.Slerp(transform.rotation,
                Quaternion.LookRotation(direction), rotationSpeed *
                Time.deltaTime);
            transform.eulerAngles = new Vector3(0,
                transform.eulerAngles.y, 0);
        }
    }
    //fuzzyBrain.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using DotFuzzy;

    public class fuzzyBrain : MonoBehaviour {

        public float moodValue = 100;
        public GameObject explode;

        LinguisticVariable health;
        LinguisticVariable shield;
        LinguisticVariable mood;
        FuzzyEngine fuzzyEngine;

        public int botHealth = 100;
        public int botShield = 100;

        int updateTime = 2; //seconds
        int lastUpdate = 0;

        void OnCollisionEnter(Collision obj)
        {
            GameObject e = Instantiate(explode, this.transform.position,
                Quaternion.identity);
            Destroy(e.gameObject,2);
            Destroy(obj.collider.gameObject);
            botShield -= 10;
            botHealth -= (int) (10 + (100 - botShield)/5.0f);
           
            if(botHealth < 0) botHealth = 0;
            if(botShield < 0) botShield = 0;
           
            health.InputValue = botHealth;
            shield.InputValue = botShield;
           
            //set alpha color of shield relative to shield strength
            GameObject.Find("Shield").GetComponent<Renderer>().material.color =
            new Color(1,0,0,botShield/200.0f);

        }

        public void UpdateStatus()
        {
            if(botHealth == 100 && botShield == 100) return; //don't bother updating
            if(botHealth > 100) botHealth = 100;
            if(botShield > 100) botShield = 100;
           
            if(Time.fixedTime > lastUpdate + updateTime)
            {
                if(botHealth < 100)
                botHealth += 5;
                if(botShield < 100)
                botShield += 10;
               
                GameObject.Find("Shield").GetComponent<Renderer>().material.color
                = new Color(1,0,0,botShield/200.0f);
                health.InputValue = botHealth;
                shield.InputValue = botShield;
                moodValue = (float) fuzzyEngine.Defuzzify();
                lastUpdate = (int) Time.fixedTime;
            }
        }

        void Start()
        {
            health = new LinguisticVariable("Health");
            health.MembershipFunctionCollection.Add(
                new MembershipFunction("Bad", 0, 0, 20, 40));
            health.MembershipFunctionCollection.Add(
                new MembershipFunction("Moderate", 30, 50, 60, 80));
            health.MembershipFunctionCollection.Add(
                new MembershipFunction("Good", 70, 90, 100, 100));
            shield = new LinguisticVariable("Shield");
            shield.MembershipFunctionCollection.Add(
                new MembershipFunction("Low", 0, 0, 10, 50));
            shield.MembershipFunctionCollection.Add(
                new MembershipFunction("Medium", 20, 50, 60, 80));
            shield.MembershipFunctionCollection.Add(
                new MembershipFunction("High", 40, 80, 100, 100));
            mood = new LinguisticVariable("Mood");
            mood.MembershipFunctionCollection.Add(
                new MembershipFunction("Angry", 0, 0, 20, 40));
            mood.MembershipFunctionCollection.Add(
                new MembershipFunction("Indifferent", 30, 50,
                    50, 80));
            mood.MembershipFunctionCollection.Add(
                new MembershipFunction("Happy", 60, 90, 100, 100));
            fuzzyEngine = new FuzzyEngine();
            fuzzyEngine.LinguisticVariableCollection.Add(health);
            fuzzyEngine.LinguisticVariableCollection.Add(shield);
            fuzzyEngine.LinguisticVariableCollection.Add(mood);
            fuzzyEngine.Consequent = "Mood";
            fuzzyEngine.FuzzyRuleCollection.Add(new FuzzyRule(
                "IF (Health IS Good) AND (Shield IS High) THEN Mood IS Happy"));
            fuzzyEngine.FuzzyRuleCollection.Add(new FuzzyRule(
                "IF (Health IS Bad) OR (Shield IS Low) THEN Mood IS Angry"));
            fuzzyEngine.FuzzyRuleCollection.Add(new FuzzyRule(
                "IF (Health IS Moderate) AND (Shield IS High) THEN Mood IS Indifferent"));
            fuzzyEngine.FuzzyRuleCollection.Add(new FuzzyRule(
                "IF (Health IS Moderate) OR (Shield IS Medium) THEN Mood IS Indifferent"));
            fuzzyEngine.FuzzyRuleCollection.Add(new FuzzyRule(
                "IF (Health IS Bad) AND (Shield IS High) THEN Mood IS Indifferent"));
        }
    }
    //Ginterface.cs (renamed from interface.js)
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class ginterface : MonoBehaviour {

        public GUIStyle myStyle;

        void OnGUI()
        {
            GUI.Label(new Rect(10,10,800,50),"Health " +
                this.GetComponent<fuzzyBrain>().botHealth
                + " Shield " + this.GetComponent<fuzzyBrain>().botShield,
                myStyle);
        }

        void Update () {
    }
    }

    Chapter 6

    Listing 6.1 Script to switch to another scene.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;

    public class menuController : MonoBehaviour {

        public void GoToGame()
        {
            SceneManager.LoadScene("game");
        }
    }

    Section 6.4

    Listing 6.11 Using a trigger event to teleport to another scene.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;

    public class teleport : MonoBehaviour {

        void OnTriggerEnter (Collider obj)
        {
            if(obj.gameObject.tag == "toSewer")
            {
                SceneManager.LoadScene("sewerScene");
            }
        }
    }

    Listing 6.12 Script to reposition a colliding game object at the position of another game object.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class teleportTo : MonoBehaviour {

        public GameObject to;

        void OnTriggerEnter(Collider obj)
        {
            obj.gameObject.transform.position = to.transform.position +
            obj.gameObject.transform.forward*3;

        }
    }

    Chapter 7

    Listing 7.1 Script to create random height values on a mesh.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class makeTerrain : MonoBehaviour {

        void Start()
        {
            Mesh mesh = this.GetComponent<MeshFilter>().mesh;
            Vector3[] vertices = mesh.vertices;
            for (int v = 0; v < vertices.Length; v++)
            {
                vertices[v].y = Random.Range(0f,10f);
            }
            mesh.vertices = vertices;
            mesh.RecalculateBounds();
            mesh.RecalculateNormals();
            this.gameObject.AddComponent<MeshCollider>();
        }
    }

    Listing 7.2 Using a sine function to set the terrain height.
    Changes to code are the same.

    Listing 7.3 Using Perlin Noise to generate terrain heights.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class makeTerrain : MonoBehaviour {

        void Start()
        {
            Perlin surface = new Perlin();
            Mesh mesh = this.GetComponent<MeshFilter>().mesh;
            Vector3[] vertices = mesh.vertices;
            for (int v = 0; v < vertices.Length; v++)
            {
                vertices[v].y = surface.Noise(
                    vertices[v].x * 2 + 0.1365143f,
                    vertices[v].z * 2 + 1.21688f) * 10;
            }
            mesh.vertices = vertices;
            mesh.RecalculateBounds();
            mesh.RecalculateNormals();
            this.gameObject.AddComponent<MeshCollider>();
        }
    }

    Listing 7.4 Using building prefabs to create a city based on Perlin Noise height values.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class makeCity : MonoBehaviour {

        public GameObject[] buildings;

        void Start()
        {
            Perlin surface = new Perlin();
           
            Mesh mesh = this.GetComponent<MeshFilter>().mesh;
            Vector3[] vertices = mesh.vertices;
            float scalex = this.transform.localScale.x;
            float scalez = this.transform.localScale.z;
           
            for (int v = 0; v < vertices.Length; v++)
            {
                float perlinValue = surface.Noise(vertices[v].x * 2 + 0.1365143f,
                    vertices[v].z * 2 + 1.21688f) * 10;
               
                perlinValue =
                Mathf.Round((Mathf.Clamp(perlinValue,0,buildings.Length)));
                Instantiate(buildings[(int)perlinValue],
                    new Vector3(vertices[v].x * scalex,
                        vertices[v].y, vertices[v].z * scalez),
                    buildings[(int)perlinValue].transform.rotation);   

            }
           
            mesh.vertices = vertices;
            mesh.RecalculateBounds();
            mesh.RecalculateNormals();
           
            this.gameObject.AddComponent<MeshCollider>();
        }
    }

    Listing 7.5 Set the Sun’s light type to directional.

    void Start ()
    {
        sunLight = new GameObject("Sun");
        sunLight.AddComponent<Light>();
        sunLight.GetComponent<Light>().type = LightType.Directional;
    }

    Chapter 8

    Listing 8.1 Unity C# to report on mobile device acceleration.

    Input.acceleration.x
    Input.acceleration.y
    Input.acceleration.z

    Listing 8.2 Unity C# to report on device orientation.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class orient : MonoBehaviour {

        string orientString = "Unknown";
        Vector2 pivotPoint = new Vector2(200,200);
        float rotAngle = 0;
        void OnGUI()
        {
            if (Input.deviceOrientation == DeviceOrientation.FaceDown)
            {
                orientString = "Face Down";
                rotAngle = 0;
            }
            if (Input.deviceOrientation == DeviceOrientation.FaceUp)
            {
                orientString = "Face Up";
                rotAngle = 0;
            }
            if (Input.deviceOrientation == DeviceOrientation.Portrait)
            {
                orientString = "Portrait";
                rotAngle = 0;
            }
            if (Input.deviceOrientation == DeviceOrientation.PortraitUpsideDown)
            {
                orientString = "Portrait Upside Down";
                rotAngle = 180;
            }
            if (Input.deviceOrientation == DeviceOrientation.LandscapeLeft)
            {
                orientString = "Landscape Left";
                rotAngle = 90;
            }
            if (Input.deviceOrientation == DeviceOrientation.LandscapeRight)
            {
                orientString = "Landscape Right";
                rotAngle = -90;
            }
            GUI.BeginGroup (new Rect (Screen.width / 2 - 200,
                Screen.height / 2 - 200, 400, 400));
            GUIUtility.RotateAroundPivot (rotAngle, pivotPoint);
            GUI.Label (new Rect (0, 0, 400, 400), orientString);
            GUI.EndGroup ();
        }
    }

    Listing 8.3 Sending a simple email message from Unity application.
    Code is the same but change “function” for “void”

    Listing 8.4 Prepopulation email data in a Unity application before sending.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class sendEmail : MonoBehaviour {

        string toEmail = "test@email.com";
        string nameField = "My Name";
        string messageField = "Message";
        void OnGUI()
        {
            GUI.Label(new Rect(10,10,50,50),"To");
            toEmail = GUI.TextField (new Rect (100, 10, 200, 50), toEmail);
            GUI.Label(new Rect(10,60,50,50),"Name");
            nameField = GUI.TextField (new Rect (100, 60, 200, 50),
                nameField);
            GUI.Label(new Rect(10,120,120,50),"Message");
            messageField = GUI.TextArea(new Rect(100, 120, 200, 200),
                messageField);
            if(GUI.Button(new Rect(50,350,180,50),"Send"))
            {
                Application.OpenURL("mailto:" + toEmail + "?" +
                    "subject=Test Email&" +
                    "body=From: " +
                    nameField + "\n" + messageField);
            }
        }
    }

    Listing 8.5 Sending data from a Unity app to a webserver for the purpose of emailing.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class emailer : MonoBehaviour {

        string toEmail = "test@email.com";
        string nameField = "My Name";
        string messageField = "Message";
        bool showWebMessage = false;
        int emailSuccessful = 1;

        void webMessageScreen()
        {
            GUI.BeginGroup (new Rect (Screen.width / 2 - 50,
                Screen.height / 2 - 50, 100, 100));
            GUI.Box (new Rect (0,0,100,100), "Email Message");
            if(emailSuccessful == 1)
            GUI.Label(new Rect(10,20,100,50),"Sending...");
            if(emailSuccessful == 2)
            GUI.Label(new Rect(10,20,100,50),"Email Sent");
            else if(emailSuccessful == 3)
            GUI.Label(new Rect(10,20,100,50),"Email Failed");
            if (GUI.Button (new Rect (10,50,80,30), "Ok"))
            {
                showWebMessage = false;
            }
            GUI.EndGroup ();
        }

        IEnumerator sendEmail()
        {
            emailSuccessful = 1;
            showWebMessage = true;
            string msgBody = "From: " + nameField + "\n" + messageField;
            WWWForm form = new WWWForm();
            form.AddField("to", toEmail);
            form.AddField("subject", "Email Subject");
            form.AddField("body", msgBody);
            WWW w = new WWW("URL OF YOUR PHP SCRIPT", form);
            yield return w;
            if (w.error != null)
            {
                emailSuccessful = 3;
            }
            else
            {
                emailSuccessful = 2;
            }
        }

        void OnGUI()
        {
            GUI.Label(new Rect(10,10,50,50),"To");
            toEmail = GUI.TextField (new Rect (100, 10, 200, 50), toEmail);
            GUI.Label(new Rect(10,60,50,50),"Name");
            nameField = GUI.TextField (new Rect (100, 60, 200, 50), nameField);
            GUI.Label(new Rect(10,120,120,50),"Message");

            messageField = GUI.TextArea (new Rect (100, 120, 200, 200),
                messageField);
            if(GUI.Button(new Rect(50,350,180,50),"Send"))
            {
                StartCoroutine(sendEmail());
            }
            if(showWebMessage)
            {
                webMessageScreen();
            }
        }
    }

    Listing 8.6 PHP web emailer.
    Code unchanged

    Listing 8.7 Code to Obtain GPS Information

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class gps : MonoBehaviour {

        bool locationFound = false;

        IEnumerator GetLocation()
        {
            Input.location.Start();
            int maxWait = 1;
            while (Input.location.status == LocationServiceStatus.Initializing &&
                maxWait > 0)
            {
                yield return new WaitForSeconds(1);
                maxWait--;
            }
            if (maxWait < 1)
            {
                yield return null;
            }
            if (Input.location.status == LocationServiceStatus.Failed)
            {
                yield return null;
            }
            else
            {
                locationFound = true;
            }
            Input.location.Stop();
        }

        void Start ()
        {
            StartCoroutine(GetLocation());
        }

        void OnGUI()
        {
            if(locationFound)
            {
                GUI.Label(new Rect(10,10,200,30),"Latitude: " +
                    Input.location.lastData.latitude);
                GUI.Label(new Rect(10,30,200,30),"Longitude: " +
                    Input.location.lastData.longitude);
                GUI.Label(new Rect(10,50,200,30),"Altitude: " +
                    Input.location.lastData.altitude);
                GUI.Label(new Rect(10,70,200,30),"Accuracy: " +
                    Input.location.lastData.horizontalAccuracy);
                GUI.Label(new Rect(10,90,200,30),"Time: " +
                    Input.location.lastData.timestamp);
            }
            else
            {
                GUI.Label(new Rect(10,10,200,30),
                    "Could not initialise location services.");
            }
            if(GUI.Button(new Rect(10,110,80,50),"Quit"))
            {
                Application.Quit();
            }
        }
    }

    Listing 8.8 Detect.
    Includes all C# files for exercise

    //swipeTrail.cs
    using UnityEngine;
    using System.Collections;

    public class swipeTrail : MonoBehaviour {

        void Update () {
            if(((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
                || Input.GetMouseButton(0)))
            {
                Vector3 touchPos = Camera.main.ScreenToWorldPoint(new
                    Vector3(Input.mousePosition.x,
                        Input.mousePosition.y, Camera.main.farClipPlane));
                this.transform.position = new Vector3(touchPos.x,touchPos.y,0);
            }
        }
    }
    //detectMotion.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;

    public class detectMotion : MonoBehaviour {

        bool isDown = false;
        bool startPointRecording = false;
        Vector2 lastMousePos = new Vector2(-1,-1);
        ArrayList points = new ArrayList();
        string patternDetected = "";
        Text patternDisplay;

        void OnGUI()
        {
            if(isDown && Input.mousePosition.x != lastMousePos.x &&
                Input.mousePosition.y != lastMousePos.x)
            {
                points.Add(new Vector2(Input.mousePosition.x, -Input.mousePosition.y));
                lastMousePos = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
            }
        }


        void Update ()
        {
            if(Input.GetMouseButtonDown(0))
            {
                isDown = true;
                startPointRecording = true;
                points = new ArrayList();
            }
            else if(Input.GetMouseButtonUp(0))
            {
                isDown = false;
                startPointRecording = false;
                Result result = this.GetComponent<gestureRecon>().Detect(points);
                patternDetected = result.Rname + " " + result.Rscore;
                patternDisplay.text = patternDetected;
            }
        }
    }
    //gestureRecon.cs
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class Point
    {
        public float X = 0;
        public float Y = 0;
        public Point(float x, float y)
        {
            this.X = x;
            this.Y = y;
        }
    }

    class Rectangle
    {
        public float X = 0;
        public float Y = 0;
        public float Width = 0;
        public float Height = 0;
        public Rectangle(float x, float y, float width, float height)
        {
            this.X = x;
            this.Y = y;
            this.Width = width;
            this.Height = height;
        }
    }

    public class Result
    {
        public string Rname;
        public float Rscore;
        public Result(string n, float s)
        {
            Rname = n;
            Rscore = s;
        }
    }


    public class gestureRecon {

        string Rname;
        float Rscore;
        ArrayList Templates;



        class Template
        {
            public string Tname;
            public static float TScore;
            public int NumTemplates = 16;
            public static int NumPoints = 64;
            public static float SquareSize = 250.0f;
            public static Point Origin = new Point(0,0);
            public static float Diagonal = Mathf.Sqrt(SquareSize * SquareSize + SquareSize * SquareSize);
            public static float HalfDiagonal = 0.5f * Diagonal;
            public static float AngleRange = Deg2Rad(45.0f);
            public static float AnglePrecision = Deg2Rad(2.0f);
            public static float Phi = 0.5f * (-1.0f + Mathf.Sqrt(5.0f));
            public ArrayList points = new ArrayList();

            public Template(string name, ArrayList points)
            {
                this.Tname = name;
                this.points = Resample(points, NumPoints);
                var radians = IndicativeAngle(this.points);
                this.points = RotateBy(this.points, -radians);
                this.points = ScaleTo(this.points, SquareSize);
                this.points = TranslateTo(this.points, Origin);

            }

            static public ArrayList Resample(ArrayList points, int n)
            {
                float I = PathCount(points) / (n - 1);
                float D = 0.0f;
                ArrayList newpoints = new ArrayList();
                for (int i = 1; i < points.Count; i++)
                {
                    Point point1 = points[i-1] as Point;
                    Point point2 = points[i] as Point;
                    float d = Distance(point1, point2);
                    if ((D + d) >= I)
                    {
                        float qx = point1.X + ((I - D) / d) * (point2.X - point1.X);
                        float qy = point1.Y + ((I - D) / d) * (point2.Y - point1.Y);
                        Point q = new Point(qx, qy);
                        newpoints[newpoints.Count] = q;
                        points.Insert(i,q);
                        D = 0.0f;
                    }
                    else D += d;
                }

                if (newpoints.Count == n - 1)
                {
                    Point p = points[points.Count - 1] as Point;
                    newpoints[newpoints.Count] = new Point(p.X, p.Y);
                }
                return newpoints;
            }

            static public ArrayList ScaleTo(ArrayList points, float size)
            {
                Rectangle B = BoundingBox(points);
                ArrayList newpoints = new ArrayList();
                Point p;
                for (int i = 0; i < points.Count; i++)
                {
                    p = points[i] as Point;
                    float qx = p.X * (size / B.Width);
                    float qy = p.Y * (size / B.Height);
                    newpoints[newpoints.Count] = new Point(qx, qy);
                }
                return newpoints;
            }

            static public ArrayList TranslateTo(ArrayList points, Point pt)
            {
                Point c = Centroid(points);
                ArrayList newpoints = new ArrayList();
                Point p;
                for (int i = 0; i < points.Count; i++)
                {
                    p = points[i] as Point;
                    float qx = p.X + pt.X - c.X;
                    float qy = p.Y + pt.Y - c.Y;
                    newpoints[newpoints.Count] = new Point(qx, qy);
                }
                return newpoints;
            }  

            static public Rectangle BoundingBox(ArrayList points)
            {
                float minX = 20000;
                float maxX = -1;
                float minY = 20000;
                float maxY = -1;
                Point p;
                for (int i = 0; i < points.Count; i++)
                {
                    p = points[i] as Point;
                    if (p.X < minX)
                    minX = p.X;
                    if (p.X > maxX)
                    maxX = p.X;
                    if (p.Y < minY)
                    minY = p.Y;
                    if (p.Y > maxY)
                    maxY = p.Y;
                }
                return new Rectangle(minX, minY, maxX - minX, maxY - minY);
            }

            static public ArrayList RotateBy(ArrayList points, float radians)
            {
                Point c = Centroid(points);
                float cos = (float) Mathf.Cos(radians);
                float sin = (float) Mathf.Sin(radians);

                ArrayList newpoints = new ArrayList();
                Point p;
                for (int i = 0; i < points.Count; i++)
                {
                    p = points[i] as Point;
                    float qx = (p.X - c.X) * cos - (p.Y - c.Y) * sin + c.X;
                    float qy = (p.X - c.X) * sin + (p.Y - c.Y) * cos + c.Y;
                    newpoints[newpoints.Count] = new Point(qx, qy);
                }
                return newpoints;
            }


            static public Point Centroid(ArrayList points)
            {
                float x = 0.0f;
                float y = 0.0f;
                Point p;
                for (int i = 0; i < points.Count; i++)
                {
                    p = points[i] as Point;
                    x += p.X;
                    y += p.Y;
                }
                x /= points.Count;
                y /= points.Count;
                return new Point(x, y);
            }

            static public float IndicativeAngle(ArrayList points)
            {
                Point c = Centroid(points);
                Point p = points[0] as Point;
                return (float) Mathf.Atan2(c.Y - p.Y, c.X - p.X);
            }  

            static public float PathCount(ArrayList points)
            {
                float d = 0.0f;
                for (int i = 1; i < points.Count; i++)
                d += Distance(points[i - 1] as Point, points[i] as Point);
                return d;
            }  

            static public float Distance(Point p1, Point p2)
            {
                var dx = p2.X - p1.X;
                var dy = p2.Y - p1.Y;
                return (float) Mathf.Sqrt(dx * dx + dy * dy);
            }

            static public float Deg2Rad(float d) { return (float)(d * Mathf.PI / 180.0); }
            static public float Rad2Deg(float r) { return (float)(r * 180.0 / Mathf.PI); }

        }


        float PathDistance(ArrayList pts1, ArrayList pts2)
        {
            float d = 0.0f;
           
            for (int i = 0; i < pts1.Count; i++)
            {
                if(i < pts2.Count) //ensure pattern has enough points to compare
                {
                    d += Template.Distance(pts1[i] as Point, pts2[i] as Point);
                }
            }
            return d / pts1.Count;
        }

        float DistanceAtAngle(ArrayList points, Template T, float radians)
        {
            var newpoints = Template.RotateBy(points, radians);
            return PathDistance(newpoints, T.points);
        }

        float DistanceAtBestAngle(ArrayList points, Template T, float a, float b, float threshold)
        {      
            float x1 = (float)(Template.Phi * a + (1.0 - Template.Phi) * b);       
            float f1 = (float)(DistanceAtAngle(points, T, x1));
            float x2 = (float)((1.0 - Template.Phi) * a + Template.Phi * b);
            float f2 = (float)(DistanceAtAngle(points, T, x2));
            while (Mathf.Abs(b - a) > threshold)
            {
                if (f1 < f2)
                {
                    b = x2;
                    x2 = x1;
                    f2 = f1;
                    x1 = (float)(Template.Phi * a + (1.0 - Template.Phi) * b);
                    f1 = (float)(DistanceAtAngle(points, T, x1));
                }
                else
                {
                    a = x1;
                    x1 = x2;
                    f1 = f2;
                    x2 = (float)((1.0 - Template.Phi) * a + Template.Phi * b);
                    f2 = (float)(DistanceAtAngle(points, T, x2));
                }
            }
            return (float) Mathf.Min(f1, f2);
        }

        public Result Detect(ArrayList points)
        {
            points = Template.Resample(points, Template.NumPoints);
            float radians = Template.IndicativeAngle(points);
            points = Template.RotateBy(points, -radians);
            points = Template.ScaleTo(points, Template.SquareSize);
            points = Template.TranslateTo(points, Template.Origin);

            float b = 20000;
            int t = 0;
            for (int i = 0; i < this.Templates.Count; i++)
            {
                float d = DistanceAtBestAngle(points, this.Templates[i] as Template, (float)-Template.AngleRange, (float)Template.AngleRange, (float)Template.AnglePrecision);
                if (d < b)
                {
                    b = d;
                    t = i;
                   
                    Template tpl = this.Templates[t] as Template;
                    Debug.Log("Results " + tpl.Tname + " " + (b / Template.HalfDiagonal));
                }
            }
            float score = (float)(1.0 - (b / Template.HalfDiagonal));
            Template tp = this.Templates[t] as Template;
            return new Result(tp.Tname, score);
        }

        void Start()
        {
            Debug.Log("Loading Patterns");
            this.Templates = new ArrayList();

            this.Templates[0] = new Template("triangle", new ArrayList(new Point[]{new Point(137,139), new Point(135,141), new Point(133,144), new Point(132,146), new Point(130,149), new Point(128,151), new Point(126,155), new Point(123,160), new Point(120,166), new Point(116,171), new Point(112,177), new Point(107,183), new Point(102,188), new Point(100,191), new Point(95,195), new Point(90,199), new Point(86,203), new Point(82,206), new Point(80,209), new Point(75,213), new Point(73,213), new Point(70,216), new Point(67,219), new Point(64,221), new Point(61,223), new Point(60,225), new Point(62,226), new Point(65,225), new Point(67,226), new Point(74,226), new Point(77,227), new Point(85,229), new Point(91,230), new Point(99,231), new Point(108,232), new Point(116,233), new Point(125,233), new Point(134,234), new Point(145,233), new Point(153,232), new Point(160,233), new Point(170,234), new Point(177,235), new Point(179,236), new Point(186,237), new Point(193,238), new Point(198,239), new Point(200,237), new Point(202,239), new Point(204,238), new Point(206,234), new Point(205,230), new Point(202,222), new Point(197,216), new Point(192,207), new Point(186,198), new Point(179,189), new Point(174,183), new Point(170,178), new Point(164,171), new Point(161,168), new Point(154,160), new Point(148,155), new Point(143,150), new Point(138,148), new Point(136,148)}));
            Debug.Log("Loading 0 " + (this.Templates[0] as Template).points.Count.ToString());

            this.Templates[1] = new Template("x", new ArrayList(new Point[]{new Point(87,142), new Point(89,145), new Point(91,148), new Point(93,151), new Point(96,155), new Point(98,157), new Point(100,160), new Point(102,162), new Point(106,167), new Point(108,169), new Point(110,171), new Point(115,177), new Point(119,183), new Point(123,189), new Point(127,193), new Point(129,196), new Point(133,200), new Point(137,206), new Point(140,209), new Point(143,212), new Point(146,215), new Point(151,220), new Point(153,222), new Point(155,223), new Point(157,225), new Point(158,223), new Point(157,218), new Point(155,211), new Point(154,208), new Point(152,200), new Point(150,189), new Point(148,179), new Point(147,170), new Point(147,158), new Point(147,148), new Point(147,141), new Point(147,136), new Point(144,135), new Point(142,137), new Point(140,139), new Point(135,145), new Point(131,152), new Point(124,163), new Point(116,177), new Point(108,191), new Point(100,206), new Point(94,217), new Point(91,222), new Point(89,225), new Point(87,226), new Point(87,224)}));
            Debug.Log("Loading 1 " + (this.Templates[1] as Template).points.Count.ToString()); 

            this.Templates[2] = new Template("rectangle", new ArrayList(new Point[]{new Point(78,149), new Point(78,153), new Point(78,157), new Point(78,160), new Point(79,162), new Point(79,164), new Point(79,167), new Point(79,169), new Point(79,173), new Point(79,178), new Point(79,183), new Point(80,189), new Point(80,193), new Point(80,198), new Point(80,202), new Point(81,208), new Point(81,210), new Point(81,216), new Point(82,222), new Point(82,224), new Point(82,227), new Point(83,229), new Point(83,231), new Point(85,230), new Point(88,232), new Point(90,233), new Point(92,232), new Point(94,233), new Point(99,232), new Point(102,233), new Point(106,233), new Point(109,234), new Point(117,235), new Point(123,236), new Point(126,236), new Point(135,237), new Point(142,238), new Point(145,238), new Point(152,238), new Point(154,239), new Point(165,238), new Point(174,237), new Point(179,236), new Point(186,235), new Point(191,235), new Point(195,233), new Point(197,233), new Point(200,233), new Point(201,235), new Point(201,233), new Point(199,231), new Point(198,226), new Point(198,220), new Point(196,207), new Point(195,195), new Point(195,181), new Point(195,173), new Point(195,163), new Point(194,155), new Point(192,145), new Point(192,143), new Point(192,138), new Point(191,135), new Point(191,133), new Point(191,130), new Point(190,128), new Point(188,129), new Point(186,129), new Point(181,132), new Point(173,131), new Point(162,131), new Point(151,132), new Point(149,132), new Point(138,132), new Point(136,132), new Point(122,131), new Point(120,131), new Point(109,130), new Point(107,130), new Point(90,132), new Point(81,133), new Point(76,133)}));
            Debug.Log("Loading 2 " + (this.Templates[2] as Template).points.Count.ToString());

            this.Templates[3] = new Template("circle", new ArrayList(new Point[]{new Point(127,141), new Point(124,140), new Point(120,139), new Point(118,139), new Point(116,139), new Point(111,140), new Point(109,141), new Point(104,144), new Point(100,147), new Point(96,152), new Point(93,157), new Point(90,163), new Point(87,169), new Point(85,175), new Point(83,181), new Point(82,190), new Point(82,195), new Point(83,200), new Point(84,205), new Point(88,213), new Point(91,216), new Point(96,219), new Point(103,222), new Point(108,224), new Point(111,224), new Point(120,224), new Point(133,223), new Point(142,222), new Point(152,218), new Point(160,214), new Point(167,210), new Point(173,204), new Point(178,198), new Point(179,196), new Point(182,188), new Point(182,177), new Point(178,167), new Point(170,150), new Point(163,138), new Point(152,130), new Point(143,129), new Point(140,131), new Point(129,136), new Point(126,139)}));
            Debug.Log("Loading 3 " + (this.Templates[3] as Template).points.Count.ToString());

            this.Templates[4] = new Template("check", new ArrayList(new Point[]{new Point(91,185), new Point(93,185), new Point(95,185), new Point(97,185), new Point(100,188), new Point(102,189), new Point(104,190), new Point(106,193), new Point(108,195), new Point(110,198), new Point(112,201), new Point(114,204), new Point(115,207), new Point(117,210), new Point(118,212), new Point(120,214), new Point(121,217), new Point(122,219), new Point(123,222), new Point(124,224), new Point(126,226), new Point(127,229), new Point(129,231), new Point(130,233), new Point(129,231), new Point(129,228), new Point(129,226), new Point(129,224), new Point(129,221), new Point(129,218), new Point(129,212), new Point(129,208), new Point(130,198), new Point(132,189), new Point(134,182), new Point(137,173), new Point(143,164), new Point(147,157), new Point(151,151), new Point(155,144), new Point(161,137), new Point(165,131), new Point(171,122), new Point(174,118), new Point(176,114), new Point(177,112), new Point(177,114), new Point(175,116), new Point(173,118)}));
            Debug.Log("Loading 4 " + (this.Templates[4] as Template).points.Count.ToString());

            this.Templates[5] = new Template("caret", new ArrayList(new Point[]{new Point(79,245), new Point(79,242), new Point(79,239), new Point(80,237), new Point(80,234), new Point(81,232), new Point(82,230), new Point(84,224), new Point(86,220), new Point(86,218), new Point(87,216), new Point(88,213), new Point(90,207), new Point(91,202), new Point(92,200), new Point(93,194), new Point(94,192), new Point(96,189), new Point(97,186), new Point(100,179), new Point(102,173), new Point(105,165), new Point(107,160), new Point(109,158), new Point(112,151), new Point(115,144), new Point(117,139), new Point(119,136), new Point(119,134), new Point(120,132), new Point(121,129), new Point(122,127), new Point(124,125), new Point(126,124), new Point(129,125), new Point(131,127), new Point(132,130), new Point(136,139), new Point(141,154), new Point(145,166), new Point(151,182), new Point(156,193), new Point(157,196), new Point(161,209), new Point(162,211), new Point(167,223), new Point(169,229), new Point(170,231), new Point(173,237), new Point(176,242), new Point(177,244), new Point(179,250), new Point(181,255), new Point(182,257)}));
            Debug.Log("Loading 5 " + (this.Templates[5] as Template).points.Count.ToString());

            this.Templates[6] = new Template("zig-zag", new ArrayList(new Point[]{new Point(307,216), new Point(333,186), new Point(356,215), new Point(375,186), new Point(399,216), new Point(418,186)}));
            Debug.Log("Loading 6 " + (this.Templates[6] as Template).points.Count.ToString());

            this.Templates[7] = new Template("arrow", new ArrayList(new Point[]{new Point(68,222), new Point(70,220), new Point(73,218), new Point(75,217), new Point(77,215), new Point(80,213), new Point(82,212), new Point(84,210), new Point(87,209), new Point(89,208), new Point(92,206), new Point(95,204), new Point(101,201), new Point(106,198), new Point(112,194), new Point(118,191), new Point(124,187), new Point(127,186), new Point(132,183), new Point(138,181), new Point(141,180), new Point(146,178), new Point(154,173), new Point(159,171), new Point(161,170), new Point(166,167), new Point(168,167), new Point(171,166), new Point(174,164), new Point(177,162), new Point(180,160), new Point(182,158), new Point(183,156), new Point(181,154), new Point(178,153), new Point(171,153), new Point(164,153), new Point(160,153), new Point(150,154), new Point(147,155), new Point(141,157), new Point(137,158), new Point(135,158), new Point(137,158), new Point(140,157), new Point(143,156), new Point(151,154), new Point(160,152), new Point(170,149), new Point(179,147), new Point(185,145), new Point(192,144), new Point(196,144), new Point(198,144), new Point(200,144), new Point(201,147), new Point(199,149), new Point(194,157), new Point(191,160), new Point(186,167), new Point(180,176), new Point(177,179), new Point(171,187), new Point(169,189), new Point(165,194), new Point(164,196)}));
            Debug.Log("Loading 7 " + (this.Templates[7] as Template).points.Count.ToString());

            this.Templates[8] = new Template("left square bracket", new ArrayList(new Point[]{new Point(140,124), new Point(138,123), new Point(135,122), new Point(133,123), new Point(130,123), new Point(128,124), new Point(125,125), new Point(122,124), new Point(120,124), new Point(118,124), new Point(116,125), new Point(113,125), new Point(111,125), new Point(108,124), new Point(106,125), new Point(104,125), new Point(102,124), new Point(100,123), new Point(98,123), new Point(95,124), new Point(93,123), new Point(90,124), new Point(88,124), new Point(85,125), new Point(83,126), new Point(81,127), new Point(81,129), new Point(82,131), new Point(82,134), new Point(83,138), new Point(84,141), new Point(84,144), new Point(85,148), new Point(85,151), new Point(86,156), new Point(86,160), new Point(86,164), new Point(86,168), new Point(87,171), new Point(87,175), new Point(87,179), new Point(87,182), new Point(87,186), new Point(88,188), new Point(88,195), new Point(88,198), new Point(88,201), new Point(88,207), new Point(89,211), new Point(89,213), new Point(89,217), new Point(89,222), new Point(88,225), new Point(88,229), new Point(88,231), new Point(88,233), new Point(88,235), new Point(89,237), new Point(89,240), new Point(89,242), new Point(91,241), new Point(94,241), new Point(96,240), new Point(98,239), new Point(105,240), new Point(109,240), new Point(113,239), new Point(116,240), new Point(121,239), new Point(130,240), new Point(136,237), new Point(139,237), new Point(144,238), new Point(151,237), new Point(157,236), new Point(159,237)}));
            Debug.Log("Loading 8 " + (this.Templates[8] as Template).points.Count.ToString());

            this.Templates[9] = new Template("right square bracket", new ArrayList(new Point[]{new Point(112,138), new Point(112,136), new Point(115,136), new Point(118,137), new Point(120,136), new Point(123,136), new Point(125,136), new Point(128,136), new Point(131,136), new Point(134,135), new Point(137,135), new Point(140,134), new Point(143,133), new Point(145,132), new Point(147,132), new Point(149,132), new Point(152,132), new Point(153,134), new Point(154,137), new Point(155,141), new Point(156,144), new Point(157,152), new Point(158,161), new Point(160,170), new Point(162,182), new Point(164,192), new Point(166,200), new Point(167,209), new Point(168,214), new Point(168,216), new Point(169,221), new Point(169,223), new Point(169,228), new Point(169,231), new Point(166,233), new Point(164,234), new Point(161,235), new Point(155,236), new Point(147,235), new Point(140,233), new Point(131,233), new Point(124,233), new Point(117,235), new Point(114,238), new Point(112,238)}));
            Debug.Log("Loading 9 " + (this.Templates[9] as Template).points.Count.ToString());     

            this.Templates[10] = new Template("v", new ArrayList(new Point[]{new Point(89,164), new Point(90,162), new Point(92,162), new Point(94,164), new Point(95,166), new Point(96,169), new Point(97,171), new Point(99,175), new Point(101,178), new Point(103,182), new Point(106,189), new Point(108,194), new Point(111,199), new Point(114,204), new Point(117,209), new Point(119,214), new Point(122,218), new Point(124,222), new Point(126,225), new Point(128,228), new Point(130,229), new Point(133,233), new Point(134,236), new Point(136,239), new Point(138,240), new Point(139,242), new Point(140,244), new Point(142,242), new Point(142,240), new Point(142,237), new Point(143,235), new Point(143,233), new Point(145,229), new Point(146,226), new Point(148,217), new Point(149,208), new Point(149,205), new Point(151,196), new Point(151,193), new Point(153,182), new Point(155,172), new Point(157,165), new Point(159,160), new Point(162,155), new Point(164,150), new Point(165,148), new Point(166,146)}));
            Debug.Log("Loading 10 " + (this.Templates[10] as Template).points.Count.ToString());       

            this.Templates[11] = new Template("delete", new ArrayList(new Point[]{new Point(123,129), new Point(123,131), new Point(124,133), new Point(125,136), new Point(127,140), new Point(129,142), new Point(133,148), new Point(137,154), new Point(143,158), new Point(145,161), new Point(148,164), new Point(153,170), new Point(158,176), new Point(160,178), new Point(164,183), new Point(168,188), new Point(171,191), new Point(175,196), new Point(178,200), new Point(180,202), new Point(181,205), new Point(184,208), new Point(186,210), new Point(187,213), new Point(188,215), new Point(186,212), new Point(183,211), new Point(177,208), new Point(169,206), new Point(162,205), new Point(154,207), new Point(145,209), new Point(137,210), new Point(129,214), new Point(122,217), new Point(118,218), new Point(111,221), new Point(109,222), new Point(110,219), new Point(112,217), new Point(118,209), new Point(120,207), new Point(128,196), new Point(135,187), new Point(138,183), new Point(148,167), new Point(157,153), new Point(163,145), new Point(165,142), new Point(172,133), new Point(177,127), new Point(179,127), new Point(180,125)}));
            Debug.Log("Loading 11 " + (this.Templates[11] as Template).points.Count.ToString());       

            this.Templates[12] = new Template("left curly brace", new ArrayList(new Point[]{new Point(150,116), new Point(147,117), new Point(145,116), new Point(142,116), new Point(139,117), new Point(136,117), new Point(133,118), new Point(129,121), new Point(126,122), new Point(123,123), new Point(120,125), new Point(118,127), new Point(115,128), new Point(113,129), new Point(112,131), new Point(113,134), new Point(115,134), new Point(117,135), new Point(120,135), new Point(123,137), new Point(126,138), new Point(129,140), new Point(135,143), new Point(137,144), new Point(139,147), new Point(141,149), new Point(140,152), new Point(139,155), new Point(134,159), new Point(131,161), new Point(124,166), new Point(121,166), new Point(117,166), new Point(114,167), new Point(112,166), new Point(114,164), new Point(116,163), new Point(118,163), new Point(120,162), new Point(122,163), new Point(125,164), new Point(127,165), new Point(129,166), new Point(130,168), new Point(129,171), new Point(127,175), new Point(125,179), new Point(123,184), new Point(121,190), new Point(120,194), new Point(119,199), new Point(120,202), new Point(123,207), new Point(127,211), new Point(133,215), new Point(142,219), new Point(148,220), new Point(151,221)}));
            Debug.Log("Loading 12 " + (this.Templates[12] as Template).points.Count.ToString());       

            this.Templates[13] = new Template("right curly brace", new ArrayList(new Point[]{new Point(117,132), new Point(115,132), new Point(115,129), new Point(117,129), new Point(119,128), new Point(122,127), new Point(125,127), new Point(127,127), new Point(130,127), new Point(133,129), new Point(136,129), new Point(138,130), new Point(140,131), new Point(143,134), new Point(144,136), new Point(145,139), new Point(145,142), new Point(145,145), new Point(145,147), new Point(145,149), new Point(144,152), new Point(142,157), new Point(141,160), new Point(139,163), new Point(137,166), new Point(135,167), new Point(133,169), new Point(131,172), new Point(128,173), new Point(126,176), new Point(125,178), new Point(125,180), new Point(125,182), new Point(126,184), new Point(128,187), new Point(130,187), new Point(132,188), new Point(135,189), new Point(140,189), new Point(145,189), new Point(150,187), new Point(155,186), new Point(157,185), new Point(159,184), new Point(156,185), new Point(154,185), new Point(149,185), new Point(145,187), new Point(141,188), new Point(136,191), new Point(134,191), new Point(131,192), new Point(129,193), new Point(129,195), new Point(129,197), new Point(131,200), new Point(133,202), new Point(136,206), new Point(139,211), new Point(142,215), new Point(145,220), new Point(147,225), new Point(148,231), new Point(147,239), new Point(144,244), new Point(139,248), new Point(134,250), new Point(126,253), new Point(119,253), new Point(115,253)}));
            Debug.Log("Loading 13 " + (this.Templates[13] as Template).points.Count.ToString());       

            this.Templates[14] = new Template("star", new ArrayList(new Point[]{new Point(75,250), new Point(75,247), new Point(77,244), new Point(78,242), new Point(79,239), new Point(80,237), new Point(82,234), new Point(82,232), new Point(84,229), new Point(85,225), new Point(87,222), new Point(88,219), new Point(89,216), new Point(91,212), new Point(92,208), new Point(94,204), new Point(95,201), new Point(96,196), new Point(97,194), new Point(98,191), new Point(100,185), new Point(102,178), new Point(104,173), new Point(104,171), new Point(105,164), new Point(106,158), new Point(107,156), new Point(107,152), new Point(108,145), new Point(109,141), new Point(110,139), new Point(112,133), new Point(113,131), new Point(116,127), new Point(117,125), new Point(119,122), new Point(121,121), new Point(123,120), new Point(125,122), new Point(125,125), new Point(127,130), new Point(128,133), new Point(131,143), new Point(136,153), new Point(140,163), new Point(144,172), new Point(145,175), new Point(151,189), new Point(156,201), new Point(161,213), new Point(166,225), new Point(169,233), new Point(171,236), new Point(174,243), new Point(177,247), new Point(178,249), new Point(179,251), new Point(180,253), new Point(180,255), new Point(179,257), new Point(177,257), new Point(174,255), new Point(169,250), new Point(164,247), new Point(160,245), new Point(149,238), new Point(138,230), new Point(127,221), new Point(124,220), new Point(112,212), new Point(110,210), new Point(96,201), new Point(84,195), new Point(74,190), new Point(64,182), new Point(55,175), new Point(51,172), new Point(49,170), new Point(51,169), new Point(56,169), new Point(66,169), new Point(78,168), new Point(92,166), new Point(107,164), new Point(123,161), new Point(140,162), new Point(156,162), new Point(171,160), new Point(173,160), new Point(186,160), new Point(195,160), new Point(198,161), new Point(203,163), new Point(208,163), new Point(206,164), new Point(200,167), new Point(187,172), new Point(174,179), new Point(172,181), new Point(153,192), new Point(137,201), new Point(123,211), new Point(112,220), new Point(99,229), new Point(90,237), new Point(80,244), new Point(73,250), new Point(69,254), new Point(69,252)}));
            Debug.Log("Loading 14 " + (this.Templates[14] as Template).points.Count.ToString());       

            this.Templates[15] = new Template("cake", new ArrayList(new Point[]{new Point(81,219), new Point(84,218), new Point(86,220), new Point(88,220), new Point(90,220), new Point(92,219), new Point(95,220), new Point(97,219), new Point(99,220), new Point(102,218), new Point(105,217), new Point(107,216), new Point(110,216), new Point(113,214), new Point(116,212), new Point(118,210), new Point(121,208), new Point(124,205), new Point(126,202), new Point(129,199), new Point(132,196), new Point(136,191), new Point(139,187), new Point(142,182), new Point(144,179), new Point(146,174), new Point(148,170), new Point(149,168), new Point(151,162), new Point(152,160), new Point(152,157), new Point(152,155), new Point(152,151), new Point(152,149), new Point(152,146), new Point(149,142), new Point(148,139), new Point(145,137), new Point(141,135), new Point(139,135), new Point(134,136), new Point(130,140), new Point(128,142), new Point(126,145), new Point(122,150), new Point(119,158), new Point(117,163), new Point(115,170), new Point(114,175), new Point(117,184), new Point(120,190), new Point(125,199), new Point(129,203), new Point(133,208), new Point(138,213), new Point(145,215), new Point(155,218), new Point(164,219), new Point(166,219), new Point(177,219), new Point(182,218), new Point(192,216), new Point(196,213), new Point(199,212), new Point(201,211)}));
            Debug.Log("Loading 15 " + (this.Templates[15] as Template).points.Count.ToString());

        }

    }