The topics listed here are for reference to get familiar with using Unity, from basic tips on working with Unity to best practices.
Table Of Contents
Default windows
This is where your physical files are located, these are on your hard-drive.
Note: when referencing scripts in your scene, NEVER drag and drop these files into the Inspector. Always use the ones that are in your scene (Hierarchy view)
It's important to get familiar with the buttons at the top of the scene view. Especially the first two (Center/Pivot, Global/Local), they influence how you manipulate objects in your scene.
These are the objects (like prefab instances) that are currently in your scene.
Remember that you should create and use empty game objects a lot. You can use them to create a "folder" structure, to create a parent-child hierarchy (child follows parent), or just to have an object with a single script on it, like InputHandler.
The game view shows what the camera is currently rendering.
Note: You can and should set a resolution for your game here, instead of the default "Free Aspect" mode. This will save you a lot of time in developing your UI.
The inspector shows all the components of a selected object.
Note that Transform is also a component, even though it's a "default" one and you can't remove it.
The console shows warnings, errors and output from Debug.Log(). Always have this window visible, it's the most important one for fixing issues in your game/code. Yellow means warning, Red means error.
Note: If you double-click an error message (red), it will open up the script in Visual Studio to the exact line where the error is coming from.
The two Layers windows, one in the top-right corner of the editor, and the other that opens when you click on "Edit Layers...". Layers are useful for rendering, for identifying categories of objects, and they're useful for physics (making one layer of objects ignore collision with another layer).
When you're starting out with unity, leave this alone. This is going to become useful when you're going to work with LayerMasks for raycasting, or when you want different cameras to render different things.
Non-default windows
How Unity handles C# scripts
Reference any component/script/gameobject by making a public variable and dragging in the scene-object containing that component
(Re-)use scripts on multiple objects. This is one of the reasons it's good to have multiple, separate scripts on one object. For example, one for tracking health/damage, one for movement patterns, and a separate script for handling graphics, etc.
Drag a prefab into the Scene/Hierarchy view to create an instance, or create an instance through code by usingGameObject newGameObject = Instantiate(prefabReference);!Important! Notice the difference between:
- editing a prefab (found in Project view), which is a physical file on your harddrive, which alters all unmodified instances of that prefab
- editing an instance of a prefab, which ONLY affects that one instance but has no relation to the rest
- editing a prefab when an instance has been modified. The prefab is the "origin" file, and should affect all instances in the scene, EXCEPT for when these instances have been modified.
Quick tip to work with spritesheets and animations: When sprites are sliced (Sprite Mode: Multiple), drag the file into the Scene view and Unity will ask you to auto-generate an Animator Contoller and an animation clip (file) for you.
Differences between Javascript and C#
// Javascript
// note that there's no ; at the end of these variable statements
let variable1 = 0 // 'let' doesn't exist in C#
const variable2 = "text" // 'const' doesn't exist in C#
var variable3 = { "name":"john" } // 'var' does exist in C#, but the object notation like { "name":"john" } doesn't.
function FunctionName1(){
// do something
}
console.log("Log a message") // write to console
// C#
// note that there is always a ; at the end of these variable statements
int variable1 = 0; // you define the type of variable (int/string/GameObject)
string variable2 = "text"; // and the line needs to end with a ;
var variable3 = null; // var may only be used within functions, not as class variables
private void FunctionName1(){
// do something
}
Debug.Log("Log a message"); // write to console
// Some important types and classes:
string variable1 = "pi";
int variable2 = 3;
float variable3 = 3.14f;
GameObject variable4 = Instantiate(prefabReference);
Vector2 variable5 = new Vector2( 1.01f, 1f );
ScriptThatIWrote variable6 = GetComponent<ScriptThatIWrote>();
Scripting in Unity's C#
void Awake(){} // runs once, before Start
void Start(){} // runs once, before Update
void Update(){} // runs every frame
void OnCollisionEnter2D(Collision2D collision){} // runs once, when colliding
void OnEnable(){} // and OnDisable(){}
void OnMouseDown(){} // for basic click interactions
For more functions, and reference: Monobehaviour Script API Reference
Unity Manual: Script Execution Order
// FirstScript.cs
public class FirstScript : MonoBehaviour
{
public SecondScript externalScript; // Drag the gameobject containing this SecondScript.cs script here, in the Unity Inspector
public void FirstScriptFunction(){ Debug.Log("I'm the first script!"); }
void Start(){
externalScript.SecondScriptFunction(); // Logs: "I'm the second script!"
}
}
// SecondScript.cs
public class SecondScript : MonoBehaviour
{
public FirstScript externalScript; // Drag the gameobject containing this FirstScript.cs script here, in the Unity Inspector
public void SecondScriptFunction(){ Debug.Log("I'm the second script!"); }
void Start(){
externalScript.FirstScriptFunction(); // Logs: "I'm the first script!"
}
}
Physics in Unity
Ref: Raycasting In Unity
// Simple raycast with three parameters: point of origin, direction, and distance.
if (Physics.Raycast(transform.position, transform.forward, 10)){
Debug.Log("There is something in front of the object!");
}
public RigidBody rb;
void FixedUpdate(){
rb.AddForce(Vector3.forward); // pushes the object forward, *increasingly* faster!
}
public RigidBody rb;
void FixedUpdate(){
rb.velocity = Vector3.forward; // moves the object forward at a constant rate
}
void OnTriggerEnter2D(Collider2D collision)
{
// Executes once, if Collider is set as Trigger
}
void OnCollisionEnter2D(Collision2D collision)
{
// Executes once, if Collider is NOT set as Trigger
}
// Replace Enter with:
// - Stay, for continuous checking of collisions, executes OFTEN
// - Exit, for when the collision has ended, executes once
void Update(){
// Runs as fast as Graphics calculations.
// So with 60 FPS this block executes sixty times per second
}
void FixedUpdate(){
// Runs as fast as Physics calculations.
// See Project Settings -> Time -> Fixed Timestep to see how often FixedUpdate runs. [Default = 0.02]
When handling physics objects, don't use the Transform component to move it.
Instead of setting transform.position, use Rigidbody.MovePosition() or Rigidbody2D.MovePosition()
Various Tips & Best Practices
Remember that when you are in Play mode, you will lose all changes that you made when you exit Play mode!
Don't keep SpriteRenderer/MeshRenderer on the top object.
Make a child object and put the graphics there, including the Animator component.
Keep Rigidbody on the top object, Colliders can either be on the top object or on (multiple) child object(s).
Instead of trying to code your own math, take a look at what Unity's own MathF library has to offer: Unity's MathF script reference
Same goes for calculating positions, rotations, angles etc., use the functions available to you in Vector2/Vector3, Transform and Quaternion
Every GameObject has a transform as a component. Instead of needing to call GetComponent every time, you can use "transform".
// Set object position
// These two lines are exactly the same
GetComponent<Transform>().position = Vector3.one;
transform.position = Vector3.one;
When handling physics objects, don't use the Transform component to move it.
Instead of setting transform.position, use Rigidbody.MovePosition() or Rigidbody2D.MovePosition()
Don't do this:
public GameObject enemyPrefab;
void Start()
{
GameObject newEnemy = Instantiate(enemyPrefab);
}
Instead, do this:
public EnemyScript enemyPrefab;
void Start()
{
EnemyScript newEnemy = Instantiate(enemyPrefab);
}
public Vector2 moveInput;
void Update(){
moveInput = new Vector(Input.GetAxis("Horizontal"),Input.GetAxis("Vertical"));
}
using UnityEngine.InputSystem;
public Vector2 moveInput;
public void OnMove(InputValue value){
moveInput = value.Get<Vector2>();
}
At least make sure that the parent objects have a uniform scale of 1 (Vector3.one, of new Vector3(1,1,1).
Whenever you spawn something, keep it in a list!
public List<EnemyScript> spawnedEnemies;
public void SpawnEnemy()
{
EnemyScript newEnemy = Instantiate(enemyPrefab);
spawnedEnemies.Add(newEnemy);
}
Call a function at any time from the inspector
public List<Enemy> spawnedEnemies;
[ContextMenu("Name To Show Up In Inspector")]
public void LogAmountOfEnemies()
{
Debug.Log("amount of spawned enemies: "+spawnedEnemies.Count);
}