User Tools

Site Tools


notes:unity3d:engine

General Info

Debugging

Shortcut Function
F5 continue debugging
F9 toggle a breakpoint
F10 step over
F11 step into
Shift+F11 step out
Ctrl+Shift+F9 delete all breakpoints
What How
Show the Console window MainMenu: Window > Console
Show errors in the Console window Console window: Click on the error filter icon in the top-right corner
Show warnings in the Console window Console window: Click on the warning filter icon in the top-right corner
Jump to a line of code that generated an error, a warning, or printed a message Console window: Double-click the error, the warning, or the message
Recompile the script Project window: Right-click a script > Reimport
Set global #defines MainMenu: Edit > Project Settings > Player > Other Settings tab > Scripting Define Symbols > enter your defines and press Enter
- to disable a define, prefix it with \
- to add multiple defines, separate them with a semicolon
Switch Inspector to the Debug mode.
This allows you to view all public and private variables in Inspector
Click on the context menu icon in the top-right corner of Inspector and select Debug:

Write a message to the Console window:

// Method#1
Debug.Log("Hello");
 
// Method#2
print("Hello");
 
// Display the position of a GameObject.
print(transform.position.ToString());

Gizmos

What How
Show gizmos in the Game view Game view: Toggle the Gizmo button in the top-right corner

Gizmos help with visual debugging. Draw them in the MonoBehaviour's OnDrawGizmo event.

Example: This gizmo draws a bounding wireframe sphere of a specified radius centered on a GameObject. In addition, it draws a line-of-sight vector that represents the object's forward direction.

using UnityEngine;
 
public class MyGameObject : MonoBehaviour 
{
    public bool DrawGizmos = true;
    public float Radius = 4.0f;
 
    void OnDrawGizmos()
    {
        if (!DrawGizmos)
            return;
 
        // Draw a front vector. The front vector showns a direction the object is facing.
        Gizmos.color = Color.blue;
        Gizmos.DrawRay(transform.position, transform.forward.normalized * Radius);
 
        // Show the proximity radius around the object.
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(transform.position, Radius);
 
        // Restore the gizmo's color back to white.
        Gizmos.color = Color.white;
    }
}

If you want to draw gizmos for selected objects only, call OnDrawGizmosSelected.

Inspector

Arrays

An array of game objects:

using UnityEngine;
 
public class SimpleTest : MonoBehaviour
{
    public GameObject[] Objects;
 
    void Start () { }
    void Update () { }
}

The above array shows up in the Inspector as follows:

You can specify the maximum capacity of the array (here 3):

Next, you can drag-and-drop objects into the array slots.

Enumerations

A variable of an enum type appears as a drop-down list in the Inspector window.

Properties

C# properties are not shown in the Inspector. Community-made scripts and solutions are available that can change this default behavior.

Fields

All public fields are exposed as properties in the Inspector. A downside of that is that other scripts may access these public fields which breaks encapsulation. In order to expose a field to the Inspector and keep it private, declare the field with the [SerializeField] attribute:

[SerializeField]
private GameObject enemy;

Keys

To snap an object to a position, hold the Ctrl key while moving an object. This makes it easier to align objects.

Key Function
Q Navigate scene
W Translate
E Rotate
R Scale
T Rect (used with 2D graphics)
combines movement, rotation, and scaling
F Reset the view on the currently selected object
Ctrl+P Toggle the play mode
Ctrl+Shift+P Toggle between paused and unpaused
Ctrl+D Duplicate an object
Shift+Ctrl+N Create an empty object
Ctrl + Delete Remove a gradient stop
Shift + Ctrl + B Display build settings
Ctrl+9 Access the Asset Store (Window > Asset Store)

The full list of Unity hot keys can be found here.

Navigation maneuver Key/mouse
Move (translate camera) Click-and-drag
Orbit (rotate camera) Alt + click-and-drag
Zoom (scale camera) Alt + right-click-and-drag
Pan Ctrl + click-and-drag
Look around Ctrl + right-click-and-drag
Focus on an object - Select the object in the Scene view.
- Hover the cursor over the Scene view.
- Press F -or- Edit > Frame Selected (F)
-or-
- Double-click the object in Hierarchy view

Logging

One way to create a logging mechanism in Unity is to use the Application class to receive exception notifications:

using UnityEngine;
using System;
using System.IO;
 
public class ExceptionLogger : MonoBehaviour 
{
    private const string LogFilename = "log.txt";
 
    void Start () 
    {
        // The Application.persistentDataPath location is always writeable.
        // When run under Unity, the path is C:/Users/testuser/AppData/LocalLow/DefaultCompany/TestProject
        Debug.Log ("PersistentDataPath: " + Application.persistentDataPath);	
    }
 
    // Register for exception listening.
    void OnEnable()
    {
        // The logMessageReceived event is invoked when a log message is received.
        Application.logMessageReceived += HandleLog;
    }
 
    // Unregister from exception listening.
    void OnDisable()
    {
        Application.logMessageReceived -= HandleLog;
    }
 
    // Update is called once per frame
    void Update () { }
 
    private void HandleLog(string logString, string stackTrace, LogType type)
    {
        using (StreamWriter writer = new StreamWriter(
               Path.Combine(Application.persistentDataPath, LogFilename)))
        {
            if (type == LogType.Exception || type == LogType.Error) 
            {
                writer.WriteLine("Logged at: " + DateTime.Now.ToString () + Environment.NewLine +
                    "Description: " + logString + Environment.NewLine +
                    "Trace: " + stackTrace + Environment.NewLine +
                    "Type: " + type.ToString ());
            }
        }
    }
}

Models

3D model file formats supported by Unity

File type Mesh Animation
FBX v v
DAE (Collada) v v
OBJ v
3DS v
DXF v

Additonal formats supported by Unity that are exported to FBX behind the scene. They require the corresponding application to be installed:

  • Maya
  • 3ds Max
  • Blender

Common properties of 3D models:

  • Scale Factor - Unity import models to a very small scale. You may want to adjust the Scale Factor to compensate the small File Scale value.
  • Generate Colliders - when checked, prevents objects from going through the model.
  • If your model does not have an animation, switch the animation off: Animation tab > deselect Import Animation

Note that when you import a 3D model, Unity creates a material for this model. You may want to assign a texture to the material.

Mesh Filter holds a mesh. Mesh Renderer renders the mesh.

Profiling

Available in Unity Pro.

The profiler gives you a statistical top-down view of how time and workload is distributed across the different parts of your game and across system hardware components, such as the CPU and graphics card.

When viewing the performance graph, it's a good practice to watch for sudden increases (peaks or spikes). These indicate frames of sudden and intense activity.

More info on the profiler can be found here.

Scripting

What How
Create a C# script MainMenu: Assets > Create > C# Script
-or-
Right-click on an empty space in the Project window > Create > C# Script
-or-
Create and attach a script in one step: Select a game object > Inspector > [Add Component] > New Script > [Create and Add] (note that the script is added into the project's root).

Script filenames:

  • Unity uses the filename to determine the name of a C# class to be created inside the file.
  • All the script files should have a unique name across the project.
  • If you rename the script file, you also need to rename the C# class inside the file to match the filename.

MonoBehaviour is the base class for script components i.e., the scripts that contain classes that inherit from MonoBehaviour are components.

  • You can search for a specific type of object by using t: in the search box followed by a type, e.g., t:Light, t:AudioSource
  • There is a path to the found object displayed at the bottom of the Hierarchy view.
  • When cancelling the search you will be automatically moved to the found object in the Hierarchy. The Hierarchy will be expanded to show the object.

Settings and Preferences

What How
Set the default screen resolution Edit > Project Settings > Player > Inspector: PlayerSettings > Resolution and Presentiation > Default Screen Width and Default Screen Height

Remarks: Set the same width and height in the Game view's aspect ratio:
Manage tags Edit > Project Settings > Tags and Layers
Change the color of interface while in the play mode Edit > Preferences > Colors > Playmode tint > Select a color
Change the project's type (2D or 3D) Edit > Project Settings > Editor > Inspector view > “Default Behavior Mode” > Mode
Set/change the default script editor Edit > Preferences > External Tools > External Script Editor > Visual Studio -or- Mono Develop
Set a build target File > Build Settings > Select a platform > [Switch Platform]
Set build settings (aka player settings) File > Build Settings > [Player Settings]
-or-
Edit > Project Settings > Player
Set the aspect ratio Game view > Select the aspect ratio from the second drop-down after Display

Stats panel

How to access the Stats panel:

  • Select the Game view.
  • Click on the Stats button in the top-right corner of the toolbar.

The most important parameter in the Stats panel is FPS (frames per second) which indicates how often the Update event is called. Strive for 30 FPS or above.

View Gizmo

  • Shift + MiddleCube switches the scene view camera to Perspective view.
  • You can switch to Ortographic view by clicking on the text below gizmo.
  • When orbiting in Ortographic view, you are automatically switched to Isometric view.
  • When in Isometric view, press the white MiddleCube to go back to the Perspective view.
  • Look at the plane from above by clicking 'y' in the view gizmo.

Components & Classes

Animation

The Animation Controller is a state machine that governs animation states.

  • Create an Animation Controller: Project view > Create > Animation Controller
  • Add the Animation Controller to a GameObject you need to control (for example, a player).
  • To see the controller, double-click it in the Project view. It opens the Animator window.
  • Expand your model in the Project view to see the components of the model.
  • Move animations (marked with a [>] icon) from the Project view onto the Animator window.
  • An orange state is a default state. Set a default state by right-clicking on the state and selecting “Set as Layer Default State”.
  • Add parameters (there is a Parameters tab next to the Layers tab in the Animator window) for example a bool parameter IsWalking.
  • A Trigger parameter is similar to bool but once it is set to true, it sets back to false automatically (i.e., it resets itself).

Add conditions (transitions) to move from one state to another:

  • Right-click on a state and select “Make Transition”.
  • Move the transition to a destination state.
  • Click the transition allow. The Inspector shows Conditions of this transition.
  • Click + to add a condition (for example IsWalking = true - it means that we transition from Idle to Walking when IsWalking == true)
  • Uncheck Has Exit Time for the animations to work correctly or you will get an error: “Asset Player: Transition in state AnyState doesn't have an Exit Time or any condition, transition will be ignored”.
  • If you want to transition from any state, simply make a transition from the Any State to your state such as a Death state (you can die any time).

Attributes

Use the RequireComponent attribute to ensure that other components needed by the script are attached.

// The script requires the CharacterController component.
[RequireComponent(typeof(CharacterController))]
public class FirstPersonInput : MonoBehaviour
{
    // ...
}

Use the AddComponentMenu attribute to add the script to the component menu in Unity's editor (the Add Component button at the bottom of the Inspector).

// Add the script to the "Control Script" group and assign it to the "Custom Input" menu item.
[AddComponentMenu("Control Script/Custom Input")]
public class FirstPersonInput : MonoBehaviour
{
    // ...
}

Use the SerializeField attribute on a private field to expose the field in the Inspector but disallow other scripts to access it (works in both the Normal and Debug modes):

public class SceneController : MonoBehaviour
{
    [SerializeField]
    private GameObject enemyPrefab;
 
    [SerializeField]
    private GameObject[] objects;
 
    [SerializeField]
    private double speed;
 
    void Update ()
    {
        // ...
    }
}

Use the HideInInspector attribute to hide a public variable from the Inspector:

[HideInInspector]
public int Counter;

Camera

// Get a reference to the first enabled camera tagged "MainCamera".
Camera mainCamera = Camera.main;
 
// Get a GameObject associated with the main camera.
GameObject cameraObj = Camera.main.gameObject;

CharacterController.

The CharacterController component makes a GameObject move like a character, including colliding with obstacles. You may want to replace the object's collider with a Character Conroller if the object is your player.

Add a Character Conroller component:

  • Inspector: Click [Add Component] > Physics > Character Controller

Example: Move a GameObject that has a CharacterController component attached:

using UnityEngine;
 
[RequireComponent(typeof(CharacterController))]
public class FirstPersonInput : MonoBehaviour
{
    public float speed = 9.0f;
 
    // A reference to the CharacterController component attached to this GameObject.
    private CharacterController cc;
 
    void Start ()
    {
        cc = GetComponent<CharacterController>();
    }
 
    void Update ()
    {
        float deltaX = Input.GetAxis("Horizontal") * speed;
        float deltaZ = Input.GetAxis("Vertical") * speed;
 
        Vector3 movement = new Vector3(deltaX, 0, deltaZ);
 
        // Limit movement vector's magnitude to the movement speed.
        // Otherwise diagonal movement would have a greater magnitude than movement
        // along the X or Z axis.
        movement = Vector3.ClampMagnitude(movement, speed);
 
        // Transform the movement vector from local to global coordinates.
        // We need the movement vector to be in global coordinates rather than 
        // in local because, for example, the player's left may be a different
        // direction from the world's left.
        movement = transform.TransformDirection(movement * Time.deltaTime);
 
        // Move the character controller by the movement vector.
        // The Move method moves the object in global coordinates.
        // It takes absolute movement deltas as the parameter.
        cc.Move(movement);
    }
}

Collider.

  • Static colliders are non-moving objects (e.g., a wall). Any game object with a collider but no rigidbody is static.
  • Dynamic colliders are moving objects (e.g., a car). Any game object with a collider and a rigidbody is dynamic.

A collider can be configured as a trigger. In this case the physics engine will allow for overlap of collider volumes but won't cause a collision. It means that the collider will no longer stop other objects from passing through.

OnTriggerEnter is called when a GameObject's collider overlaps a collider of another object. Another object's collider is passed to OnTriggerEnter as the other reference.

What How
Add a collider to a GameObject - Select the object in the Scene view.
- Inspector > [Add Component] > Physics > Capsule Collider (or any other collider)

Example: Configure a collision between two objects: a Player and an Enemy.

1. Create two GameObjects (for example cubes) and name them Player and Enemy. Also, create and assign an “Enemy” tag to the Enemy object.

2. Create a script to move the Enemy toward the Player and attach it to the Enemy. The idea is that the Enemy should somehow collide with the Player:

using UnityEngine;
 
public class MoveHoriz : MonoBehaviour
{
    public float speed = 1.0f;
 
    void Update ()
    {
        transform.Translate(Time.deltaTime * speed, 0, 0);
    }
}

3. Configure the Player's Collider component as a trigger by selecting the Is Trigger checkbox:

4. Add a Rigidbody component to the Player and uncheck Use Gravity.

5. Repeat the steps 3 and 4 for the Enemy.

6. Create a collision detection script and attach it to the Player:

using UnityEngine;
 
public class DetectCollision : MonoBehaviour
{
    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Enemy"))
        {
            Debug.Log("Crash!");
            Destroy(other.gameObject); // destroy the enemy
        }
    }
}

7. Run the game. Once the Enemy reaches the Player, the “Crash!” message should be displayed in the Console. Also, the Enemy should dissapear.

Example: Deactivate an object with a tag MyObject when the GameObject touches it:

void OnTriggerEnter(Collider other)
{
    if (other.gameObject.CompareTag("MyObject"))
    {
        other.gameObject.SetActive(false);
    }
}

Example: Destroy the GameObject if it collides with anything:

void OnTriggerEnter(Collider other)
{
    Destroy(this.gameObject);
}

Links

Performance

As a performance optimisation, Unity calculates all the volumes of all the static colliders in a scene and holds this information in a cache. This makes sense as static colliders shouldn't move, and this saves recalculating this information every frame.

Any time we move, rotate, or scale a static collider Unity recalculates them again and update the static collider cache. It consumes resources.

