Skip to content

Instantly share code, notes, and snippets.

@marcofugaro
Last active May 10, 2020 15:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcofugaro/5992e9ca4696e7c04c596edc7cacb21b to your computer and use it in GitHub Desktop.
Save marcofugaro/5992e9ca4696e7c04c596edc7cacb21b to your computer and use it in GitHub Desktop.
Unity C# Reference

Unity C# Reference

Types

The reference types are string, arrays, classes, delegates. Others like struct are value types.

To cast between types you do (int)myNumberString

Array

string[] names = new string[5];
string[] names = new string[] { "marco", "eleonora", "bisceglie" };

The foreach loop looks like

foreach (var element in array) {
  // ...
}

Structs

It is just like a normal type

public struct Agent {
  string id;
  Vector3 position;
}

Enums

Rendered as selects in the editor

public enum Difficulty
{
  Easy,
  Normal,
  Hard
}

Under the hood they have 0 to n values

public enum Difficulty
{
  Easy, // == 0
  Normal, // == 1
  Hard // == 2
}

public Difficulty currentDifficulty = Difficulty.Normal;

You can also set them specifically

public enum Difficulty
{
  Easy = 42,
  Normal = 62, 
  Hard = 2 
}

Functions

No functions in C#, only methods

Classes

public class Person
{
  string name;

  public Person(string name) {
     name = name;
  } 
}

protected only the class that inherit from this class can access it

virtual lets you override this property/method from an extending class

public class Pet : MonoBehaviour
{
  protected virtual void Speak() {
    Debug.log("Hello");
  }
}

public class Duck : Pet
{
  protected override void Speak() {
    // base.Speak(); // to call the parent
    Debug.log("Quack");
  }
}

static properties/methods can be accessed directly from the class type like Score.value += 1;.

Non-static properties/methods instead, can be accessed by finding them globally:

GameObject.Find("Score Keeper").getComponent<Score>();
                      ^
                      This is the name of the object in the scene graph

Getters and setters are defined like this

public class Game : MonoBehaviour
{
  public bool IsGameOver
  {
    get 
    {
	  return Time.time > 30;
    }

    set
    {
      // ...
    }
  }

}

To make a getter read-only from the outside:

public class Game : MonoBehaviour
{
  public bool IsGameOver { get; private set; }
}

Namespaces

You define namespaces like

namespace MyLibrary
{
	public class MyClass {}
}

And use them like

using MyLibrary

// ...

MyClass.property

They can also be nested like namespace MyLibrary.Section and using MyLibrary.Section

Lists

Like arrays, but of variable length

using System.Collections.Generic;

// ...

public List<Player> players = new List<Player>();

void Start() 
{
  var player = new Player();

  players.Add(player);

  players[0] == player; // true
	
  players.Remove(player);

  foreach (var player in players) {
    // ...
  }
}

Dictionaries

using System.Collections.Generic;

// ...
public Dictionary<string, Item> items = new Dictionary<string, Item>();

void Start() 
{
  var item = new Item();

  items.Add('9hasd8h9ads', item);

  items['9hasd8h9ads'] == item; // true
	
  items.Remove('9hasd8h9ads');

  foreach (KeyValuePair<string, Item> element in items) {
    Debug.Log(element.Key);
    var item = element.Value;
  }

  foreach (var key in items.Keys) {
    // ...
  }

  foreach (var item in items.Values) {
    // ...
  }

  if (items.ContainsKey('9hasd8h9ads')) {
    // ...
  }
}

Abstract classes

Abstract classes allow you to define some patterns that a child class extending the abstract class must implement.

public abstract class Enemy : MonoBehaviour
{
	void abstract Attack();

}

public class Skeleton : Enemy {
  public override void Attack() {}
}

If the Skeleton class in not implementing an Attack() method, it will throw an error.

The difference with virtual methods, is that abstract methods don't have an implementation (curly braces).

Interfaces

