---
tags: games
---
# Unity & Git Workshop
## Workflow
- A new feature will be implemented on a separate branch; For each user story a feature branch
- Branch name should be the name of the user story
- Feature Branches can have a ```// TODO``` and unused code but:
- Merges should remove any ```// TODO'S``` in the files
- Merges should remove unused code
- Merges should format code
- Commits should include the task number like TG-23
- This mentions show up in Taiga as well
- Use separate scenes for your story
- Scenes are hard to merge and are guaranteed to miss something if you merge incorrectly
- Ideally each user story should have a scene and a merge removes that test scene and adds the functionality to the master (or other) scene if necessary
- Use namespaces for every script
- Folders represent namespaces
- Folder structure should group things together
- Art folder for Animation, Textures, Materials, Shadergraph, VFX
- Script folder for any code related stuff
- Prefabs folder for prefab objects
- Scenes folder for Scene objects
- Plugin folder for asset packages
- Prefabs are important
- Use where possible to enable fast level design
- Every feature should be a prefab
- Character
- Spikes
- etc..
- Prefab variants
- nested Prefabs
## Git
If you're not familiar with git basics, here's a [short tutorial](https://www.youtube.com/watch?v=USjZcfj8yxE) (15min)
The [feature branch workflow](https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow) will be used, please read up on it if you're not familiar
Always open a new branch per feature for example `git checkout -b feature/spikes`
When you're done open a pull request on the github repo and send the PR link in discord


Git guide:
https://rogerdudler.github.io/git-guide/
Git UI:
https://www.sourcetreeapp.com/
https://www.gitkraken.com/b
https://desktop.github.com/
## Unity
### Interface

- Scene View: Allows placement and movement of GameObjects in the Scene
- Game View: Previews how the player will see the scene from the camera
- Inspector: Provide details on the selected GameObject in the scene.
- Assets / Project: All prefabs, textures, models, scripts etc are stored here
- Hierarchy: Enables nesting and structuring of GameObjects within the scene
### Project Organization pointers
- Use empty game objects within your scene to group together like items. An example would be grouping all your buildings/trees/terrain into a group called "Environment". This not only makes it easier to find objects, but also makes it easier to disable/enable groups of objects.
- On a similar note, use empty game objects as parent objects for things like meshes. When possible avoid placing scripts or components on meshes directly. Using an empty parent makes it easy to modify the mesh without having to recreate/add the components. It also allows you to control the position/rotation of mesh objects while keeping the parent consistent.
- Create a standard folder structure in your project panel. Below is an image of how I typically arrange my folders. Names are up to you, but try to be consistent.
- Avoid ambiguous naming of files. Name things what they are. If you have a trash can prop, name it "TrashCan_Prop". Anyone should be able to browse through your scene hierarchy or project panel and have a good understanding of what the object should be based on the name alone.
### Unity Game Objects
#### What are GameObjects
GameObjects are the core building block of everything in the Unity games engine. The name almost gives it away:
- Anything you place within a scene in Unity must be wrapped in a game object.
If you’ve got a web design background, you can think of GameObjects as being a lot like ```<div>``` elements! Extremely boring containers, but are highly extensible to create complex functionality or visuals.
#### Creating Hierarchy
Like a ```<div>``` in web development, a GameObject is also a container. Just as you nest ```<div>```s to create varied and desirable layouts or abstractions you may wish to do the same with games objects.
#### Key Built-in Components
A few example components:
- MeshFilter: Allows you to assign materials to a 3D mesh to a GameObject
- MeshRender: Allows you to assign materials to a 3D Mesh
[Box | Mesh]
- Collider: Enables detection of GameObject during collisions
- Rigidbody: Enables realistic physic simulation to act on GameObjects with 3d Meshes and will be trigger detection events on box colliders
- Light: Illuminates portions of your scene
- Camera: Defines the player viewport to be attached to a GameObject
- Various UI Canvas Components for displaying GUIs
Loads more..
#### Creating Custom Components
To start creating components, go into the desired GameObject > Add Component > type the name of your new component in the search bar > new script (c#).
### Structure of MonoBehaviour and other useful things
#### Key Functions
All components inherit from the MonoBehaviour Class. It includes several standard methods, most importantly:
- ```void Start()``` which is called whenever an object containing the script is instantiated in the scene. This is useful anytime we want to perform some initialisation code, eg. set a player’s equipment after they spawn into a match.
- ```void Update()``` which is called every frame. This is where the bulk of code involving user input will go, updating various properties such as the motion of the player in the scene.
- ```void FixedUpdate()``` has the frequency of the physics system; it is called every fixed frame-rate frame. Compute Physics system calculations after FixedUpdate. 0.02 seconds (50 calls per second) is the default time between calls.
- ```LateUpdate()``` LateUpdate is called every frame, if the Behaviour is enabled. LateUpdate is called after all Update functions have been called.
- ```OnGUI()```
- ```OnDisable()```
- ```OnEnable()```
#### Inspector Variables
Often we want to make components as flexible as possible. For example all weapons might have a different damage, rate of fire, has_sight etc. Whilst all the weapons are essentially the same thing we may want to be able to create different variations quickly through the unity editor.
Another example where we might want to do this is when creating a UI component that tracks user mouse movements and places a cursor in the viewport. Here we might want to control the sensitivity of the cursor to movements (if the user was using a joystick or gamepad vs a computer mouse). Thus it would make sense to have these variable easy to change both in edit mode and also experiment with them during runtime.
We can do this easily by simply declaring them as ```public``` variables in the body of the component.
#### Accepting user input
Of course, we want our game to respond to user input. The most common ways to do that are using the following methods in the Update() function of a component (or anywhere else you like):
- ```Input.GetKey(KeyCode.W)``` Returns True W key is being held down
- ```Input.GetKeyDown(KeyCode.W)``` Returns True when W key is first pressed
- ```Input.GetAxis(“Vertical”)```, ```Input.GetAxis(“Horizontal”)``` Returns between -1,1 mouse input movement
#### Manipulating GameObjects
Once we have user input we want GameObjects within our scene to respond. There are several types of responses we may consider:
- Translation, Rotation, Scale
- Create new GameObjects
- Sending messages to existing GameObjects / components
#### Transformations
GameObjects all have a transform property which enable various useful manipulations on the current game object to be performed.
```csharp
gameObject.transform.Translate(new Vector3(0,0,0));
gameObject.transform.Rotate(new Vector3(180,0,0));
gameObject.transform.localScale = 2;
// localPosition
// localScale
// localRotation.eulerAngles
```
In general it’s a good practice to use local[Position,Rotation] rather than the global position / rotation of an object. This usually makes it easier to move objects in a manner that makes sense, as the local space axis will be oriented and centered on the parent object rather than the world origin and x,y,z directions.
If you need to convert between local and world space (which often is the case) you can use the following:
```csharp
// world space to local space
gameObj.transform.InverseTransformPoint(new Vector3(0,0,0));
// convert direction in world space to the direction in a rotated local space
gameObj.transform.InverseTransformDirection(Vector3.forward);
```
#### Creating new GameObjects
Since GameObjects are basically everything in your scene, you might want to be able to generate them on the fly. For example if your player has some sort of projectile launcher you might want to be able to create projectiles on the fly which have their own encapsulated logic for flight, dealing damage, etc…
First we need to introduce the notion of a Prefab. We can create these simply by dragging any GameObject in the scene hierarchy into the assets folder. This essentially stores a template of the object we just had in our scene with all the same configurations.
We can then perform ‘instantiation’ of the prefab and manipulate it to the desired location in the scene and establish the necessary parent relationships.
```csharp
GameObject instance = Instantiate(prefab_onject);
// set position and parent
instance.transform.position = new Vector3(0,0,0);
instance.transform.parent = transform.parent;
```
More to prefabs here:
https://docs.unity3d.com/Manual/Prefabs.html
#### Accessing other GameObjects and Components
Often we need to communicate with other GameObjects as well as their associated components. Once you have a reference to a game object this is pretty simple.
```csharp
ComponentName comp = some_game_object.GetComponent<ComponentName>();
```
#### Access via tagging
We can tag GameObjects or prefabs via the inspector and then use the find game object functions to locate references to them.
```csharp
GameObject some_game_object = GameObject.FindGameObjectWithTag(“Brick”);
```
#### Access via transform
If we wish to access components in some parent object we can easily do this via the transform attribute.
```csharp
ComponentName comp = gameObject.transform.parent.GetComponent<ComponentName>();
```
#### Access via SendMessage
Alternatively if we want to send a message to many other components or wish to message an object which is far up a nested hierarchy, we can use the send message functions, which accept the name of the function followed by the arguments.
```csharp
gameObject.SendMessage(“MethodName”,params); // Broadcast message
gameObject.SendMessageUpwards(“MethodName”, params); // Only received by components which are nested above.
```
#### Raycasting
You may have heard of this before when people compare FPS games that are ‘physics based’ or ‘ray based’. Raycasting is essentially like having a laser pointer which, when it comes into contact with a ‘collider’ or ‘rigidbody’, it returns a ‘hit’ and passes back the details of the object.
There are two scenarios where this comes in handy (There’s probably loads more):
- If you were designing a weapon system for a game, you could use raycasting for hit detection, and even customise the length of the ray so that melee items ‘hit’ only at short ranges
- Create a ray from the mouse pointer to a point in 3d space, ie if you wish the user to be able to select units with their mouse in a strategy game.
```csharp
void Update() {
RaycastHit hit;
// Setup a ray to be cast taking the mouse position in screen space
// and convert to ray direction in 3d space
Ray ray = Camera.allCameras[0].ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, Mathf.Infinity)) {
// hit.transform, etc..
}
}
```
#### Collision detection
Above Collider and Rigidbody components were mentioned, which can be added to an object. The rule for collisions is that one object in the collision must have a rigidbody and the other a collider (or both have both components). Note that when using raycasting, rays will only interact with objects with collider components attached.
Once setup within any custom component attached to the object, we can use the OnCollisionEnter, OnCollisionStay and OnCollisionExit methods to respond to collisions. Once we have the collision information we can get the GameObject responsible and use what we learned earlier to interact with components attached to it as well.
```csharp
private void OnCollisionEnter(Collision collision) {
GameObject collideWith = collision.gameObject;
}
```
One thing to note is that rigid-bodies provide physics such as gravity for objects, so if you want this turned off you will need to check the ```is_kinematic``` on -> Forces, collisions or joints will not affect the rigidbody anymore.
Unity Collider Overview:
https://docs.unity3d.com/Manual/CollidersOverview.html
https://docs.unity3d.com/Manual/LayerBasedCollision.html
#### Extending the Unity Editor
Unity enables you to add custom buttons to your inspectors so that you can affect the world during edit mode. For example, to help with world building you might develop a custom tool window for building modular houses.
```csharp
namespace Project.CustomInspector
{
[CustomEditor(typeof(SomeClass))]
public class SomeClass_Inspector : Editor
{
private SomeClass t;
private SerializedObject GetTarget;
private SerializedProperty SomeProperty;
private int ListSize;
private void OnEnable()
{
t = (SomeClass) target;
GetTarget = new SerializedObject(t);
// Find the List in our script and create a reference of it
SomeProperty = GetTarget.FindProperty("SomeProperty");
}
public override void OnInspectorGUI()
{
// base is standard on gui
base.OnInspectorGUI();
// Examples:
EditorGUILayout.Space();
EditorGUILayout.LabelField("General Settings", EditorStyles.boldLabel);
using (new EditorGUILayout.VerticalScope("Box"))
{
if (SomeProperty.boolValue =
EditorGUILayout.Toggle("Bool checkbox", OneAudioSource.boolValue))
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(OtherSerializedProp, new GUIContent("SomeOtherStuff"));
EditorGUI.indentLevel--;
}
}
// Update the serializedProperty - always do this in the beginning of OnInspectorGUI.
serializedObject.Update();
// Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI.
serializedObject.ApplyModifiedProperties();
}
}
}
```
#### Materials and PBR
Unity runs off a physically-based rendering engine which enables real time lighting and realistic materials. The reality is you will either need to learn 3d modeling first or use models made and optimised by someone else before you get to this, in order to make stuff that actually looks good.
#### Animation
Unity has a graph-based animation system which enables you to blend and control animations on various objects such as players implementing a bone based animation system.
## Game development pipeline
### Speed up development
Follow these best practices to speed up development and boost the quality of the final product.
#### Set up correct version control
- Use text serialization (by default in Unity).
- Set up built-in YAML merge tool. See more about SmartMerge here.
- Set up commit hooks. See more here.
#### Use the Cache Server
- Switching platforms decreases development speed.
- Make sure to set up the Cache Server for your team.
#### Avoid storing static data in JSON or XML files
- This results in slow loading.
- Parsing generates garbage.
- Instead, for built-in static data use ScriptableObjects with custom editor tools.
Don’t leave unused assets, plugins and duplicated libraries in your project
Unused assets in your project can still be built into the game. Make sure that you don’t leave garbage in your project: if you set up a version control system, restoring files should be easy.
- Check what dependencies assets from the Asset Store drag into the project. For example, you might be surprised to find that you have five different JSON libraries in the project.
- Check for outdated assets and scripts from early prototypes.
- Moving old assets to the “removed” folder still results in resources and scripts being built into the game.
#### Repetitive actions require manual work
- For every repetitive task there should be a script automating it.
- Make sure that you can “play” the game or interactive content from any scene.
- Consider a solution, such as Cloud Build, that automates the build process.
#### More tips:
How to set up a stable and flexible build pipeline:
https://unity3d.com/how-to/set-up-a-stable-build-pipeline
Profile your project on target devices as well as in the editor
- Always profile the content on your target device; if you profile in the editor only, you can miss performance bottlenecks.
- 
#### Unity Profiler
Use both built-in and platform-specific profiling and debugging tools
Here are resources to learn about Unity’s profiling tools:
- The Profiler
- The Profiler Analyzer
- The Memory Profiler
- Understanding optimization in Unity
- Optimizing graphics performance
- General best practices (including extensive tips on optimizing Unity’s UI system)
Profile and optimize early on:
- The longer you wait with profiling, the larger the performance costs can become.
- Start profiling early on, so you’re sure your project fits into the frame, memory and disk size budgets.
- Profile before your optimize, so that you have the data you need to optimize actual bottlenecks.
Make sure you know as much as possible about your target platform(s)
- Desktop, mobile and console platforms have very different bottlenecks.
### Choose the correct Asset settings
Assets take up most of the size of your game. Save time on optimizing by thinking carefully about Asset settings.
Set up Sprite Atlases correctly:
- Make sure that you use Sprite Atlases for sprites used together in a scene. This will reduce the number of draw calls in the game/interactive content.
- https://docs.unity3d.com/Manual/class-SpriteAtlas.html
- Or, consider using Tilemap, which can improve performance of 2D games. Get some tips for optimizing with Tilemaps here.
- https://unity3d.com/how-to/move-fast-and-save-time-in-Unity
Set up texture settings correctly:
- Make sure that you know the right texture settings for the target platform:
- What compression does the platform support?
- Do the textures need mip maps?
- Set up an automated way to apply these settings for new textures using AssetPostprocessor API as shown by this project.
- https://github.com/MarkUnity/AssetAuditor
- Prevent artists from committing textures with wrong settings.
#### Unity Asset import settings
Try the Addressable Asset System
The new Addressable Asset System provides a framework to solve a set of common problems related to addressing, building, and loading assets. It handles asset management overhead by simplifying content pack creation and deployment. Try these resources for more information:
From the Blog: Addressable Asset System
https://blogs.unity3d.com/2019/07/15/addressable-asset-system/
From the Docs: Addressable Asset System docs
https://blogs.unity3d.com/2019/07/15/addressable-asset-system/
From Unite: Addressables for live content management
https://docs.unity3d.com/Packages/com.unity.addressables@0.3/manual/index.html
### Boost programming productivity
Boost productivity with best practices for code architecture.
Know how to use your code editor efficiently
- Make sure to know all the features and shortcuts of your code editor as it can speed up everyday tasks.
- If you use Visual Studio, see this video on tips and tricks when working with a Unity project. Or, watch this video for tips on JetBrains Rider.
- https://www.youtube.com/watch?v=MBWc4oRBwiE
- https://www.youtube.com/watch?v=2CvSoo0hlWI
Avoid abstract code
- Abstract Enterprise code is rarely justified because it runs slowly and requires IL2CPP to generate more code.
Establish and document clear architectural conventions:
- When writing code, don’t use different methods to accomplish the same task, e.g.
- Config formats (files, properties, assets).
- Events (Unity events, C# events, SendMessage).
- Define which manager is responsible for which objects?
Understand the Unity frame loop
- When Awake, OnEnable, Update and other methods are called.
- When coroutines are updated.
- How FixedUpdate is executed.
Avoid relying on Unity execution order for script initialization logic
- When a MonoBehaviour is instantiated during the game Unity calls its Awake and Start methods. While the game is simple enough the order in which MonoBehaviours are initialized when the first scene is loaded might not matter. Later you might want to change this order using the Script Execution Order list in Project Settings. But once you have more than a few scripts in this list, relying on it can make it a source of hard-to- track bugs. In this case you should create a script which calls initialization functions for all your other MonoBehaviours at startup.
Account for framerate when scripting logic or animation
- Use Time.deltaTime for FPS independent scripts.
More tips:
3 ways to architect with Scriptable Objects
https://unity.com/how-to/architect-game-code-scriptable-objects
Have a better scripting experience
https://unity3d.com/how-to/better-scripting-experience
### Optimize CPU Performance
Optimize CPU usage for smooth performance and a longer battery life.
Use Update() method sparingly:
- Native -> Managed calls have some overhead. Use custom managers instead
- Avoid having custom Behaviours inherit from an abstract class with Update/Awake/Start methods defined
Define how frequently you need to update different systems in your game
Not all systems need to be updated every frame. Areas to look at include:
- Moving objects.
- AI and pathfinding.
- Logging and saving game state.
- Other "heavy" systems.
Cache data you need frequently, such as:
- Reflection
- Find()
- Camera.main
- GetComponent()
Pool frequently instantiated objects
- Instantiating objects is slow.
- Create pools of objects at the start of the game/content.
- Reuse objects instead of creating new ones.
Don’t allocate memory for every frame
- Small allocations every frame will cause a GC spike.
- Try to eliminate ALL allocations.
Try alternatives to memory-allocating APIs, such as:
- LINQ.
- String concatenation.
- Unity APIs returning arrays:
- Physics.RaycastAll, Mesh.vertices, GetComponents, etc.
More tips:
1K update calls
https://blogs.unity3d.com/2015/12/23/1k-update-calls/
Unity’s evolving best practices
https://unity3d.com/how-to/unity-best-practices-for-engine-performance
### Optimize GPU Performance
Avoid spikes in graphics performance with these tips.
You can also use the Unity GPU Profiler.
Avoid overdraw in mobile games because it causes performance bottlenecks
- Mobile GPUs can only draw so many pixels per second.
- Don’t draw unnecessary transparent images.
- Use more complex meshes to crop fully transparent areas.
Use the Universal Render Pipeline for your shaders in mobile projects
- Use the shaders that are compatible with the Universal Render Pipeline (formerly known as the Lightweight Render Pipeline).
- When using Shader Graph, make sure to set Precision to half where full precision is not needed; this will make your shaders more performant.
- https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@7.0/manual/index.html
Watch for incorrect settings that can break dynamic batching
- Objects must be “similar” to be dynamically batched.
- The Frame Debugger shows why certain objects were not batched.
- Use the SRP Batcher with the Universal Render Pipeline to increase the number of batched objects.
- https://docs.unity3d.com/Manual/FrameDebugger.html
- https://docs.unity3d.com/Manual/SRPBatcher.html
Set up LODs correctly
- LODs enable economic rendering of objects further from the camera.
More tips:
Why your draw calls are not batched
https://blogs.unity3d.com/2017/04/03/how-to-see-why-your-draw-calls-are-not-batched-in-5-6/
Mobile optimization best practices
https://docs.unity3d.com/Manual/BestPracticeUnderstandingPerformanceInUnity.html
### Optimize UI Performance
Account for different resolutions and aspect ratios
- Test UI on devices with different resolutions and aspect ratios
- Sometimes it is better to create different UI screens for different devices
Move animated elements to separate Canvases
- The Canvas creates a new combined mesh when an element changes, which can be costly for complex Canvases.
Avoid lag when a new UI window is opened
Your game experiences lag when a new window or a big chunk of UI is created. Minimize this effect by:
- Making UI windows less complex.
- Splitting UI in parts.
- Caching windows.
Make sure your lists don’t contain a large amount of items
- Dynamically reuse list items instead of creating all of them at once.
- Create a nested Canvas in the list.
- Use open source implementations, such as this.
- https://github.com/boonyifei/ScrollList
See:
Unity UI optimization tips
https://unity3d.com/how-to/unity-ui-optimization-tips
## Advanced
### Bone Animation


https://blogs.unity3d.com/2018/11/09/getting-started-with-unitys-2d-animation-package/
https://www.youtube.com/watch?v=eXIuizGzY2A
### Localization
https://levelup.gitconnected.com/unity-advanced-localization-802cb954ca16
### Dark Mode
https://levelup.gitconnected.com/unity-implementing-dark-mode-9715ac8ac715
### Complex Gravity
https://catlikecoding.com/unity/tutorials/movement/complex-gravity/
### Custom Gravity
https://catlikecoding.com/unity/tutorials/movement/custom-gravity/
### Orbit Camera
https://catlikecoding.com/unity/tutorials/movement/orbit-camera/
### Rendering
https://catlikecoding.com/unity/tutorials/rendering/
https://catlikecoding.com/unity/tutorials/advanced-rendering/
### Hex Map
https://catlikecoding.com/unity/tutorials/hex-map/
### Pseudorandom Noise
https://catlikecoding.com/unity/tutorials/pseudorandom-noise/
### Shaders
A gentle introduction to shaders
https://www.alanzucconi.com/2015/06/10/a-gentle-introduction-to-shaders-in-unity3d/
Volumetric rendering in unity
https://www.alanzucconi.com/2016/07/01/volumetric-rendering/
Atmospheric Scattering Shader
https://www.alanzucconi.com/2017/10/10/atmospheric-scattering-7/
Fast Subsurface Scattering in Unity
https://www.alanzucconi.com/2017/08/30/fast-subsurface-scattering-2/
### Shadergraph
Youtube playlist:
https://www.youtube.com/watch?v=M0qIXGiL5kM&list=PLVmb_qp6XRczuNNbmr_nSPVUH3OOTrkjB
### VFX graph
https://unity.com/visual-effect-graph
https://www.youtube.com/watch?v=7bMOhNUA1bI
https://www.youtube.com/watch?v=keVozyJAIUM
https://www.youtube.com/watch?v=FvZNVQuLDjI
### DOTween
Package for interpolating any value, i.e. Position
https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676
### Entity Component System / DOTS - Data Oriented Tech Stack
The new Unity way.
https://unity.com/dots
Complete First Person Shooter Multiplayer Project:
https://github.com/Unity-Technologies/DOTSSample