Let’s tackle these one at a time:
Properties
First Properties. You're probably use to fields
[SerializeField] int myInt;
and methods/functions
public int MyInt()
{
return myInt; //Edited
}
What I’ve just done here is encapsulated a private variable (myInt) and made it publicly available for read only in the function MyInt()
There is another way of creating such an accessor known as a property. Properties are like methods, except that they take no parameters, and don’t require () at the end. For example:
public int MyInt
{
get
{
return myInt;
}
}
Now you can read myInt just like a regular field without the (). You have already been using properties if you’ve been accessing things like .Count in a List or .Length in an Array.
Properties can also have write access. Where read access is defined with a get, they can be set with a Set.
public int MyInt
{
get
{
return myInt;
}
set
{
myInt = value; //behind the scenes, value is the right hand side of the argument
}
}
Of course, this is no different than saying
public int MyInt;
but suppose you want a property publicly readable but only able to be set within the class itself, that’s where mixed access modifiers come into play.
public int MyInt
{
get //This can be read from anywhere
{
return myInt;
}
private set //MyInt = someValue; can only be called within this class.
{
myInt = value;
}
}
Properties are fantastic, and powerful, but they have one limitation. You can’t expose them to the inspector (or serialize them at all!)… well… you couldn’t until relatively recent versions of Unity. Now you can expose public/private properties in the inspector with [field: SerializeField]
So before, if you wanted myInt to be serialized and exposed in the inspector, you would need to declare it like this:
[SerializeField] private int myInt; //This is known as the backing field
public int MyInt {get {return myInt;}} //This is the publicly exposed property
or
[SerializeField] private int myInt;
public int MyInt => myInt; //this is shorthand for a read only (get only) property, it returns the right hand side of the argument
Now you can use [field: SerializeField] and declare the property all on one line
[field: SerializeField] public int MyInt {get; private set;}
Behind the scenes, Unity automatically creates a hidden backing field and restricts access to the property so that it’s publicly readable, but only writable in the same class.
There is one significant restriction to this… It only works if you’re using a simple getter and setter, like the one I put forth earlier, i.e. get returns the backing field. set writes to the backing field. If you need any other code in the getter or setter, then you have to go back to the traditional methods.
Matching Types
In a SerializedField, when you specify a Component type, the inspector will only accept a prefab or GameObject that contains that specified type. In this case, since the property is set up for an InputReader
[field: SerializeField] InputReader InputReader;
Unity knows to only allow you to put an object containing an InputReader into that slot.
Events and Delegates
In this case,
stateMachine.InputReader.JumpEvent
is an event. Events are a collection of methods that are to be called when the event is raised. We subscribe to events with a simple += and -= syntax.
statemachine.InputReader.JumpEvent += Enter; //Add Enter() to the event queue
statemachine.InputReader.JumpEvent -= Enter; //Remove Enter() from the event queue
The compiler handles the complicated behind the scenes things of saying “Add the Enter() method that goes with this specific instance of this class to the queue”
We don’t need to include the () (in fact, if you include it, it won’t compile). C# knows you mean the Enter() method.