We can move, rotate or scale dynamic colliders as often as we want and Unity won't recache any collider volumes. Unity expects us to move colliders. We simply need to indicate to Unity which colliders are dynamic before we move them. We do this by using the Rigidbody component.

  • Any GameObject with a collider and a rigidbody is considered dynamic.
  • Any GameObject with a collider but no rigidbody is expected to be static.
  • Dynamic colliders can move, and have a rigidbody attached.
  • Standard rigidbodies are moved using physics forces.
  • Kinematic rigidbodies are moved using their transform.

Coroutines

Coroutines are a Unity-specific way of handling tasks that execute incrementally over time.

  • The statement yield return new WaitForSeconds(n) pauses execution for n seconds, resuming after the interval at the next line.
  • The statement yield return null suspends execution for the current frame, resuming execution at the next line on the next frame.

Example: Draw a sphere and remove it after one second:

// The point variable is the position of the sphere.
StartCoroutine(DrawSphere(point));
...
private IEnumerator DrawSphere(Vector3 pos)
{
    GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    sphere.transform.position = pos;
 
    yield return new WaitForSeconds(1);
 
    Destroy(sphere);
}

Cursor

Hide and lock the mouse cursor:

Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;

Click Esc to unlock the mouse cursor.

GameObject

A GameObject is composed of related components. A component is a class derived from MonoBehaviour. It can be attached to a GameObject in the scene to change its behaviour.

You can add components to a GameObject using the Component menu. You can also add your own custom components by dragging-and-dropping your scripts onto a GameObject.

Finding

Use GameObject.Find or GameObject.FindGameObjectWithTag methods to find an object in the scene. Keep in mind that these methods may be expensive. It means that you should call them during events such as Start and Awake rather than Update.

GameObject.FindGameObjectWithTag performs better than GameObject.Find or Object.FindObjectsOfType. The FindGameObjectWithTag method performs well because internally Unity converts the tag parameter to a numerical value which speeds up comparison.

Method Description
GameObject.FindGameObjectWithTag(string tag) returns the first occurence of an object with a matching tag
GameObject.FindWithTag(string tag) the same as FindGameObjectWithTag (?)
GameObject.FindGameObjectsWithTag(string tag) returns an array of objects with a matching tag
GameObject.Find(objectName) returns the first occurence of an object with a name
// Search the scene for the first occurence of an object with the tag "Enemy".
GameObject enemy = GameObject.FindGameObjectWithTag("Enemy");
 
// Search the scene for all objects with the tag "Enemy" and return them in an array.
GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
 
// Search the scene for the first occurence of an object with the name "Player" (two equivalent statements).
GameObject obj = GameObject.Find("Player");
GameObject obj = GameObject.Find("Player").gameObject;
 
// Find a game object by its name and call a method MyMethod of its component MyScript.
GameObject.Find(name).GetComponent<MyScript>().MyMethod();

Example: Find the nearest GameObject to a given object in terms of linear distance:

GameObject[] objects = GameObject.FindGameObjectsWithTag(tag);
GameObject nearest = FindNearestGameObject(gameObject);
...
private GameObject FindNearestGameObject(GameObject obj)
{
    GameObject nearestObject = null;
    float shortestDist = float.MaxValue;
 
    foreach (GameObject o in objects)
    {
        // Calculate the distance between two points.
        // The Vector3.Distance(a,b) method is the same as (a - b).magnitude
        float dist = Vector3.Distance(transform.position, o.transform.position);
        if (dist < shortestDist)
        {
            // Exclude the game object the script is called on.
            if (o.GetInstanceID() != obj.GetInstanceID())
            {
                shortestDist = dist;
                nearestObject = o;
            }
        }
    }
 
    return nearestObject;
}

Example: Build an array of GameObjects:

using UnityEngine;
 
public class SimpleTest : MonoBehaviour
{
    public GameObject[] Objects;
 
    void Start ()
    {
        Objects = new GameObject[3];
 
        // Find objects in the active scene by name (case sensitive).
        // The Find method returns null if no object is found with the given name.
        Objects[0] = GameObject.Find("Cube");
        Objects[1] = GameObject.Find("Cylinder");
        Objects[2] = GameObject.Find("Sphere");
    }
}

Comparing

Compare tags of two GameObjects:

// gameObject - a reference to this GameObject
// obj - a reference to another GameObject
bool theSameTag = gameObject.CompareTag(obj.tag);

Determine if two GameObjects represent the same object:

bool theSameObjects = (gameObject.GetInstanceID() == obj.GetInstanceID());

Destroying

Destroy a GameObject from the scene graph:

GameObject obj = GameObject.Find("Sphere");
Destroy(obj);

An object that destroys itself after a certain amount of time:

public class DestroyByTime : MonoBehaviour 
{
    public float lifetime;
 
    void Start()
    {
        Destroy(gameObject, lifetime);
    }
}

Parent/Child

Attach an object to another object as a child through the Transform component:

// 'childObj' and 'parentObj' are instance of GameObjects.
childObj.transform.parent = parentObj.transform;

Iterate all children attached to this object:

for(int i=0; i<transform.childCount; ++i)
    Debug.Log(transform.GetChild(i).name);

Get the transform of a GameObject's child:

Vector3 pos = transform.FindChild(childName).position;

Activate/Deactivate

Use the SetActive method to activate a GameObject. Note that the GameObject's Update method is called only if the object is active.

Immortal

Normally, objects don't survive outside the scene to which they belong but there are certain objects that you need carried over between scenes, such as the Player character, a high-score system, an AudioManager, or a GameManager (aka GameController) class.

Use the DontDestroyOnLoad method to make a GameObject persistent.

void Start()
{
    DontDestroyOnLoad(gameObject);
}

Keep in mind that all child objects will survive with the persistent object as well as any assets or resources it uses, such as meshes, textures, and sounds. For this reason, many persistent objects are empty GameObjects with no children, featuring only the basic components.

Also, be careful not to create duplicates of persistent objects when reloading or returning to a scene in which the persistent object was created. A remedy to that is to create your persistent object as a singleton.

public class GameManager : MonoBehaviour
{
    private static GameManager instance = null;
 
    // Singleton instance.
    public static GameManager Instance { get { return instance; } }
 
    // GameManager's functionality.
    public int highScore = 0;
    public bool isPaused = false;
    // etc.
 
    void Awake()
    {
        // Check if any valid instance of the GameManager already exists in the current scene.
        // If so, delete this GameManager object, because only one instance of GameManager is allowed and
        // it already exists.
        if (instance != null)
        {
            DestroyImmediate(gameObject);
        }
        else
        {
            // Make this GameManager object the only instance.
            instance = this;
 
            // Make the GameManager persistent.
            DontDestroyOnLoad(gameObject);
        }
    }
}

GetComponent

GetComponent

Use the GetComponent method if you need to access a single component and you know its data type. GetComponent returns a reference to the first component of a matching type attached to a GameObject.

Examples:

Rigidbody rb = GetComponent<Rigidbody>();
Transform trans = GetComponent<Transform>();
CharacterController cc = GetComponent<CharacterController>();
MyScript script = GetComponent<MyScript>();

Use the MonoBehaviour.Invoke method to call a method of another component. The second argument specifies the time (in seconds), after which the method should be invoked:

// Get a reference to a component.
MyScript script = GetComponent<MyScript>();
 
// Call the OnSave method on the MyScript component.
script.Invoke("OnSave", 0.5f); // call OnSave after half a second

In this example, the handler is any component provided via Object Inspector:

public class CustomComponent : MonoBehaviour
{
    public MonoBehaviour Handler;
 
    void Start()
    {
        Handler.Invoke("OnSave", 0.0f);
    }
}

Two ways of testing if a component is attached to a GameObject:

// Method #1
if (obj.GetComponent<MyComponent>())
{
    // ...
}
 
// Method #2
if (obj.GetComponent<MyComponent>() != null)
{
    // ...
}

GetComponents

Use the GetComponents method to return references to all components of a given type attached to a GameObject.

Examples:

// Component is a base class of all components.
Component[] all = GetComponents<Component>();
 
// Get all MyScript components.
MyScript[] scripts = GetComponents<MyScript>();

FindObjectsOfType

Use the static Object.FindObjectsOfType<ObjectType> method to return an array of active components (or objects in general) of a given type:

Examples:

// Get a list of all colliders in the scene.
Collider[] cols = Object.FindObjectsOfType<Collider>();
 
// Get a list of all transform components in the scene.
Transform[] objects = Object.FindObjectsOfType<Transform>();

Interobject Communication

Use GetComponentsInChildren and GetComponentsInParent if you need to access components outside of a GameObject.

  • GetComponentsInChildren - returns refrences to all components in all children of a GameObject.
  • GetComponentsInParent - returns refrences to all componets in an object's parent.

Another way of calling a method on another object is to access a script attached to that object:

RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
    // Retrieve the object the ray hit.
    GameObject obj = hit.transform.gameObject;
 
    // Access a script on the object.
    EnemyObject target = obj.GetComponent<EnemyObject>();
 
    if (target != null)
    {
        // Call a method of the target.
        target.Die();
    }
}

Input

Unity docs: “Use the UnityEngine.Input class to read the axes set up in the Input Manager, and to access multi-touch/accelerometer data on mobile devices. The value is in the range -1…1 for keyboard and joystick. If the axis is setup to be delta mouse movement, the mouse delta is multiplied by the axis sensitivity and the range is not -1…1. This value is frame-rate independent; you do not need to be concerned about varying frame-rates.”

The Input.GetAxis method returns a positive or a negative number, depending on the direction of movement.

Display a list of abstract input names and the controls mapped to those names:

  • Main Menu: Edit > Project Settings > Input

Examples:

// 'speed' (also called 'sensitivity') is a scaling factor.
 
// Get input from the mouse.
float deltaHoriz = Input.GetAxis("Mouse X") * speed;
float deltaVert = Input.GetAxis("Mouse Y") * speed;
 
// Get input from the keyboard. "Horizontal" and "Vertical" are indirect names for keyboard mapping.
// The left/right arrows and the letters A/D are mapped to "Horizontal".
// the up/down arrows and the letters W/S are mapped to "Vertical".
float deltaHoriz = Input.GetAxis("Horizontal") * speed;
float deltaVert = Input.GetAxis("Vertical") * speed;
 
// Check if the left mouse button has been clicked.
bool clicked = Input.GetMouseButtonUp(0)
bool clicked = Input.GetButton("Fire1");
 
// Get the mouse position in pixel coordinates.
Vector3 point = Input.mousePosition;

Light

Lighting in Unity is provided by the Light component. To show the Lighting panel select Window > Lighting. It has three tabs: Object, Scene, Lightmaps.

Mark an object as Static in the Inspector if you apply light mapping, mesh baking, or light baking. For example, buildings and the ground should be set as static objects.

There are two broad types of lighting in Unity:

  • Dynamic lighting - calculated in real time while the game is running.
  • Baked lighting - calculated offline and saved to a texture light map. The texture is then applied to the baked objects in the scene. This improves performance.

The Light component defines four types of lights:

  • The Directional Light behaves like the sun. It illuminates objects based on the direction of the light. The position of a directional light does not affect the light cast from it, only the rotation the light source is facing.
  • The Point Light behaves like a light bulb. It illuminates objects based on the light's position in the scene. Rotation has no influence on the light as this light shines equally in all directions. Point lights are brighter when an object is closer. Note that other than Range, the settings for point lights are the same as for directional lights.
  • The Spot Light behaves like a flashlight or headlamps on a car. It points in a direction based on its rotation and illuminates all objects within a cone. Spot lights respond to both rotation and position.
  • Area lights only work when baking a light map. Area lights shine in all directions to one side of a rectangular plane.

Commonly used properties of light sources:

  • Intensity - controls the brightness of the light. Intensity is independent of range.
  • Range - determines how far a light is emitted from the centre of the gameobject holding the light component. Range only works with point and spot lights.
  • Spot angle (only for spot lights) - determines the angle of the cone used by the spot light in degrees.
  • Color - controls the color of the light.

Ambient light

  • Access ambient light properties: Window > Lighting > Scene tab
  • Ambient light controls global non-directional lighting in the scene.
  • Ambient light works with both dynamic and baked lighting.
  • For complete control set the ambient light to black and use only the lighting in the scene.

Emissive materials

  • Emissive materials are created by setting the emission property in an appropriate self-illuminating shader.
  • Emissive materials work only with baked lighting.

Cookies

  • A cookie acts like a mask in front of the light to create a patterned shadow.
  • Cookies use the alpha channel of a texture to give the light a projected shadow pattern.
  • Cookies must be a 2D texture when working with spot and directional lights.
  • Cookies must be a cube map when using a point light (because the point light shines in all directions).
  • When using directional lights there is an option to change the cookie's size, scaling the pattern in the scene.
  • Cookies do not work with area lights. When using baked lighting cookies only work with spot lights and are ignored for baked point lights and baked directional lights.

Shadows

  • There are two types of shadows available: hard and soft shadows.
  • Strength sets the value of the darkness of the shadow.
  • Resolution is a quality setting.
  • Bias controls an offset value to optimise shadow rendering. It affects how far from objects the shadows will start.

Halo

  • The Draw Halo property of the Light component draws the default halo around the light.
  • Halos respond to both the range and intensity of the light.
  • To override the default halo add an individual Halo component:
    • Uncheck the Draw Halo property of the Light component.
    • [Add Component] > Effects > Halo

Flare

  • To render a flare, assign a flare asset to the flare slot of your light source.
  • Flares only respond to the intensity of the light.
  • A lens flare component can be attached directly to the game object:
    • [Add Component] > Effects > Lens Flare
    • Leave the flare property on the light source empty or there will be two flares rendered on the light.
  • A flare layer component must be attached to a camera for that camera to render a flare element.

Render Mode

  • There are two different methods of rendering dynamic lights: using vertex lighting and using per pixel lighting.
  • Normal mapping, light cookies and real time shadows are only rendered for pixel lights.
  • Spot light shapes and specular highlights are much better when rendered in pixel mode as well.
  • Limit the number of pixel lights: Edit > Project Settings > Quality > Pixel Light Count

Tips

  • Direction light: To obtain a nice rounded shade set RotationX=50 and RotationY=60.
  • Fill light: To not overwhelm your main light, darken your fill light.
  • Rim light: Position your rim light under the game object. This way it will only light contours of the object.

Set a spot light in the current position of the scene camera:

  • Select the spot light in your scene view.
  • Ctrl + Shift + F
  • You should see a circle that is the bottom on the spot light's cone
  • Move the scene camera a little bit
  • You should see the spot light's cone

Materials

What How
Create a material and set its color Project panel > Click the Create drop-down > Material > Inspector: change Albedo; Albedo represents the color of material
-or-
MainMenu: Assets > Create > Material > Inspector: change Albedo
Apply a material Drag a material from the Project tab onto an object in the Scene view. This allows you to preview how the material would look like applied to an object from the scene.
-or-
Drag a material from the Project tab onto an object in the Hierarchy view.
-or-
Drag a material from the Project tab onto a slot in the Mesh Renderer component of a GameObject.
Inspect a mesh material Materials are associated with the Mesh Renderer component of a game object. Expand the Mesh Renderer to see the materials applied:
View properties of a material Select the material in the Project tab.
-or-
Select an object in the Hierarchy tab. In the Inspector, at the bottom of the game object's components, there are properties of associated materials. This part of inspector describes the actual material rather than an instance associated with the GameObject.
Change the shininess of a material Adjust the Smoothness property (smoother surfaces are more shiny)

Messaging

Use SendMessage and BroadcastMessage methods to call functions by name on other components attached to the same GameObject, regardless of their type. The messaging methods are useful when there are lots of different types of objects receiving the message.

  • SendMessage - executes a method by its name on all components attached to a GameObject.
  • BroadcastMessage - executes a method by its name on all components attached to a GameObject and recursively on all child objects.

Both methods rely on reflection, which can cause performance issues. Because of that, minimize their usage, especially during Update and OnGUI events. Delegates and interfaces offer a faster alternative.

Example: Assume that the TestObject script is attached to a GameObject. The following code invokes Method1 on the TestObject and all components/scripts attached to this GameObject (if they have Method1):

using UnityEngine;
...
public class TestObject : MonoBehaviour 
{
    void Start () 
    {
        // SendMessageOptions defines what happens if Method1 is not present on a component.
        SendMessage("Method1", SendMessageOptions.DontRequireReceiver);
    }
}

See also: EventManager.

MonoBehaviour Events

MonoBehaviour is the base class for script components i.e., the scripts that contain classes that inherit from MonoBehaviour are components.

Event Description
Awake Called before the Start event. The difference between Awake and Start is that Awake is always called at object creation and Start is called on the first frame in which the GameObject becomes active. If a GameObject starts the scene deactivated, then Start will not be called until the object is activated. For objects that are activated by default, Start is called at the beginning of the scene, after the Awake event. If you need to cache component references into local variables of a class then use the Awake event rather than Start. During the Start event, the assumption is that all local references to objects are already valid.
Start Called on the frame when a script is enabled just before any of the Update methods is called the first time. Start is called exactly once in the lifetime of the script.
Update Called once before rendering a frame for every active component on every active GameObject in the scene. It's useful for performing repetitive behaviors or functionality that must be updated over time, such as input events or mouse clicks. Note that the order in which Update events are invoked across all components for each frame is not guaranteed.
FixedUpdate Called in regular and normalized fashion with fixed time intervals between each call. It's useful for working with physics such as updating the velocity of your object or a Rigidbody component.
LateUpdate Called once per frame just like Update but it is guaranteed to run after Update and FixedUpdate. It's useful for updating camera movement, performing procedural animation, and gathering last known states.

The Update methods should contain minimal code such as reading player input. All other code should be handled by an event system.

OnDestroy Called when the GameObject is removed.
OnMouseDown
OnMouseEnter
OnMouseExit
The mouse-input and touch-input events. In order to be fired, the GameObject has to have a collider component attached.
OnApplicationQuit OnApplicationQuit is sent to all objects in the scene just before the game exits but before the scene and its contents are destroyed. Sometimes, however, OnApplicationQuit may not be called on devices which don't quit applications but rather suspend them. If you need to receive OnApplicationQuit events on suspension, you need to enable the relevant option:
MainMenu: Edit > Project Settings > Player > Inspector: expand the Other Settings tab for the iOS builds and enable the Exit on Suspend checkbox
OnApplicationFocus OnApplicationFocus is sent to all objects in the scene when the game loses focus.
OnApplicationPause There are two kinds of pause events in Unity:
- An ultimate pause where every activity and every event in a game is suspended; in this state, there is no passing of time and nothing can move forward.
- A relative pause where the game is aware of being in a paused state; it halts some events but allows others to continue such as GUI interaction and user input, which can unpause the game.

The OnApplicationPause event refers to the ultimate pause. This event is called only if the Run In Background option is not enabled in the Player Settings tab, under the Resolution group. This option, when disabled, automatically pauses a desktop game whenever the window focus is lost. This means OnApplicationPause follows an OnApplicationFocus event. In iOS, OnApplicationPause will be called whenever the application is minimized or pushed into the background.
OnGUI Called every frame after the scene is rendered.

Do not rely on the OnApplicationPause event for creating a relative pause. To achieve this, use the Time.timeScale variable or create a more comprehensive system in which you have control over which elements are paused.

The full list of MonoBehaviour events can be found here.

Particle Systems

What How
Create a particle system MainMenu: GameObject > Particle System
Apply a material
(possibly with a texture)
to a particle system
- Select the particle system
- Expand Renderer in the Inspector
- Drag a material onto the Material slot:

- Change the shader for the particle material, for example, to Additive:
Shader drop-down list > Particles > Additive

Many of the particle system properties are controlled by a curve displayed at the bottom of Inspector. It represents how the value changes over time:

Commonly used properties of particle systems:

Property Description
Looping Determines if the particle system keeps playing forever.
Start Lifetime How long the particle exists.
Start Speed How fast the particle is moving.
Start Size How big the particle is.
Start Rotation The orientation of the particle.
Start Color A particle tint.
Simulation Space - Local simulation space is fine for a still particle system.
- World simulation space may be better for a moving particle system.
Emission How quickly particles are emitted.
Shape The shape of the area emitted from. The default is a wide cone.
Size over Lifetime How the particle grows and shrinks over time.
Rotation over Lifetime Hoe the particle rotates over time.
Render How the particle looks like.

Prefabs

A prefab is a game object with components already attached and set up that does not exist in any specific scene but rather exists as an asset. A prefab instance is a copy of the prefab placed in a scene.

Create a prefab by dragging a GameObject from the Hierarchy tab and dropping it in the Project tab. This automatically saves the object as a prefab. Back in the Hierarchy the original object's name turns blue to signify that it's now linked to a prefab.

If you want to edit the prefab, first make changes on the original object. Then, to propagate changes from the object to the prefab, select GameObject > Apply Changes To Prefab from the MainMenu.

Alternatively, you may want to delete the original object and spawn the new objects from the prefab.

The instantiation of a prefab creates a copy of a GameObject in the scene.

Example: Instantiate a prefab and assign it to a private variable enemy:

public class SceneController : MonoBehaviour
{
    // A variable for linking to the prefab object.
    [SerializeField]
    private GameObject enemyPrefab;
 
    // An enemy object in the scene.
    // Note that this object is automatically added to the scene once instantiated.
    private GameObject enemy;
 
    void Update ()
    {
        // Only spawn a new enemy if there isn't already one in the scene.
        // We compare the enemy variable to null here but keep in mind that this comparison
        // may be changed in the future versions of Unity to something like enemy.isDestroyed
        if (enemy == null)
        {
            // Instantiate an object from the prefab.
            enemy = Instantiate(enemyPrefab) as GameObject;
 
            enemy.transform.position = new Vector3(0, 1, 0);
            float angle = Random.Range(0, 360);
            enemy.transform.Rotate(0, angle, 0);
        }
    }
}

Preferences

// Check if a key is present in preferences.
bool keyFound = PlayerPrefs.HasKey(keyName);
 
// Obtain an integer assigned to a key.
int n = PlayerPrefs.GetInt(keyName);
 
// Obtain an integer assigned to a key. If the key does not exist, use the default value.
int n = PlayerPrefs.GetInt(keyName, defaultValue);
 
// Assign an integer to a key.
PlayerPrefs.SetInt(keyName, n); // n is an integer

Random

// Return a random float between -10.0f [inclusive] and 10.0f [inclusive].
float n = Random.Range(-10.0f, 10.0f);

Raycasting

  • Raycast
  • SphereCast
  • LineCast
  • Mouse picking - the action of picking out the spot in the scene directly under the mouse cursor.

Example (mouse picking): Perform a raycast using a ray originating at the camera and going through the mouse position. This Update method may be called on any object as it obtains a reference to the main camera through Camera.main:

void Update()
{  
    // Check the left click.
    if (Input.GetMouseButtonUp(0))
    {
        // Perform a raycast originating at the camera and going through the mouse position.
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit, 100)) // 100 is maxDistance
        {
            Debug.Log(hit.collider.gameObject.name); // display the name of an object hit by the ray
        }
    }
}

Another way of obtaining the object that has been hit is to access the transform property:

RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
    // Retrieve the object the ray hit.
    GameObject obj = hit.transform.gameObject;
}

A ray originating at the object's position and pointing at the object's direction:

Ray ray = new Ray(transform.position, transform.forward);

Example: Perform a raycast using a ray going from the camera through the middle of the screen. This script has to be attched to a camera object:

using UnityEngine;
 
public class RayShooter : MonoBehaviour
{
    private Camera cam;
 
    void Start()
    {
        // Access the camera attached to this object.
        cam = GetComponent<Camera>();
    }
 
    void Update()
    {
        // Check if the mouse has been clicked.
	if (Input.GetMouseButtonDown(0))
        {
            // The point is in the middle of the screen.
            Vector3 point = new Vector3(cam.pixelWidth / 2, cam.pixelHeight / 2, 0);
 
            // Uncomment, if you want the point to be located at the mouse position.
            // Vector3 point = Input.mousePosition;
 
            // Create a ray going from the camera through the point (the middle of the screen).
            Ray ray = cam.ScreenPointToRay(point);
 
            // Perform the raycast. The hit variable contains information about the instersection
            // of the ray with an object the ray hit.
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            {
                // Display coordinates where the ray hit.
                Debug.Log("Hit " + hit.point);
            }
        }
    }
}

Example: The following script determines if a clear line or path exists between two objects. The path is clear if there are no colliders intersecting an imaginary line drawn between the two objects:

using UnityEngine;
 
public class ObjectPath : MonoBehaviour
{
    // A reference to another object to whom a clear path should be tested.
    public GameObject another = null;
 
    // The layer mask specifies a bitmask indicating which layers in the scene the collision test applies to.
    public LayerMask layerMask;
 
    void Update ()
    {
        if (another != null)
        {
            // Determine if a clear path exists between two objects.
            if (!Physics.Linecast(transform.position, another.transform.position, layerMask))
            {
                Debug.Log("Path clear");
            }
            else
            {
                Debug.Log("Path not clear");
            }
        }
    }
 
    // Show a helper line.
    void OnDrawGizmos()
    {
        if (another != null)
        {
            Gizmos.DrawLine(transform.position, another.transform.position);
        }
    }
}

To use the script, follow the steps:

  • Create a new script and name it ObjectPath.
  • Copy and paste the above code to the ObjectPath script.
  • Create two objects (for example, a Player and an Enemy) as well as a few obstacles (for example, walls).
  • Create a new layer and name it Walls.
  • Assign the walls to the Walls layer.
  • Attach the ObjectPath script to the Player object.
  • Assign the Enemy object to the ObjectPath componet's Another slot.
  • Select the Walls layer in the ObjectPath componet's Layer Mask slot.
  • Start the game.

Note that if the two objects themselves have colliders, such as BoxColliders, then the colliders will be included in the collision detection. For this reason, use the LayerMask to include or exclude specific layers.

Example: Perform raycasting with a circumference around the ray. The radius parameter (0.75) determnines how far around the ray to detect intersections:

Ray ray = new Ray(transform.position, transform.forward);
RaycastHit hit;
 
if (Physics.SphereCast(ray, 0.75f, out hit))
{
    if (hit.distance < range)
    {
        // Turn toward a new direction.
        float angle = Random.Range(-100.0f, 100.0f);
        transform.Rotate(0, angle, 0);
    }
}

Tip: When your environment has an uneven surface (for example, a room full of objects on the floor) and you need to raycast from/to the surface, cover the surface (i.e, the floor) with a quad. Use the quad's collider for raycasting. You can remove the quad's mesh renderer component as you don't need to render it, you only need the collider. Also, it's a good practice to keep the surface in a separate layer. Create a new layer (call it “Floor”) and then select it in the quad's layer drop-down. This way you assign your surface to the layer “Floor”.

Rigidbody

  • Standard rigidbodies are expected to be moved using physics forces.
  • Kinematic rigidbodies are expected to be moved using their transforms.

To use physics (for example, to detect collisions or to move an object using forces) attach a Rigidbody component to a GameObject.

A kinematic rigidbody does not react to physics forces and it can be animated and moved by it's transform. This is great for everything from objects with colliders like elevators and moving platforms, to objects with triggers, like collectables that need to be animated or moved by their transform.

What How
Configure a rigidbody as kinematic In the Rigidbody component:
- Leave Use Gravity checked.
- Check Is Kinematic.
Add a rigidbody to a GameObject - Select a GameObject in the Scene view
- Inspector > [Add Component] > Physics > Rigidbody
-or-
- Component > Physics > Rigidbody

Example: Move a game object:

Rigidbody rb = GetComponent<Rigidbody>(); // a Rigidbody component associated with the GameObject
float speed = 10.0f; // the speed of the game object
float moveHoriz = Input.GetAxis("Horizontal");
float moveVert = Input.GetAxis("Vertical"); 
...
void FixedUpdate()
{
    // Determine the force vector.
    Vector3 movement = new Vector3(moveHoriz, 0.0f, moveVert);
 
    // Move the game object by applying a force to the Rigidbody associated with the game object.
    rb.AddForce(movement * speed);
}

Example: Move an object using forces:

Rigidbody rb = GetComponent<Rigidbody>();
rb.AddForce = new Vector3(x,y,z); // causes the game object to move
rb.velocity = new Vector3(x,y,z);
rb.position = new Vector3(x,y,z);
rb.rotation = Quaternion.Euler(x,y,z);

Tips:

  • If you want to set infinity for Drag and Angular Drag, type inf. It will be turned into Infinity.
  • Prevent a game object from sinking into a floor by seting Freeze Position Y and Freeze Rotation X and Z.

Scenes

If you need to export your whitebox (aka graybox) scene geometry, you may want to use third party utilities such as Obj Exporter Script or Scene Obj Exporter Editor Extension. The geometry is exported as an OBJ file.

Shaders

Shader Remarks
Standard - Supports colors (Albedo), texture, transparency (Rendering Mode), and a normal map
- Displays the color of the material (including the texture)
- Applies basic light across the surface
Particles > Additive - Adds the color of a particle to the color behind it.
- Makes a background transparent.
Particles > Multiply - Makes everything darker. It gives an opposite effect to the Additive shader.
Diffuse - A standard flat look for rendering 3D meshes
- Supports a texture
Bumped Diffuse - Use it when you have a normal map specified.
Bumped Specular - Use it if you want a shiny surface. There is a Shininess parameter available.
Unlit > Texture - Makes an object independent from the lighting system.
- Displays the texture exactly as it is in the original image.
Legacy > Transparent > Diffuse - Supports the alpha channel

Skyboxes

A skybox is a cube surrounding the camera with pictures of the sky on each side. As other textures, skybox images are first assigned to a material, and then applied to the scene.