Interfaces are similar to abstract classes, however they do not allow methods or properties, just types.

They have a name I___able as common practice.

interface IDamageable {
  int Health { get; set; }

  void Damage(int damageAmount);
}


public class Player : MonoBehaviour, IDamageable  
{

}

A class can extend multiple interfaces, however just one traditional class.

You could also pass an interface type to a GetObject call:

// returns the class with IDamageable on the clicked GameObject
IDamageable clickedObj = hitInfo.collider.GetComponent<IDamageable>();

if (clickedObj) {
  // ...
}

Delegates

A delegate is a variable that holds a method, the signature of the method is kept in a type of the class. They are kinda like callbacks in javascript (.onclick = ).

public class Player : MonoBehaviour
{
  public delegate void ChangeColor(Color newColor);
  public ChangeColor onColorChange;

  // to assign it
  void Start () {
    onColorChange = UpdateColor;
  }

  void UpdateColor(Color newColor) {
    // ...
  }
}

Events

Evants make use of Delegates to turn them into something like addEventListener()

The difference is that events can be invoked only from whitin the class they are defined.

public class UI : MonoBehaviour 
{
  public delegate void ActionClick();
  public static event ActionClick onClick;

  ButtonClick()
  {
    if (onClick != null) { // if there's a listerner attached
      onClick();
    }
  }
}



public class Cube : MonoBehaviour 
{
  void Start() {
     UI.onClick += Explode;
  }
  
  void OnDisable() {
     UI.onClick -= Explode;
  } 
  
  void Explode() {}
}

Actions

using System;

public class UI : MonoBehaviour 
{
  public static Action<> onClick; // in the generic go the parameter types of the function

  ButtonClick()
  {
    if (onClick != null) { // if there's a listerner attached
      onClick();
    }
  }
}



public class Cube : MonoBehaviour 
{
  void Start() {
     UI.onClick += Explode;
  }
  
  void OnDisable() {
     UI.onClick -= Explode;
  } 
  
  void Explode() {}
}

The previous example can be written more clearly using actions

Function delegates

Function delegates are syntactic sugar of delegates

using System;

public class Player : MonoBehaviour
{
  public Func<Color, void> onColorChange; // input type + return type

  // to assign it
  void Start () {
    onColorChange = UpdateColor;
  }

  void UpdateColor(Color newColor) {
    // ...
  }
}

Singleton pattern

Singletons allow us to access easier instances of classes withoud doing the GameObject.GetComponent stuff

public class UIManager : MonoBehaviour
{
  private static UIManager _instance;
  public static UIManager Instance 
  {
    get
    {
      if (_instance == null) {
        Debug.Error("UIManager not present in the scene");
      } 
       
      return _instance;
    }
  }

  void Awake() {
    _instance = this;
  }

}

But this can easily be abstracted like:

public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
{
  private static T _instance;
  public static T Instance 
  {
    get
    {
      if (_instance == null) {
        Debug.Error(typeof(T).ToString() + " not present in the scene");
      } 
       
      return _instance;
    }
  }

  void Awake() {
    _instance = this as T;

    Init();
  }

  // since the class can't call Awake, we optionally provide the Init method to use
  public virtual void Init() {}
}

then use it on a class that you wish to make a singleton like

public class UIManager : MonoSingleton<UIManager> {}

and access it like

UIManager.Instance.Something();

LINQ

Like lodash, contains utilities for arrays ecc ecc

using System.Linq

public class Player : MonoBehaviour 
{
  void Start() {
    int[] scores = new  int[] { 97, 92, 81, 60 };
    
    var scoreQuery = 
      from score in scores 
      where score > 80
      select score;

    // which is exactly the same as

    var scoreQuerySimple = scores.Where(score => score > 80);
  }
}

Unity utilities

You usually put your utilities as statics in public static class Utilities

To create a primitive

GameObject.CreatePrimitive(PrimitiveType.Cube);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment