string
int
float
boog
char
(1 letter string)DateTime
https://www.tutorialsteacher.com/csharp/csharp-data-types
The reference types are string
, arrays
, classes
, delegates
. Others like struct
are value types.
To cast between types you do (int)myNumberString
string[] names = new string[5];
string[] names = new string[] { "marco", "eleonora", "bisceglie" };
The foreach loop looks like
foreach (var element in array) {
// ...
}
It is just like a normal type
public struct Agent {
string id;
Vector3 position;
}
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
}
No functions in C#, only methods
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; }
}
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
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) {
// ...
}
}
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 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 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) {
// ...
}
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) {
// ...
}
}
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() {}
}
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 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) {
// ...
}
}
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();
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);
}
}
You usually put your utilities as statics in public static class Utilities
To create a primitive
GameObject.CreatePrimitive(PrimitiveType.Cube);