General

In the editor scene window, to rotate about a select object hold Alt and press Middle Click.

Unity comes with a bunch of tools that you have to install from the package manager. This is confusing because they have both an asset store and a package manager. You can install Probuilder, which lets you design, prototype and play-test levels rapidly in the Unity Editor.

Cameras

To set a camera's view to be aligned with your scene view, select the camera and in the GameObject menu select “Align with Scene View”.

Unity uses left handed chirality.

Forward in Unity is the +z axis. Right is +x, up is +y.

Unity’s Prefab system allows you to create, configure, and store a GameObject complete with all its components, property values, and child GameObjects as a reusable Asset. The Prefab Asset acts as a template from which you can create new Prefab instances in the Scene.

When making changes to prefabs, don't forget to click the apply button on the inspector window of the top level prefab object, which can be hidden.

Unity uses 3 rotation systems. Intro to Quaternion Rotations (in Unity)

  1. Euler Angers - rotation about x, y, z axis
  2. Angle Axis - A normalized Vector3 representing the axis about which to rotate by float angle amount
  3. Quaternions - Angle Axis rotation representation that have been scaled to improve performance.

Calculations

Quaternion.FromToRotation()

This code snippet calculates the rotation required to rotate an object from a given starting direction (in this case the back of the object given Vector3.back) to a final direction (in this case direction to camera) using the Quaternion.FromToRotation() function.

// Get the direction to a camera
Vector3 directionToCamera = Camera.main.transform.position - transform.position;
 
transform.rotation = Quaternion.FromToRotation(Vector3.back, directionToCamera);

Quaternion.LookRotation()

Quaternion.LookRotation() gives us more control on our rotation than Quaternion.FromToRotation(), as it gives us a control of our final rotation when we finish the primary rotation (as in ending up looking at what you need to look at but being upside down). It takes in two rotations, a first priority look to direction, and then a second priority look direction.

// Get the direction to a camera
Vector3 directionToCamera = Camera.main.transform.position - transform.position;
 
Quaternion targetRotation = Quaternion.LookRotation(-directionToCamera, Vector3.up);
 
transform.rotation = Quaternion.FromToRotation(Vector3.back, directionToCamera);

Quaternions

Number primer: Numberphile video.

They are in the form of x, y, z, w. They are always normalized, so x² + y² + z² + w² = 0

Creating Quaternions

// This has to be normalized. We generally never use this
Quaternion rotation = new Quaternion(0,0,0,1);
 
// You usually create a rotation in euler and then convert to quaternion.

Conversions

// Convert from Quaternion to Euler:
Vector3 inEuler = quaternionRotation.eulerAngles;
 
// Convert Euler to Quaternion
Quaternion inQuaternion = Quaternion.Euler(inEuler);
 
// To Angle-Axis
Quaternion randomQuaternion = Random.rotation;
float angle;
Vector3 axis;
 
randomQuaternion.ToAngleAxis(out angle, out axis);
 
// And back
Quaternion rotation = Quaternion.AngleAxis(angle,axis);

Modify one rotation value to another rotation value.

SLERP - Spherical Linear Interpolation. Two ways of doing this, with a constant velocity or with a smooth variable velocity.

LERP

You can use both.

You can set a whole bunch of attributes for functions and member variables. For example:

[Serialized]
private float damage = 0f;
[Client]
private void Shoot()
{
    // Code that only runs on a client and not a server in multiplayer
}

Check the Unity Scripting API docs

        // Create a Ray at the center of the viewport
        // There is an optional LayerMask parameter used to simplify which objects should collide with the ray
        Ray ray = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0.0f));
        RaycastHit hit;
 
        // Casts a ray, from point origin, in direction direction, of length maxDistance, against all colliders in the Scene.
        if (Physics.Raycast(ray, out hit, pickupRange)) {
            // A more elegant way to do this forthcoming, using ItemID + an item database
            if (hit.transform.gameObject.tag == "YourGunTag") {
                Destroy(hit.transform.gameObject);
            }
        }   

A good tutorial that covers this

Unity is filled with awesome functions that handle complex timing for you.

The InvokeRepeating() method is one them. It lets you run a script on a timer at watever rate you like. docs.

Here is an example from this tutorial video on how to use it to handle it automatic weapon firing.

if (Input.GetButtonDown("Fire1"))
{
    InvokeRepeating("Shoot", 0f, 1f / currentWeapon.fireRate);
} else if (Input.GetButtonDown("Fire1"))
    {
        CancelInvoke("Shoot");
    }
}
 
    private void Shoot()
    {
        RaycastHit _hit;
        if(Physics.Raycast(cam.transform.position, cam.transform.forward, out _hit, currentWeapon.range, mask ))
        {
            // We hit something
            Debug.Log("We hit " + _hit.collider.name);
            if(_hit.collider.tag == PLAYER_TAG)
            {
                CmdPlayerShot(_hit.collider.name, currentWeapon.damage);
            }
        }
    }

Here's a method that will play random audio noises from a list.

    public class Shoot : MonoBehaviour
    {
        [SerializeField] private AudioSource sound;
        [SerializeField] private AudioClip[] m_Sounds;    // an array of sounds that will be selected randomly
 
        // Update is called once per frame
        void Update()
        {
            if(Input.GetButtonDown("Fire1"))
            {
                // pick & play a random footstep sound from the array,
                // excluding sound at index 0
                int n = Random.Range(1, m_Sounds.Length);
                sound.clip = m_Sounds[n];
                sound.PlayOneShot(sound.clip);
                // move picked sound to index 0 so it's not picked next time
                m_Sounds[n] = m_Sounds[0];
                m_Sounds[0] = sound.clip;
            }
        }
    }

InputField

Here's an input field for text set by a button. The script is attached to an empty game object in the scene.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class NameTransfer : MonoBehaviour
{
    public string theName;
    public GameObject inputField;
    public GameObject textDisplay;
 
 
    public void StoreName()
    {
        theName = inputField.GetComponent<Text>().text;
        textDisplay.GetComponent<Text>().text = "Welcome " + theName + " to the game!";
    }
 
}

Rect Transform

These friggen things. If you press shift and then alt, something happens. Will need to dive into this at one point.

Objects of classes always have an object of that type attached to them.

namespace UnityEngine
{
    //
    // Summary:
    //     Base class for everything attached to GameObjects.
    [NativeClass("Unity::Component")]
    [NativeHeader("Runtime/Export/Component.bindings.h")]
    [RequiredByNativeCode]
    public class Component : Object
    {
        public Component();
 
        //
        // Summary:
        //     The game object this component is attached to. A component is always attached
        //     to a game object.
        public GameObject gameObject { get; }
        //
        // Summary:
        //     The tag of this game object.
        public string tag { get; set; }
        //
        // Summary:
        //     The Rigidbody attached to this GameObject. (Null if there is none attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property rigidbody has been deprecated. Use GetComponent<Rigidbody>() instead. (UnityUpgradable)", true)]
        public Component rigidbody { get; }
        //
        // Summary:
        //     The Rigidbody2D that is attached to the Component's GameObject.
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property rigidbody2D has been deprecated. Use GetComponent<Rigidbody2D>() instead. (UnityUpgradable)", true)]
        public Component rigidbody2D { get; }
        //
        // Summary:
        //     The Camera attached to this GameObject. (Null if there is none attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property camera has been deprecated. Use GetComponent<Camera>() instead. (UnityUpgradable)", true)]
        public Component camera { get; }
        //
        // Summary:
        //     The Light attached to this GameObject. (Null if there is none attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property light has been deprecated. Use GetComponent<Light>() instead. (UnityUpgradable)", true)]
        public Component light { get; }
        //
        // Summary:
        //     The Animation attached to this GameObject. (Null if there is none attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property animation has been deprecated. Use GetComponent<Animation>() instead. (UnityUpgradable)", true)]
        public Component animation { get; }
        //
        // Summary:
        //     The Transform attached to this GameObject.
        public Transform transform { get; }
        //
        // Summary:
        //     The ConstantForce attached to this GameObject. (Null if there is none attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property constantForce has been deprecated. Use GetComponent<ConstantForce>() instead. (UnityUpgradable)", true)]
        public Component constantForce { get; }
        //
        // Summary:
        //     The AudioSource attached to this GameObject. (Null if there is none attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property audio has been deprecated. Use GetComponent<AudioSource>() instead. (UnityUpgradable)", true)]
        public Component audio { get; }
        //
        // Summary:
        //     The GUIText attached to this GameObject. (Null if there is none attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property guiText has been deprecated. Use GetComponent<GUIText>() instead. (UnityUpgradable)", true)]
        public Component guiText { get; }
        //
        // Summary:
        //     The NetworkView attached to this GameObject (Read Only). (null if there is none
        //     attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property networkView has been deprecated. Use GetComponent<NetworkView>() instead. (UnityUpgradable)", true)]
        public Component networkView { get; }
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property guiElement has been deprecated. Use GetComponent<GUIElement>() instead. (UnityUpgradable)", true)]
        public Component guiElement { get; }
        //
        // Summary:
        //     The GUITexture attached to this GameObject (Read Only). (null if there is none
        //     attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property guiTexture has been deprecated. Use GetComponent<GUITexture>() instead. (UnityUpgradable)", true)]
        public Component guiTexture { get; }
        //
        // Summary:
        //     The Collider attached to this GameObject. (Null if there is none attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property collider has been deprecated. Use GetComponent<Collider>() instead. (UnityUpgradable)", true)]
        public Component collider { get; }
        //
        // Summary:
        //     The Collider2D component attached to the object.
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property collider2D has been deprecated. Use GetComponent<Collider2D>() instead. (UnityUpgradable)", true)]
        public Component collider2D { get; }
        //
        // Summary:
        //     The Renderer attached to this GameObject. (Null if there is none attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property renderer has been deprecated. Use GetComponent<Renderer>() instead. (UnityUpgradable)", true)]
        public Component renderer { get; }
        //
        // Summary:
        //     The HingeJoint attached to this GameObject. (Null if there is none attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property hingeJoint has been deprecated. Use GetComponent<HingeJoint>() instead. (UnityUpgradable)", true)]
        public Component hingeJoint { get; }
        //
        // Summary:
        //     The ParticleSystem attached to this GameObject. (Null if there is none attached).
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Obsolete("Property particleSystem has been deprecated. Use GetComponent<ParticleSystem>() instead. (UnityUpgradable)", true)]
        public Component particleSystem { get; }

You can format your debug colors!

Debug.LogError("<Color=Red><a>Missing</a></Color> Beams Reference");

There multiple ways of doing multiplayer in Unity. Unity used to support a multiplayer system called UNet but it was deprecated in 2019 and removed from the codebase. They have yet to fully roll out their new version. Read about it here.

Another option is to use Photon's PUN service. It is free for up to 20 concurrent users and handles matchmaking. There's an official written tutorial here.

Photon PUN

PhotonView

A PhotonView identifies an object across the network (viewID) and configures how the controlling client updates remote instances.

  • unity_game_dev.txt
  • Last modified: 2020/04/18 21:02
  • by paul