Unity 3D – Getting a Better Understanding of C# Concepts !

When digging into Unity3D for the first time, you probably want to have a functional prototype as fast as possible.
This tutorial provides a global overview of the main concepts I can see as useful for use in Unity3D in C#.


First let’s talk a bit about the language features !

When searching for informations you will see so much related concepts that it can be really misleading and time consuming so we are going to clarify it :

Microsoft created a framework named .NET framework which can be seen as a huge Toolbox composed of two main parts : the Framework Class Library (FCL) and the Common Language Runtime” (CLR).”

  • At Compilation time : Several “.NET compatible” languages such as C# can be compiled into Bytecode (Common Intermediate Language (CIL)) by the language compiler.
  • At Runtime : The code is compiled into native code (0101…)”just-in-time” by the Common Language Runtime (CLR) tool.

C#: Overview_Common_Language_Infrastructure
By Jarkko PiiroinenOwn work, Public Domain, Link


Now how are C# scripts and Unity3D Game Engine working together ?

Unity3D API (and even the whole Editor !) is simply C# code dispatched in DLLs required for your C# project either with MonoDevelop or VisualStudio : UnityEditor.dll, UnityEngine.dll.

Tip : You can find the decompiled code on the internet ! (Not very useful as API documentation is very well maintained !).

The main point is that instead of a single program entry point (the main function), the API provides several functions (Awake(), Start(), Update(), OnCollisionEnter(), OnTriggerEnter()) that triggers for specific events for each of your classes.

Basically, I see it as something like (very simplified to see most used events) :

public abstract class MonoBehaviour
{
    static void Main(string[] args)
    {
        StartMainForAllScripts();
    }

    static void MainForScript1()
    {
        Awake();
        Start();
        while(!ExitRequest)
        {
            ProcessInputs(); // OnCollisionEnter, etc.
            while(!FixedUserDefinedTimeElapsed);
            FixedUpdate();
            while(!FrameTimeElapsed);
            Update();        
        }
        OnApplicationQuit();
    }

    // Engine Events to be User Defined :
    protected abstract void Awake();
    // ...
}

This is called a Game Loop pattern.

As you can see, any of your classes that rely on the engine must inherit MonoBehaviour and you can implement any of its Event Functions.

Tip : That imply a small limitation : your MonoBehaviour classes cannot inherit from one of your abstract classes (C# limitation).

I will talk about the Compilation Process (mainly for Androïd & iOS platforms) in another article !


What is useful in C# features for my Game ?

Namespaces

You can organize your code into namespaces. For example, com.organization.product. It can be useful to organize your custom modules (e.g. a custom server access), even more when you are planning to package it (e.g. sell it as package int the Unity Asset Store). You don’t need it for your specific game code.

OOP Concepts

All the great OOP concepts are fully baked into C#.

For an entity (e.g. Person), you implement (its Model part), you can follow this simple pattern :

// Define the "Contract" - an interface that other classes can use.
public interface IPerson
{
    string m_Name { get; private set; }
    void Walk();
}
public abstract class PersonBase : MonoBehaviour, IPerson
{
    public string m_Name { get; private set; }
    void Walk() { _WalkMyOnWay(); }
    protected abstract void _WalkMyOnWay(); // To be defined in concrete class
}
public class Baby : PersonBase
{
    protected override void _WalkMyOnWay() { /* ... */ }
}

Tip : I personnaly rarely use Constructors : As MonoBehaviour provides an Awake() function, you can instantiate everything in it.

I share with you a better way of architecturing your source code in Unity3D in details ici. How to process user inputs / outputs (the View) ? How to create your Player Model ? How to efficiently update your Model when an input is received ?

Data Structures, enumerations

Structs are very useful if you need to expose a custom set of multiple data in the Inspector without having to go for Editor Scripting.

public enum EventTypes {EventTriggered, Periodic, Aperiodic} 

[SerializeField]
public struct m_Person
{
    public string m_FullName;
    public int m_Age;
}

Get / Set Properties

In standard OOP concepts, you learned that your class members should never be public but accessed through accessor / mutator functions e.g. getName().
C# introduce properties to allow you to have a better control on class members access :

private string m_name; // Backing or "internal" Field
public string m_Name 
{ 
    public get { return m_name; } 
    public set { m_name = value; } 
}

Note that you can here modify the properties body (e.g. to do specific checks) and scope or even remove one of them. Given this syntax, it becomes useless to implement standard getX() / setX() functions and readability is greatly improved.

Tip : The auto-implemented property “public string m_Name { get; set; }” is semantically equivalent to the previous statement.

C# events and delegates

See https://unity3d.com/fr/learn/tutorials/topics/scripting/events for more info.
It simply follows an Observer design pattern. The Event is “mapped” to a Delegate (which is as sort of Function container / list). When you “fire” the Event by calling it, all its listeners (those who registered a callback function into the delegate) gets notified.

Tip : You can also use UnityEvents as an alternative.

Tip : You can set a Template as the default source code being used when creating a new C# class by saving it as “81-C# Script-NewBehaviourScript.cs.txt” in Unity Ressource folder : “%UNITY_PATH%\Editor\Data\Resources\ScriptTemplates\
(For me install path was “C:\Program Files\Unity\”).

Some Useful References :

I hope you enjoyed this tutorial as much as I liked writing it.
Please fill in the comment section with your remarks and your experiences !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *