Unity Basics
Basic Game Development using Unity
Updated: 23 December 2025
Notes from this series
Setting Up
Create a new 3D Project with the Universal Render Pipeline and select a folder to save the project to, if this is the first time creating a Unity Project it may take some time to load
You may also need to set Visual Studio as the Editor using Edit > Preferences > External Tools and selecting Visual Studio as the External Script Editor. Even if you want to use VSCode just set this up once so that the csproj files are generated. Alternatively, you can select VSCode, select the generated files you want, and then click Regenerate Project Files
Scenes
Scenes are ways to store and separate sections of your game, like levels for example, typically scenes are saved in Assets/Scenes. To Create a Scene use File > New Scene and save it with a name
We can add simple objects to the Scene by using primitives, we can create these using GameObject > 3D Object > Object Type or by right clicking in the Scene’s object hierarchy in the left panel
f- fit entire scene to your screenr- scale toolw- move toole- rotate toolt- transform toolalt + drag- rotate screenctrl + alt + drag- tranlate screen
The standard Unity lighting and physics systems use the measurement base unit to be 1m
Materials
To set a colour or texture you make use of a Material, these are stored in Assets/Materials, you can create a new Material by right clicking on the folder and selecting Create > Material
To apply a material to an object just drag the material over the object you’d like to assign it to
A Matte material may have settings like:
- Metallic Map:
0 - Smoothness:
0.25
A Shiny material may look more like:
- Matallic Map:
0 - Smoothness:
0.75
RigidBody
To use physics a game object needs a RigidBody component. To do this you need to select Add Component > RigidBody in a component inspector
Player Movement
Player movement can be handled using the Input System pacakge to apply forces with a script that’s attached to an object
To install the package go to Window > Package Manager > Input System (search) > Install which will then reload Unity
You will also need to go to File > Build Settings and select the architecture to be x86_64
Next, on a Player object select Add Component > Player Input and then create an Input Action Asset. To create this select Create Actions in the Input Action Inspector and save it in Assets/Inputs. If you get a NullReferenceException when trying to do this it may still have created the action but not assigned it to the object, if that happens just drag it into the Actions field of the object
Scripting
Scripts are stored in Assets/Scripts which make use of C#. To create a new script you can do Assets > Create or select an object, and select Add Component > New Script in the inspector which will create an attach a script at once.
A newly created script, for example PlayerController.cs may look like so:
PlayerController.cs
1using System.Collections;2using System.Collections.Generic;3using UnityEngine;4
5public class PlayerController : MonoBehaviour6{7 // Start is called before the first frame update8 void Start()9 {10
11 }12
13 // Update is called once per frame14 void Update()15 {16
17 }18}To use a PlayerInput we need to apply an input to the object. We can use either Update to apply a change to an object immediately before render or FixedUpdate to apply a change before physics calculation. To move an object we’d like to make use of FixedUpdate
Once we add some handlers like the OnMove to handle Input Actions, and use the FixedUpdate function to set a force on the object, we’ve got something like this:
PlayerController.cs
1using UnityEngine;2using UnityEngine.InputSystem;3
4public class PlayerController : MonoBehaviour5{6 private Rigidbody _rigidBody;7 private float _movementX;8 private float _movementY;9
10 // Start is called before the first frame update11 void Start()12 {13 // Get the RigidBody data for the object14 _rigidBody = GetComponent<Rigidbody>();15 }16
17 // FixedUpdate is called before physics calculations18 void FixedUpdate()19 {20 var movement = new Vector3(_movementX, 0.0f, _movementY);21
22 _rigidBody.AddForce(movement);23 }24
25 // Handle the OnMove event26 void OnMove(InputValue movementValue)27 {28 // Get the movement vector from the input value29 var movementVector = movementValue.Get<Vector2>();30
31 _movementX = movementVector.x;32 _movementY = movementVector.y;33 }34}Next, we can add a public float force variable to expose a force multiplier that can be set from the Object Inspector itself. After doing that and implementing the multiplers the code should look like this:
PlayerController.cs
1using UnityEngine;2using UnityEngine.InputSystem;3
4public class PlayerController : MonoBehaviour5{6 public float Force = 1;7
8 private Rigidbody _rigidBody;9 private float _movementX;10 private float _movementY;11
12 // Start is called before the first frame update13 void Start()14 {15 // Get the RigidBody data for the object16 _rigidBody = GetComponent<Rigidbody>();17 }18
19 // FixedUpdate is called before physics calculations20 void FixedUpdate()21 {22 var movement = new Vector3(_movementX, 0.0f, _movementY);23
24 _rigidBody.AddForce(movement);25 }26
27 // Handle the OnMove event28 void OnMove(InputValue movementValue)29 {30 // Get the movement vector from the input value31 var movementVector = movementValue.Get<Vector2>();32
33 _movementX = movementVector.x * Force;34 _movementY = movementVector.y * Force;35 }36}
publicvariables can be modified from the Object Inspector when associating a script
Camera Movement
When setting up movement for the camera you will typically set it up as a child of a game object, this can be done by dragging the Camera object over the game object you want to use, such as the player, in the Object Hierarchy
When we link the objects, all the movements of our player will be passed on to the camera, we typically don’t want this and would normally be better off by restricting the camera movement
If our child object is rotating we might be better off by associating the two objects by using a script instead of settnig it as a child
Create a new Script called CameraController.cs by using Add Component > New Script from the Object Inspector
Since the CameraController will be positioned based on the child object, we will want to set that as a property for the CameraController, we can do this by having a public GameObject field in the CameraController class. In general, the equation that governs our relative positions is:
1CameraPosition = PlayerPosition + CameraOffsetWe can apply the above with:
CameraController.cs
1using System.Collections;2using System.Collections.Generic;3using UnityEngine;4
5public class CameraController : MonoBehaviour6{7
8 public GameObject Player;9 private Vector3 _offset;10
11 // Start is called before the first frame update12 void Start()13 {14 // The Offset is Camera Position - Player Position15 _offset = transform.position - Player.transform.position;16 }17
18 // LateUpdate is called once per frame after the Update method is run19 void LateUpdate()20 {21 // The new Position is the Player Position + Camera Offset22 transform.position = Player.transform.position + _offset;23 }24}Rotating Objects
We can create a cube that can be used as a simple collectible, we can make this rotate by using the Update function and setting the rotation based on this:
1using System.Collections;2using System.Collections.Generic;3using UnityEngine;4
5public class PickupController : MonoBehaviour6{7 void Update()8 {9 // Rotate based on dT to ensure constant position updates10 var rotation = new Vector3(15, 30, 45) * Time.deltaTime;11
12 transform.Rotate(rotation);13 }14}Prefabs
A Prefab is an asset that functions as a Game Object template. Prefabs can be accessed in different scenes, and we can make a change to a single instance or to the Prefab itself and it will update across scenes if we update a single object
To create a Prefab select the Game Object from the heirarchy into the Assets/Prefabs folder. You can then double click on the prefab that was created and it will take you into the prefab editor
To contain instances of this prefab we can create an empty Game Object, e.g. PrefabParent and place instances of the Prefab within that
Collisions
We use the OnTriggerEnter function that triggers when a collision is detected, we then use the Unity Tagging system to identify what object type the collision happened with
To set a tag for an object or prefab, go to the object inspector for the Game Object, and create a new tag for the object, for example Pickup
Select the BoxCollider component’s IsTrigger property to allow for the collider to work as a collider
Collidersstop physics objects from passing through each other,TriggerCollidersnotify us when there is a contact via theOnTriggerEnterevent
We can also add a RigidBody object to prevent Unity from treating the object as static as this will be more difficult for Unity to calculate physics each frame, howver if the object has IsTrigger selected this will cause it to fall through game objects when influenced by physics, we can enable IsKinematic on the RigidBody whcih will not react to forces, but can only be moved via transforms
Once setting all the above and implementing the OnTriggerEnter function on the PlayerController so we can detect when the player collides, we will have the following:
PlayerController.cs
1using UnityEngine;2using UnityEngine.InputSystem;3
4public class PlayerController : MonoBehaviour5{6 public float Force = 1;7
8 private Rigidbody _rigidBody;9 private float _movementX;10 private float _movementY;11
12 // Start is called before the first frame update13 void Start()14 {15 // Get the RigidBody data for the object16 _rigidBody = GetComponent<Rigidbody>();17 }18
19 // FixedUpdate is called before physics calculations20 void FixedUpdate()21 {22 var movement = new Vector3(_movementX, 0.0f, _movementY);23
24 _rigidBody.AddForce(movement);25 }26
27 // Handle the OnMove event28 void OnMove(InputValue movementValue)29 {30 // Get the movement vector from the input value31 var movementVector = movementValue.Get<Vector2>();32
33 _movementX = movementVector.x * Force;34 _movementY = movementVector.y * Force;35 }36
37 // Handle event on entering a collision object38 void OnTriggerEnter(Collider other)39 {40 if (other.CompareTag("Pickup"))41 other.gameObject.SetActive(false);42 }43}Storing State Information
We may want to store state information like scores, there are a few ways we can do this, one of which would be keeping it stored in a variable on our Player object, and updating the variable when needed, for example:
1using UnityEngine;2using UnityEngine.InputSystem;3
4public class PlayerController : MonoBehaviour5{6 private int _score;7
8 // Start is called before the first frame update9 void Start()10 {11 // Get the RigidBody data for the object12 _rigidBody = GetComponent<Rigidbody>();13 _score = 0;14 }15
16 // ...17
18 // Handle event on entering a collision object19 void OnTriggerEnter(Collider other)20 {21 if (other.CompareTag("Pickup"))22 {23 other.gameObject.SetActive(false);24 _score++;25 }26 }27}Adding UI
To add some UI Text you can use the UI > TextMeshPro, we can move around text as well as use anchoring to position it in the canvas, you can additionally use shift + alt + click in the Rect Transform in the Object Inspector to change the way the position types work
To access the UI content programatically, such as the Text, we just need to add the appropriate object as an input where needed. To access the TextMeshPro object we use a property such as public TextMeshProUGUI ScoreText which we can set from the Unity UI, using this we can set the text content when our score updates like so:
PlayerController.cs
1using UnityEngine;2using UnityEngine.InputSystem;3using TMPro;4
5public class PlayerController : MonoBehaviour6{7 public TextMeshProUGUI ScoreText;8
9 // ...10
11 // Start is called before the first frame update12 void Start()13 {14 // Get the RigidBody data for the object15 _rigidBody = GetComponent<Rigidbody>();16
17 // Set the score state and UI18 _score = 0;19 SetCountText();20 }21
22 // ...23
24 // Handle event on entering a collision object25 void OnTriggerEnter(Collider other)26 {27 if (other.CompareTag("Pickup"))28 {29 // Hide Game Objects30 other.gameObject.SetActive(false);31
32 // Update score state and UI33 _score++;34 SetCountText();35 }36 }37
38 // Set the score text in the UI39 private void SetCountText()40 {41 ScoreText.text = $"{_score} pts.";42 }43}