Download as pdf or txt
Download as pdf or txt
You are on page 1of 45

The Relevant Unity’s Stuff

simonsanchezart.com/the-relevant-unity-stuff/2048

By Simon May 6, 2020

The objective of this post is to gather all the fundamental concepts that you and me could
want to check out if we get stuck in something. Things like how to loop over all the
elements in a dictionary, how to create an enum, the difference between const and
readonly and so on.

(The information here is not the most optimal or exact, it’s what I know at this point and
time and will be updated. For feedback, please leave a comment!)

Index

Executions

OnValidate()
Gets called when it gets loaded or when a value is changed in the inspector.

LateUpdate()
Executes after all the code inside Update() gets executed, useful when making, for example
a Camera Follow, as the camera needs to follow a character after this character was moved
in Update().

Awake()
Gets called even if the script is not enabled. (Before Start())

FixedUpdate() vs Update()
Update is called each frame, FixedUpdate is called every x physics step, FixedUpdate
should be used when manipulating physics or rigidbodies, specially if those manipulations
are over time and not single-framed.

Debugging

Formatted logs

1/45
1 Debug.LogFormat( "The age of {0} is {1}, it's {2} that he has a pet" ,
nameString, ageInt, petBool);

1 int age = 10;


2 Debug.Log($ "My age is
3 {age}" );

Pretty logs

1 Debug.Log( "<b>This</b> <i>is a word</i>, this is <size=8>another</size>


2 word and so on" );
Debug.Log( "This is a word, <b><color=green>this is another</color></b> word
3 and so on" );

Throwing exceptions

1 public void ValidateEmail( string email)


2 {
3 if (!email.Contains( "@" ))
4 {
5 throw new System.ArgumentException( "Not a valid
email" );
6
Debug.Log( "Inaccessible" )
7 }
8 }
9

Try-catch

2/45
1 try
2 {
ValidateEmail( "ea" );
3 Debug.Log( "Email validated" );
4 }
5 catch (System.ArgumentException exceptionVariable)
6 {
7 Debug.Log( "Unsuccessful attempt, " +
8 exceptionVariable.ToString());
9 }
finally
10 {
11 Debug.Log( "Email validator ran" );
12 }
13
14
15
16
17

Syntax

Member naming

1 public int PlayerAge { get ; set ; };


2 public int playerAge;
3 [SerializableField] int _playerAge;
4 int p_playerAge;
5

If’s

Switch statement

3/45
1 int caseSwitch = 1;
2 switch (caseSwitch)
3 {
4 case 1:
5 Console.WriteLine( "Case 1" );
break ;
6
case 2:
7
Console.WriteLine( "Case 2" );
8 break ;
9 default :
10 Console.WriteLine( "Default case" );
11 break ;
12 }
13
14

Fall-through

1 switch (values)
2 {
3 case Numbers.x:
4 case Numbers.x1:
5 print( "For both x and
x1" );
6 break ;
7 case Numbers.y:
8 case Numbers.y1:
9 print( "For both y and
10 y1" );
11 break ;
12 }

Ranges in Switch

4/45
1 int age = 25;
2 switch (age)
3 {
4 case int n when (n >= 18 &amp;&amp; n
5 <=25):
print( "You're between 18 and 25" );
6
break ;
7 default :
8 print( "You're older than 25" );
9 break ;
10 }
11
12

Ternary operator

1 message = health > 0 ? "Player is alive" : "Player is


2 dead" ;
3

Loops

For loop

1 for ( int i = 100; i > 0; i--


2 )
3 {
if (i % 2 == 0)
4
{
5 print(i);
6 }
7 }
8

Do-while loop
Runs at least once, then checks if the condition is true to run again.

5/45
1 int i = 0;
2 do
3 {
print(i);
4
i++;
5 } while (i < 50);
6
7

While loop

1 bool isDead = false ;


2 while (!isDead)
3 {
4 Kill();
isDead = true ;
5
}
6
7

Break
Used to stop a loop.

1 for ( int i = 0; i < 100;


2 i++)
3 {
print(i);
4 if (i == 50)
5 {
6 break ;
7 }
8 }
9

Continue
Instead of stopping the loop completely, stops the current iteration (based on a condition.)

Loop over array/list with For

1 for ( int i = 0; i < names.Length; i++)


2 {
3 print(names[i]);
}
4
5
6/45
Loop over array/list with Foreach

1 foreach ( var name in names)


2 {
3 print(name);
}
4

Loop over dictionary

1 foreach (KeyValuePair< int , Item> item in itemDatabase)


2 {
3 Debug.Log(item.Key);
Debug.Log(item.Value.name);
4
}
5

Nested loops

1 for ( int x = 0; x < 10; x++)


2 {
3 for ( int y = 0; y < 10; y++)
4 {
5 Debug.Log( "x: " + x + " y: " +
y);
6 }
7 }
8
9
10
11
12
13

Methods

Return type

7/45
1 [SerializeField] int total;
2 void Start()
3 {
4 total = Sum(1, 1);
}
5
int Sum( int a, int b)
6 {
7 return a + b;
8 }
9
10
11
12
13

Method overriding

1 public class Pet : MonoBehaviour


2 {
3 protected string petName;
4 protected virtual void Speak()
5 {
Debug.Log( "Speak" );
6
}
7 void Start()
8 {
9 Speak();
10 }
11 }
12
13
14
15
16
17

1 public class Dog : Pet


2 {
3 protected override void Speak()
4 {
Debug.Log( "Bark Bark!" );
5 }
6 }
7
8
9
10
8/45
Invoke

1 Invoke( "Method" , 2);


2 InvokeRepeating( "Method" , 2,
1);
3 CancelInvoke();
4 CancelInvoke( "Method" );
5
6
7
8
9
10
11

Invoking without direct string (nameof)

1 void Start()
2 {
3 Invoke(nameof(DebugTest), 1f);
}
4
void DebugTest()
5 {
6 Debug.Log( "No strings
7 attached" );
8 }
9
10
11
12
13

Method overloading

1 public int Add( int num1, int num2)


2 {
3 return num1 + num2;
4 }
5 public string Add( string text1, string text2)
{
6
return text1 + text2;
7 }
8
9
10

Extension methods
9/45
1 public static class ExtensionMethods
2 {
3 public static void ResetTransform( this Transform
4 trans)
{
5 trans.position = Vector3.zero;
6 trans.localRotation = Quaternion.identity;
7 }
8 }
9

1 public class AnotherClass : MonoBehaviour


2 {
3 void Start()
4 {
transform.ResetTransform();
5 }
6 }
7
8
9

Types, classes and structs

Arrays

1 string [] names;
2 string [] names = new string [5];
3 string [] names = new string [] { "Jonathan" , "Simon" , "Alicia" ,
4 "Lila" };
5

Lists

1 List<GameObject> enemiesToSpawn = new List<GameObject>


2 ();

Add an element

1 list.Add(element)
2

10/45
Insert element at x index

1 list.Insert(1, "George" );
2
3

Enums

1 [SerializeField] enum LevelSelector


2 {
3 Easy,
Normal,
4
Hard
5 }
6 [SerializeField] LevelSelector currentLevel;
7 void Start()
8 {
9 switch (currentLevel)
10 {
11 case LevelSelector.Easy:
12 Debug.Log( "Selected 'Easy' " );
break ;
13 case LevelSelector.Normal:
14 Debug.Log( "Selected 'Normal' " );
15 break ;
16 case LevelSelector.Hard:
17 Debug.Log( "Selected 'Hard' " );
18 break ;
19 }
}
20
21
22
23
24
25

Enum value type

11/45
1 enum Example = { Alive, Tired, Dead };
2 enum Example = { Alive = 2, Tired, Dead };
3 enum Example = { Alive = 5, Tired = 13, Dead = 2
4 };
5 enum Example : byte = { Alive, Tired, Dead };
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Casting enum to int

1 enum Difficulty
2 {
3 Easy,
Normal,
4
Hard
5 }
6 [SerializeField] Difficulty selectedDifficulty;
7 void Start()
8 {
9 SceneManager.LoadScene(( int )selectedDifficulty);
10 }
11
12
13
14

Dictionaries

12/45
1 public Dictionary< int , Item> itemDatabase = new Dictionary< int ,
2 Item>();
3 void Start()
4 {
5 Item sword = new Item();
sword.name = "Sword" ;
6 sword.id = 0;
7 Item bread = new Item();
8 bread.name = "Bread" ;
9 bread.id = 0;
10 itemDatabase.Add(0, sword);
11 itemDatabase.Add(1, bread);
}
12
13
14
15
16
17
18
19

Get value from key

1 void Start()
2 {
3 var value =
4 students[ "Juan" ];
print(value);
5 }
6

Get key from value

13/45
1 var key = students.FirstOrDefault(s => s.Value ==
2 15).Key;
3 print(key);
4 var secondKey = ( from s
5 in students
6 where s.Value == 14
7 select s).FirstOrDefault().Key;
print(secondKey);
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

Dictionary collection initializer

1 Dictionary< string , int > students = new Dictionary< string , int >()
2 {
3 { "Juan" , 14},
{ "Matilda" , 21},
4 { "Romero" , 18}
5 };
6
7

Use of serialized classes


(Might wanna use a ScriptableObject to store this kind of data instead)

14/45
1 [System.Serializable]
2 public class Item
3 {
4 public int itemID;
5 public string name;
6 public string description;
}
7
public class array : MonoBehaviour
8
{
9 public Item[] myItems;
10 void Update()
11 {
12 if (Input.GetKeyDown(KeyCode.Space))
13 {
14 foreach ( var item in myItems)
15 {
16 print(item.itemID);
17 print(item.name);
print(item.description);
18 }
19 }
20 }
21 }
22
23
24
25
26
27

Class Inheritance

1 [System.Serializable]
2 public class Items
3 {
4 public string name;
5 public int index;
6 public string description;
7 public Sprite image;
}
8
9
10
11
12
13

15/45
1 [System.Serializable]
2 public class Weapons : Items
3 {
4 public int damage;
5 public int bleed;
}
6

1 [System.Serializable]
2 public class Consumables : Items
3 {
4 public int health;
5 public int poison;
}
6

1 public class ItemDatabase : MonoBehaviour


2 {
3 [Space(10)]
4 public Items[] otherItems;
[Space(10)]
5
public Weapons[] weapons;
6 [Space(10)]
7 public Consumables[] consumables;
8 }
9
10

16/45
Abstract classes
They cannot be instantiated by themselves, and they can force the declaration of methods
to the classes that implement them.

1 public abstract class Employee : MonoBehaviour


2 {
3 public string companyName;
4 public string employeeName;
5 public abstract void CalculateMonthlySalary();
6 }
7
8

17/45
1 public class Fulltime : Employee
2 {
3 [SerializeField] int earnedPerDay;
4 void Start()
5 {
CalculateMonthlySalary();
6 }
7 public override void CalculateMonthlySalary()
8 {
9 Debug.Log(employeeName + " will earn: $" + earnedPerDay *
10 24);
11 }
12 }
13
14

1 public class PartTime : Employee


2 {
3 [SerializeField] int hoursWorked;
4 [SerializeField] int hourlyRate;
5 void Start()
6 {
CalculateMonthlySalary();
7 }
8 public override void CalculateMonthlySalary()
9 {
10 int salary = hoursWorked * hourlyRate;
11 Debug.Log(employeeName + " will earn: $" +
12 salary);
13 }
14 }
15
16

Interfaces

1 public interface IDamageable<T>


2 {
3 int health { get ; set ;}
4 void TakeDamage(T damageAmount);
5 }
6

18/45
1 public class Player : MonoBehaviour,
2 IDamageable< int >
3 {
4 int IDamageable.health { get ; set ; }
5 void IDamageable.TakeDamage( int damageAmount)
{
6 }
7
8
9
10

Const vs readonly

1 const int maxHealth =


2 100;
3 readonly int maxHealth;
4
5

Ref Keyword
To pass arguments as reference instead of value in methods, they need to be initialized
before being passed into the method, properties with get and set can’t be used as ref.
You’re not obligated to update the reference parameter.

1 public static string UpdateDeathCount( ref int countReference)


2 {
3 countReference++;
4 return "Next time you'll be at number " + countReference;
}
5
public static void DebugDeath()
6 {
7 Debug.Log( "Player deaths: " + playerDeaths);
8 string message = UpdateDeathCount( ref playerDeaths);
9 Debug.Log( "Player deaths: " + playerDeaths);
10 }
11
12

Out keyword
Same as ref, but arguments don’t need to be initialized before passing into the method, but
you need to initialize the parameter before returning the method.

19/45
1 public static string UpdateDeathCount( out int countReference)
2 {
3 countReference = 1;
countReference++;
4
return "Next time you'll be at number " + countReference;
5 }
6 public static void DebugDeath()
7 {
8 Debug.Log( "Player deaths: " + playerDeaths);
9 string message = UpdateDeathCount( out playerDeaths);
10 Debug.Log( "Player deaths: " + playerDeaths);
11 }
12
13
14
15
16

Singleton pattern
Useful in cases you only have one instance of a class, for example in managers.

20/45
1 static GameManager _instance;
2 public static GameManager Instance
3 {
4 get
{
5 if (_instance == null )
6 {
7 Debug.LogError( "There's in no GameManager
8 instance" );
9 }
10 return _instance;
}
11
}
12 void Awake()
13 {
14 _instance = this ;
15 }
16 public void MethodExample( string text)
17 {
18 Debug.Log(text);
}
19
20
21
22
23
24
25
26
27
28
29

1 void Start()
2 {
3 GameManager.Instance.MethodExample( "This is a
test" );
4 }

Lazy Instantiation

21/45
1 get
2 {
if (_instance == null )
3
{
4 GameObject go = new
5 GameObject( "SpawnManager" );
6 go.AddComponent<SpawnManager>();
7 }
8 return _instance;
}
9
10
11
12
13

The disadvantage of lazy Instantiation is that you will need to find a way to dynamically
populate fields in the class if you’re instantiating the manager.

Non-Monobehavior Singleton

1 public class GameManager


2 {
3 #region "Singleton"
4 static GameManager _instance;
5 public static GameManager Instance
{
6 get
7 {
8 if (_instance == null )
9 {
10 _instance = new GameManager();
11 Debug.LogWarning( "There was no " + nameof(GameManager) + " instance,
12 an instance was created." );
13 }
14 return _instance;
}
15
}
16 #endregion
17
18

Detecting an interface with Raycast

22/45
1 void Update()
2 {
3 if (Input.GetMouseButtonDown(0))
4 {
Ray rayOrigin = Camera.main.ScreenPointToRay(Input.mousePosition);
5 RaycastHit hit;
6 if (Physics.Raycast(rayOrigin, out hit))
7 {
8 IDamageable obj = hit.collider.GetComponent<IDamageable>();
9 if (obj != null )
10 {
11 obj.TakeDamage(509);
}
12
}
13 }
14 }
15
16
17
18
19
20
21
22

1 public class Player : MonoBehaviour, IDamageable


2 {
3 int IDamageable.health { get ; set ; }
4 void IDamageable.TakeDamage( int damageAmount)
5 {
this .GetComponent<MeshRenderer>().material.color = Color.red;
6 }
7 }
8
9

Delegates

1 public delegate void ChangeColor(Color newColor);


2 public ChangeColor onChangeColor;
3 public delegate void OnComplete();
4 public OnComplete onComplete;
5 void Start()
6 {
7 onChangeColor = UpdateColor;
onChangeColor(Color.green);
8 onComplete += Task;
9 onComplete += Task2;
10 onComplete += Task3;
23/45
11 if (onComplete != null )
12 {
13 onComplete();
}
14 }
15 public void UpdateColor(Color colorToUse)
16 {
17 Debug.Log( "Changing color to: " + colorToUse);
18 }
19 public void Task()
20 {
21 Debug.Log( "Completed Task 1" );
}
22
public void Task2()
23
{
24 Debug.Log( "Completed Task 2" );
25 }
26 public void Task3()
27 {
28 Debug.Log( "Completed Task 3" );
29 }
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

Events

24/45
1 public delegate void ActionClick();
2 public static event ActionClick
3 onClick;
4 public void ButtonClick()
5 {
if (onClick != null )
6 {
7 onClick();
8 }
9 }
10
11
12
13
14

1 void OnEnable()
2 {
3 Main.onClick += TurnRed;
}
4
public void TurnRed()
5 {
6 GetComponent<MeshRenderer>().material.color = Color.red;
7 }
8 void OnDisable()
9 {
10 Main.onClick -= TurnRed;
11 }
12
13
14
15
16
17

Actions

1 using System;
2 public class Actions : MonoBehaviour
3 {
4 public static Action< int > OnDamageReceived;
5
6
7
8
9
10
25/45
Func

1 public Func< string , int >


2 CharacterLength;
3 void Start()
4 {
CharacterLength = GetCharacters;
5
int count = CharacterLength( "Simon" );
6
Debug.Log( "Number of characters: " + count);
7 }
8 int GetCharacters( string name)
9 {
10 return name.Length;
11 }
12
13
14
15
16
17
18
19
20

Lambda expressions

1 public Func< string , int >


2 CharacterLength;
3 void Start()
4 {
CharacterLength = (name) => name.Length;
5
int count = CharacterLength( "Jonathan" );
6
Debug.Log( "Number of characters: " + count);
7 }
8
9
10
11
12

Void delegate with parameters

26/45
1 public Action< int , int >
2 Sum;
3 void Start()
4 {
Sum = (a, b) =>
5 {
6 int total = a + b;
7 Debug.Log(total);
8 };
9 Sum(2, 2);
10 }
11
12
13
14
15

Void delegate with no parameters

1 public Action onName;


2 void Start()
3 {
4 onName = () => Debug.Log( "Name: " +
5 gameObject.name);
onName();
6 }
7
8

Return delegate with no parameters

1 public Func< int > GetName;


2 void Start()
3 {
4 GetName = () =>
gameObject.name.Length;
5
int nameLength = GetName();
6 Debug.Log(nameLength);
7 }
8
9

Return delegate with parameters

27/45
1 public Func< int , int , int >
2 Sum;
3 void Start()
4 {
Sum = (a, b) =>
5
{
6 return a + b;
7 };
8 int total = Sum(5,5);
9 Debug.Log(total);
10 }
11
12
13
14
15
16

Protected
They’re only accessible to the same class and the classes who inherit from that class.
The difference between protected and private, is that protected allows classes to inherit
and access those variables.

Static
They’re shared with all instances of a class, static variables can be accessed without
instantiating an object of the class, if you change a static variable in one class, it will
change in all of the others.

Statics to create Utilities

1 public static class UtilityHelper


2 {
3 public static void CreateCube()
4 {
GameObject.CreatePrimitive(PrimitiveType.Cube);
5 }
6 public static void SetPositionZero(GameObject obj)
7 {
8 obj.transform.position = Vector3.zero;
9 }
10 }
11
12

28/45
1 void Update()
2 {
3 if (Input.GetKeyDown(KeyCode.Space))
4 {
UtilityHelper.CreateCube();
5 }
6 if (Input.GetKeyDown(KeyCode.E))
7 {
8 UtilityHelper.SetPositionZero( this .gameObject);
9 }
10 }
11
12

Properties
They can be read (get) only, write (set) only, or both, they can be accessed as public, at the
same time, you can make them run code when you read or write a property. You cannot
initialize them, you cannot see them in inspector (unless you’re in debug mode.)

1 public bool IsGameOver { get ; private set ;}

1 bool isGameOver
2 public bool IsGameOver
3 {
4 get
{
5
return isGameOver;
6 }
7 set
8 {
9 isGameOver = value;
10 }
}
11
12
13
14
15

Namespaces

1 using System.Collections;
2 using System.Collections.Generic;
3 using UnityEngine;

Useful to organize code, and to avoid conflicts when you have two classes with the same
29/45
name.

1 namespace WeaponPack.Magic
2 {
3 public class Weapon : MonoBehaviour
4 {
}
5 }
6
7

1 using System.Collections;
2 using System.Collections.Generic;
3 using UnityEngine;
4 using WeaponPack.Magic;
5 public class Weapon : MonoBehaviour
6 {
7 }
8
9

Trigonometry and Math

Vectors
A vector is a struct that stores three variables (x,y,z), it has a direction and a magnitude.

The magnitude is calculated with Pythagoras theorem:

Vector2(-4, 3)
Magnitude of that vector = sqrt((-4)^2 + 3^2)
Magnitude = 5

To keep the direction of the vector, but with magnitude of 1, you need to normalize it:

Vector2(-4, 3)
magnitudeOfTheVector = 5
x1 = -4 / magnitudeOfTheVector
y1 = 3 / magnitudeOfTheVector

Normalized vector = sqrt(x1^2 + y1^2)


Normalized vector = sqrt((-0.8)^2 + 0.6^2) = 1

Let’s say we want to create a vector from VectorA to VectorB:

30/45
VectorC = VectorB – VectorA

You can get the distance between VectorA to VectorB by calculating the magnitude of
VectorC. And you can get the direction from VectorA to VectorB by normalizing VectorC.

Raycasting

1 [SerializeField] LayerMask mask;


2 void Update()
3 {
4 Ray ray = new Ray(transform.position, transform.forward);
RaycastHit hit;
5
if (Physics.Raycast(ray, out hit, mask, 25,
6 QueryTriggerInteraction.Ignore))
7 {
8 GameObject hitted = hit.collider.gameObject;
9 Debug.DrawLine(ray.origin, hit.point, Color.red);
10 Destroy(hitted);
11 }
else {
12 Debug.DrawLine(ray.origin, ray.origin + ray.direction * 100, Color.green);
13 }
14 }
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

31/45
Important stuff
For a Layer Mask to work properly when Raycasting, you need to assign also a
maxDistance, this is because the layer mask is treated as an int, therefore Unity can
mistakenly use the layer mask as a max distance, to set an infinite max distance, use
Mathf.Infinity.

Angles n’ stuff

32/45
33/45
34/45
Vector math

35/45
Lerp

1 Light _light;
2 void Start()
3 {
_light = GetComponent<Light>();
4 }
5 void Update()
6 {
7 _light.intensity = Mathf.Lerp(_light.intensity, 8f, 0.5f *
8 Time.deltaTime);
9 }
10
11
12
13
14

Input

GetKey
36/45
1 if (Input.GetKeyDown(KeyCode.Space))
2 {
3 print( "Space has been pressed" );
}
4
if (Input.GetKey(KeyCode.Space))
5 {
6 print( "Space is being pressed" );
7 }
8 if (Input.GetKeyUp(KeyCode.Space))
9 {
10 print( "Space has been released" );
}
11
12
13
14
15
16
17

Transform manipulation

Assign position

1 Vector3 startingPos = new Vector3(0, 0,


2 0);
3 void Start()
4 {
transform.position = startingPos;
5 }
6

Using Axis

37/45
1 float speed = 5f;
2 void Update()
3 {
4 float horizontalAxis = Input.GetAxis( "Horizontal" );
5 float verticalAxis = Input.GetAxis( "Vertical" );
6 transform.Translate( new Vector3(horizontalAxis, verticalAxis, 0) * speed *
7 Time.deltaTime);
}
8
9
10
11
12
13

Time

Pause (Time.timeScale)

1 bool isPaused;
2 void Update()
3 {
4 if (Input.GetKeyDown(KeyCode.Space))
5 {
isPaused = !isPaused;
6 Time.timeScale = isPaused ? 0 : 1;
7 }
8 }
9
10
11
12
13

Linq

Contains

38/45
1 using System.Linq;
2 public class UsingLinq : MonoBehaviour
3 {
4 public string [] names = { "jon" , "marcos" , "aurelio" };
5 void Start()
6 {
7 bool nameFound = names.Any(name => name ==
"aurelio" );
8
Debug.Log( "Name found: " + nameFound);
9 }
10 void Start()
11 {
12 bool nameFound = names.Contains( "jon" );
13 Debug.Log( "Name found: " + nameFound);
14 }
15
16
17
18
19
20
21
22
23

Distinct

1 public string [] names = { "jon" , "marcos" , "aurelio" , "aurelio" ,


2 "marcos" };
3 void Start()
4 {
5 var uniqueNames = names.Distinct();
6 foreach ( string name in uniqueNames)
7 {
print(name);
8 }
9 }
10
11
12

Where

39/45
1 void Start()
2 {
3 var longNames = names.Where(name => name.Length >
4 5);
5 foreach ( string name in longNames)
{
6 print(name);
7 }
8 }
9
10

Order

1 var passingGrades = grades.Where(grade => grade > 69);


2 var orderedGrades = passingGrades.OrderByDescending(grade =>
3 grade);
4 foreach ( int grade in orderedGrades)
5 {
print(grade);
6
}
7

Query syntax

1 var scoreQuerySyntax =
2 from score in scores
3 where score > 80
4 select score;
5 var scoreQuery = scores.Where(score => score >
6 80);
7
8
9

Attributes
[Range(x, y)] – Before a variable to get a slider. (min, max)

[Space] – Adds a space in the Inspector

[Header(“text”)] – Adds a title in Inspector

[Tooltip(“text”)] – Adds a description in Inspector while hovering the mouse.

40/45
[HideInInspector] – Hides variable in Inspector

[SerializableField] – Shows private variable in Inspector

[TextArea] – Adds a text box (attribute before string variable)

[Multiline] – Similar to TextArea but places the text box at the right side of the label.

[ContextMenu(“MethodName”)] – Makes it possible to call a method from Inspector’s


component contextual menu

[ContextMenuItem(“Text to show”, “MethodName”)] – Before a variable, makes it


possible to call a method in the context menu of that variable

Context menu: the contextual menu is the menu that appears generally when right clicking.

Class Attributes
[DisallowMultipleComponent] – You cannot add two of the same class to the same
game object.

[HelpURL(“https://www.google.com/”)] – Adds the possibility to access


documentation to your own class from the Inspector (the little blue book)

[RequireComponent(typeof(Class))] – Forces the component of type Class to be in


the same game object as the class where the attribute is applied.

[ExecuteInEditMode] – Executes the code in the class without the need of playing.

[SelectionBase] – If added for example to a class attached to the parent, it selects the
parent in Scene View instead of the children.

Other Attributes
[UnityEditor.MenuItem(“Menu/Sub menu/Sub menu”)] – Adds a button in
Unity’s menu so you can call a method, this attribute needs to be added before the method.

Other

Saving data
PlayerPrefs: Stores and accesses data between game sessions, in Windows it’s stored in the
registry (where it’s stored depends on the Game name and Company name set up in Project
Settings)
41/45
1 [SerializeField] int number = 10;
2 [SerializeField] string name = "simon" ;
3 void OnValidate()
4 {
5 PlayerPrefs.SetInt( "Saved int" , number);
PlayerPrefs.SetString( "Saved string" , name);
6 PlayerPrefs.Save();
7 }
8
9

number was changed to 12 in the inspector, and name was changed to ‘test’

Json

42/45
1 [SerializeField] int number = 10;
2 [SerializeField] string nametest = "simon" ;
3 [SerializeField] Color color;
4 [SerializeField] AnimationCurve curve;
5 void OnEnable()
{
6
JsonUtility.FromJsonOverwrite(PlayerPrefs.GetString( "json file" ), this );
7 }
8 void OnDisable()
9 {
10 PlayerPrefs.SetString( "json file" , JsonUtility.ToJson( this , true ));
11 PlayerPrefs.Save();
}
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

43/45
Optimization tips
Code for readability first, profile, and then optimize.

1. Eliminate calls to empty Update functions (they still use resources)


2. If you need to check something every frame, use Update(), if not, try using
Coroutines or InvokeRepeating, as this is more performant.
1. Instead of using ‘yield return new WaitForSeconds(x)’, cache that
WaitForSeconds(x) to avoid garbage.
WaitForSeconds wait = new WaitForSeconds(1f);
3. Move things out of Update when they don’t need to be called or calculated every
frame, for example, avoid getting components in Update or searching for objects.
4. Avoid calculating the same thing twice or more times, put it in a variable.
5. Use sqrMagnitude to calculate distances and use that value to compare distances if
needed, you save a square root calculation.
6. Cache the main camera and transforms, Unity performs a get function when you use
Camera.main directly, same with transform.
7. Avoid instantiating or destroying objects during gameplay, instead, use object
pooling.

You can use Samples to make things more clear in the Profiler

44/45
1 using UnityEngine.Profiling;
2 public class MyClass: MonoBehaviour
3 {
4 void Update()
5 {
Profiler.BeginSample( "DEBUGING" );
6 Debug.Log( "object destroyed" );
7 Profiler.EndSample();
8 }
9 }
10
11
12
13

Share this

45/45

You might also like