What How
Access the default skybox MainMenu: Window > Lighting > Environmental Lighting panel:
Create a skybox material - Create a new material
- Set the Skybox > 6 Sided shader for the material
- Import six skybox textures (drag-and-drop them to the Project view or use Import New Asset
- Change the Wrap Mode of the imported textures to Clamp and press Apply

- Drag the textures to the appropriate slots of the skybox material
- Use the new skybox material in the scene (Window > Lighting > Environmental Lighting):
Toggle the skybox
Remove Skybox Scene view > Select the skybox > press Delete. Make sure None is shown in Skybox.

Sound

There are three main audio components in Unity:

  • audio clips
  • audio sources - an audio source plays an audio clip
  • audio listener

To associate an audio clip with a GameObject, use an Audio Source component:

  • Attach an Audio Source component to a GameObject and assign an AudioClip to it.

-or-

  • Drag an audio clip on to a GameObject. Unity will create a new Audio Source on the GameObject and automatically assign the dragged audio clip.

Special Folders

Assets' special folders:

  • Resources
  • Plugins
  • Editor
  • Gizmos

Examples: Load assets from the Assets/Resources folder:

// Load and instantiate a game object.
GameObject obj = Instantiate(Resources.Load("MyObject", typeof(GameObject))) as GameObject;
 
// Load a text file Levels.xml or Levels.txt etc. 
TextAsset file = Resources.Load("Levels", typeof(TextAsset)) as TextAsset;
string body = file.text; // access the body of the text file
 
// Create three instances of a game object MyObject located at the Assets/Resources folder.
for (int i = 1; i <= 3; ++i)
{
    GameObject obj = Instantiate(Resources.Load("MyObject", typeof(GameObject))) as GameObject;
    obj.transform.position = new Vector3(i-1 + i*0.2f, 0, 0);
    obj.name = i.ToString(); // assign a name
}

Textures

2D image file formats supported by Unity:

File type Lossless compression Alpha channel
PNG v v
JPG
GIF
BMP no compression
TGA v v
TIFF v
PICT
PSD no compression v
  • Textures should be sized in powers of 2 for example 256×256.
  • Textures aren't applied to geometry directly. Instead, they can be part of materials and the materials are applied to an object.
What How
Apply a texture to an object Drop a texture onto an object. A new material is created automatically and this material is applied to the object.
-or-
Apply a texture to an existing material:
Tile a texture Set the tiling properties:
Import a texture Right-click in the Project tab > Import New Asset

Time

Use the Time class to access time in your scripts.

Move this object along its forward direction:

// 'speed' is a scaling factor that represents the speed of movement.
transform.localPosition += transform.forward * speed * Time.deltaTime;

Transform.

The values of Transform properties are measured relative to the Transform's parent. It means that the parent's position is the origin of the child's position. If the Transform has no parent, the properties are measured in world space.

Read this to find out about differences between TransformPoint, TransformDirection, and TransformVector.

Get the Transform component of a GameObject by accessing its transform property:

using UnityEngine;
 
public class MyScript : MonoBehaviour
{
    void Start ()
    {
        // Get the Transform component attached to this GameObject.
        Transform trans = this.transform;
    }
}

Translation / Position

  • Transform.position - The position of an object in world space stored as a Vector3.
  • Transform.localPosition - The position of an object relative to the parent stored as a Vector3. If the object has no parent, it is the same as Transform.position. The value of Transform.localPosition corresponds to the position shown in the Inspector's Transform component.

Move a GameObject along the x axis:

// Example #1
transform.Translate(Time.deltaTime, 0, 0);
 
// Example #2
// direction is 1 or -1
transform.Translate(direction * speed * Time.deltaTime, 0, 0);

Reset a GameObject's position:

transform.position = Vector3.zero;

Place a GameObject in front of another GameObject (obj) and point in the same direction:

// Vector3.forward is a shorthand for Vector3(0,0,1)
// The TransformPoint method transforms position from local space to world space.
transform.position = obj.transform.TransformPoint(Vector3.forward * 1.5f);
transform.rotation = obj.transform.rotation;

By default an object moves in relation to its local coordinate system. You can move the object in the world coordinate system by supplying an additional parameter for Transform.Translate:

// Space.World instructs Unity to use the scene coordinate system.
transform.Translate(0, Time.deltaTime, 0, Space.World);

Rotation

  • Transform.rotation - The rotation of an object in world space stored as a Quaternion.
  • Transform.localRotation - The rotation of an object relative to the parent stored as a Quaternion.
  • Transform.eulerAngles - The rotation as Euler angles in degrees. Unity converts Euler angles to and from quaternion values.

Set the rotation angle directly:

transform.localEulerAngles = new Vector3(0, 15, 0);

Increment the current rotation:

transform.Rotate(new Vector3(0, 15, 0)); // method #1
transform.Rotate(0, 15, 0); // method #2

Increment the current rotation and make it frame rate independent.

transform.Rotate(new Vector3(0, 15, 0) * Time.deltaTime); // Rotate(Vector3)
transform.Rotate(0, 15 * Time.deltaTime, 0); // Rotate(float, float, float)

Rotate an object in relation to the world coordinate system:

// Space.Local is a default for the fourth parameter.
transform.Rotate(0, 10.0f, 0, Space.World);

Reset the GameObject's rotation:

transform.localEulerAngles = Vector3.zero;

GUI

Immediate Mode

The OnGUI method is called every frame after everything else is rendered.

Draw a label in the middle of the screen:

void OnGUI()
{
    int size = 12;
    float posX = Camera.main.pixelWidth / 2 - size / 2;
    float posY = Camera.main.pixelHeight / 2 - size / 2;
    GUI.Label(new Rect(posX, posY, size, 2 * size), "O");
}

Draw a button:

void OnGUI()
{
    // Specify the button's position, width, height, and label.
    if (GUI.Button(new Rect(10, 10, 40, 20), "Test"))
        Debug.Log("Clicked");
}

Retained Mode

All UI elements must be children of the Canvas element to behave correctly. They are anchored to the Canvas.

Follow the steps to create the visual part of GUI:

  • Import sprite images you will use in your UI. If you work in a 3D project, set the images' Texture Type to Sprite (2D and UI).
  • Create a Canvas object (MainMenu: GameObject > UI > Canvas). An EventSystem object is automatically created.
  • If you work in a 3D project, switch to 2D view mode.
  • Double-click the canvas in the Hierarchy in order to zoom out and view it fully.
  • You may want to turn off the skybox for better visibility.
  • Set the Canvas's Pixel Perfect property.
  • Make sure the Rect tool is selected.
  • Add UI objects (such as images, texts, and buttons) to the Canvas.
  • Attach the sprites to your UI elements by dragging the sprites from the Project view to the element's Source Image slot.
  • Click the Set Native Size button in the elements' Image component to resize the image correctly.
  • If needed, change the elements' anchors using the Anchor Presets or type in exact numbers for the anchor points.
  • Set the elements' padding by adjusting the PosX and PosY properties.

If GUI interferes with your gameplay, check if the mouse pointer is over an EventSystem object:

using UnityEngine.EventSystems;
...
void Update()
{
    if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
    {
        // non-GUI game logic goes here
    }
}
What How
Change button's fading Adjust the button's Fade Duration property
Turn off arrow keys navigation in GUI Deselect the check box Send Navigation Events in the settings of EventSystem
Assign an event handler to a button - Click the button in Hierarchy.
- Under the On Click() section in the Inspector, click the plus sign:

- Click the selector circle and select a GameObject whose method you want to use as your handler (or drap-and-drop a GameObject).
- From the drop-down list next to the selector, select a component of the GameObject and then a method that will serve as an event handler for the button.

Tip: Make sure that the selected game object has a component whose method you want to use.
Tip: The selection sequence is: GameObject > the GameObject's component > the component's method

Techniques

Arrange Objects

Draw objects in a circle

using UnityEngine;
 
public class DrawObjects : MonoBehaviour
{
    public GameObject obj;
 
    void Start ()
    {
        int numObjects = 12;
        float radius = 4f;
 
        // Draw objects in a circle.
        for (int i = 0; i < numObjects; ++i)
        {
            float angle = i * Mathf.PI * 2 / numObjects;
            Vector3 pos = new Vector3(Mathf.Cos(angle), 0.1f, Mathf.Sin(angle)) * radius;
            Instantiate(obj, pos, Quaternion.identity);
        }
    }
}

Draw objects in a grid

using UnityEngine;
 
public class DrawObjects : MonoBehaviour
{
    public GameObject obj;
 
    void Start ()
    {
        int numObjects = 25;
        float spacing = 2f;
 
        int num = (int)Mathf.Sqrt((float)numObjects);
 
        // Draw objects in a num x num grid.
        for (float y = -num / 2; y < num / 2; y++)
        {
            for (float x = -num / 2; x < num / 2; x++)
            {
                Vector3 pos = new Vector3(x, 0.15f, y) * spacing;
                Instantiate(obj, pos, Quaternion.identity);
            }
        }
    }
}

Draw objects as a wall

using UnityEngine;
 
public class DrawObjects : MonoBehaviour
{
    public GameObject obj;
 
    void Start ()
    {
        int numObjects = 25;
        float spacing = 0.2f;
 
        int num = (int)Mathf.Sqrt((float)numObjects);
 
        for (int y = 0; y < 5; ++y)
        {
            float yf = 0.5f + y + spacing;
            for (int x = 0; x < 5; ++x)
            {
                Instantiate(obj, new Vector3(x, yf, 0), Quaternion.identity);
            }
        }
    }
}

Camera Following an Object

The following script makes a camera follow a Player GameObject. Create a CameraController script and attach it to the camera:

using UnityEngine;
 
public class CameraConroller : MonoBehaviour
{
    // Our player object. It needs to be attached in the camera's Inspector view.
    public GameObject player;
 
    // A difference between the current position of the camera and the position of the player.
    private Vector3 offset;
 
    void Start ()
    {
        // Calculate the offset. The offset is constant.
        offset = transform.position - player.transform.position;
    }
 
    void LateUpdate ()
    {
        // Move the camera to align with the player.
        // Because this code is called in LateUpdate, we know that the player has already moved.
        transform.position = player.transform.position + offset;
    }
}

EventManager

One way of implementing an event system is to create a singleton class EventManager that persists across levels and is globally accessible. It accepts notifications of events sent by publishers and then immediately dispatches the notifications to all appropriate subscribers in the form of events. The subscribers need to register themselves with the EventManager for one or more specific events. Then, when the event occurs, the subscribers are notified.

There is also event handling system available online such as CSharpNotificationCenter. This system relies on the SendMessage and BroadcasMessage methods. Another broadcast messenger system is CSharpMessenger Extended.

See also: Messaging.

GameController

A GameController (a.k.a. GameManager or SceneController) usually is an empty GameObject providing the following functionality:

  • Determining if a game is paused.
  • Determining whether the win condition has been satisfied.
  • Tracing the current state of the game.

Levels

Progressing to the next level can be achieved by changing the active scene.

Use the SceneManager.LoadScene method to change the active scene in Unity. There is also a method SceneManager.LoadSceneAsync that loads the scene asynchronously in the background.

SceneManager.LoadScene(sceneName);

Load game levels from an XML file. This example uses LINQ-to-XML:

using UnityEngine;
using System.Linq;
using System.Xml.Linq;
using System.Collections.Generic;
...
List<string> levels = new List<string>();
 
// Load Level.xml file from Assets/Resources.
TextAsset file = Resources.Load("Levels", typeof(TextAsset)) as TextAsset;
 
XElement doc = XElement.Parse(file.text);
 
var query = from setup in doc.Elements("level").Elements("data")
            select setup;
 
foreach (XElement element in query)
    levels.Add(element.ToString());
 
// Just for testing.
foreach (string level in levels)
    Debug.Log(level);
<levels>
<level><levelname>1</levelname><data>2,D,4,45,FR,Q</data></level>
<level><levelname>2</levelname><data>33,TT,G,43,1</data></level>
<level><levelname>3</levelname><data>7,8,E,Q,21,9</data></level>
</levels>

ManualMouseInput

OnMouseDown, OnMouseEnter, and OnMouseExit are the mouse-input and touch-input events. In order to be fired, the GameObject has to have a collider component attached. There are occasions when the mouse events are not launched, even with a collider attached, because other objects (with colliders) are obscuring the objects you need to click. One solution is to assign the foreground objects to an IgnoreRaycast layer. If this is not enough, you may want to manually handle mouse input events.

A rudimentary script to handle mouse/touch input manually:

using UnityEngine;
using System.Collections;
 
public class ManualMouseInput : MonoBehaviour
{
    // A collider attached to this object.
    private Collider col = null;
 
    void Awake()
    {
        col = GetComponent<Collider>();
    }
 
    void Start ()
    {
        StartCoroutine(UpdateMouse());
    }
 
    public IEnumerator UpdateMouse()
    {
        // Is this object's collider intersected? 
        bool isIntersected = false;
 
        // Is the mouse button down?
        bool isButtonDown = false;
 
        // Loop forever 
        while (true)
        {
            // Get the mouse screen position.
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); 
            RaycastHit hit;
 
            // Test the ray for collision against this collider.
            if (col.Raycast(ray, out hit, Mathf.Infinity))
            {
                // Object was intersected. 
                if (!isIntersected)
                    SendMessage("OnMouseEnter", SendMessageOptions.DontRequireReceiver);
 
                isIntersected = true;
 
                // Test for mouse events.
                if (!isButtonDown && Input.GetMouseButton(0))
                {
                    isButtonDown = true;
                    SendMessage("OnMouseDown", SendMessageOptions.DontRequireReceiver);
                }
 
                if (isButtonDown && !Input.GetMouseButton(0))
                {
                    isButtonDown = false;
                    SendMessage("OnMouseUp", SendMessageOptions.DontRequireReceiver);
                }
            }
            else
            {
                // Check if this collider was previously intersected.
                if (isIntersected)
                    SendMessage("OnMouseExit", SendMessageOptions.DontRequireReceiver);
 
                isIntersected = false;
                isButtonDown = false;
            }
 
            // Wait until the next frame.
            yield return null;
        }
    }
}

Mouse-Look

An example of a mouse-look script:

using UnityEngine;
using System.Collections;
 
public class MouseLook : MonoBehaviour
{
    public enum RotationAxes
    {
        MouseBoth = 0,
        MouseX = 1, // horizontal rotation (around y-axis)
        MouseY = 2  // vertical rotation (around x-axis)
    }
 
    // The axes variable is available as a drop-down list in Object Inspector.
    public RotationAxes axes = RotationAxes.MouseBoth;
 
    // Horizontal and vertical sensitivity determines the speed of rotation.
    public float sensitivityHoriz = 9.0f;
    public float sensitivityVert = 9.0f;
 
    // Limits for vertical rotation. They determine how much the view can tilt up or down.
    public float minimumVert = -45.0f;
    public float maximumVert = 45.0f;
 
    // rotationX represents a vertical angle. It's called rotationX because vertical 
    // rotation goes around the x-axis.
    private float rotationX = 0; 
 
    void Start ()
    {
        Rigidbody rb = GetComponent<Rigidbody>();
        if (rb != null)
            // The player's rotation needs to be solely controlled by the mouse, not by physics.
            rb.freezeRotation = true; 
    }
 
    void Update ()
    {
        if (axes == RotationAxes.MouseX)
        {
            // Horizontal rotation.
 
            // The Rotate() method increments the current rotation.
            transform.Rotate(0, Input.GetAxis("Mouse X") * sensitivityHoriz, 0);
        }
        else if (axes == RotationAxes.MouseY)
        {
            // Vertical rotation.
 
            // Change the vertical rotation angle.
            rotationX -= Input.GetAxis("Mouse Y") * sensitivityVert;
 
            // Clamp the vertical angle between min and max limits.
            rotationX = Mathf.Clamp(rotationX, minimumVert, maximumVert);
 
            // Keep the same Y angle (no horizontal rotation).
            float rotationY = transform.localEulerAngles.y;
 
            // Set the rotation angle directly.
            transform.localEulerAngles = new Vector3(rotationX, rotationY, 0);
        }
        else
        {
            // Both horizontal and vertical rotation.
 
            rotationX -= Input.GetAxis("Mouse Y") * sensitivityVert;
            rotationX = Mathf.Clamp(rotationX, minimumVert, maximumVert);
 
            // delta is the amount to change the rotation by.
            float delta = Input.GetAxis("Mouse X") * sensitivityHoriz;
 
            // Increment the rotation angle by delta.
            float rotationY = transform.localEulerAngles.y + delta; 
 
            transform.localEulerAngles = new Vector3(rotationX, rotationY, 0);
        }
    }
}

Standard Assets Project

Unity comes with a Standard Assets Example Project. It is located at

C:\Users\Public\Documents\Unity Projects\Standard Assets Example Project

Sample scenes are located at SampleScenes > Scenes.

Tips & Tricks

  • Use an empty GameObject to attach scripts that do not apply to any specific object in the scene. Such a GameObject is often called Controller and the attached script SceneController.
notes/unity3d/engine.txt · Last modified: 2017/03/29 by leszek