Skip to content

Mod Creation_C# Programming_Unity and MonoBehaviour

TheTimeSweeper edited this page Sep 29, 2024 · 6 revisions

Unity and MonoBehaviour

Scene, GameObject, and Component

Every Unity game is running a scene that is composed of GameObject's which have a collection of components attached to them. Components are the main source of game logic. A MonoBehaviour is the main class you want to derive from to create your own GameObject component.
Generally when people say "component" they are talking about classes derived from MonoBehaviour, and visa versa.

MonoBehaviour Messages

Every instance of MonoBehaviour has some special functions that are called by the engine at specific events. Here is the game loop: https://docs.unity3d.com/uploads/Main/monobehaviour_flowchart.svg

All MonoBehaviour callbacks are described in unity documentation: Check under "Messages" header But down below we'll talk about some of them.

Constructing a MonoBehaviour

Constructor

Generally, you shouldn't use constructors in classes derived from MonoBehaviour. If you need to initialize something, do it in Awake. https://ilkinulas.github.io/development/unity/2016/05/30/monobehaviour-constructor.html

Awake

Awake is the first thing that is called when a GameObject with this MonoBehaviour attached is created. Awake also runs in your main plugin class, and occurs prior to all catalog init, so it should be used for any hooks or catalog events.

Start

Start is basically a second awake, for when you need things to happen right after the first initialization. In your main plugin class, this happens after all plugin mods are loaded in the appdomain and their metadata available through the BepInEx Chainloader

Update

The update is called every frame if the MonoBehaviour is enabled.

This is usually the most commonly used function of scripts in Unity games, however, RoR2 does most of its logic in FixedUpdate.
Usually, if you want to do something every frame, like making sure visuals line up, you should do this here.

FixedUpdate

FixedUpdate has the frequency of the physics system; it is called every fixed frame-rate time.
This means that depending on framerate it can skip frames, or be called multiple times in one frame.
The majority of game logic runs in this update, so that it is independent of framerate.
FixedUpdate in RoR2 updates 50 times per second, or every 0.02 seconds

LateUpdate

Same as Update but gets called after coroutines and animations. Less commonly used

OnDestroy

Happens after component or its game object is destroyed.
You can destroy any component/game object with Object.Destroy

OnEnable

Happens every time your MonoBehaviour is enabled, or more likely, the GameObject is attached to is set active.
This is different from Awake or Start in that those functions only happen once

OnDisable

Happens every time your MonoBehaviour is disabled, or more likely, the GameObject is attached to is set inactive.

MonoBehaviour functions

These functions are generally called from within MonoBehaviour components and are in some way related to the gameobject

Invoke

Calls a function after a specified amount of time. It is for the best to avoid this method. If you want to invoke something with a delay use coroutine instead.

InvokeRepeating

Calls a function after a specified amount of time and then continues to call that function with a given time interval between calls. Avoid, same as Invoke.

StartCoroutine

Starts an asynchronous process similar to a thread. Use this to repeat a function a specific number of times or Lerp a value without slowdown.

interesting article about coroutine vs threading: https://gamedev.stackexchange.com/questions/143454/unity-coroutine-vs-threads

Manipulating Components

These functions are used to add, reference, and remove components of GameObjects. If your mod is done through code, you will likely have to wrangle with these a lot.

AddComponent

Adds a component to an object. This also returns the component that was just added.
This can be used to add extra functionality to a game object by making it run a script that it does not currently run.

Object.Destroy

When a component is passed in, it will remove the component from the GameObject. Of course, if a GameObject is passed in, it will destroy the whole GameObject.

GetComponent

Get component returns a script / component that is attached to an object. This will return null if it is trying to access a component that an object does not have, and you will run into a NullReferenceException if you try to do anything with that null component.
Can be used to get other scripts on an object and access their variables and functions.

A warning, GetComponent can be a bit cpu intensive especially on objects like Characters which have a lot of components.
It is best to avoid this at runtime, and most importantly, in functions like Update or FixedUpdate.
If you want to use it, especially multiple times, generally call it once at the beginning of your code and store it in a variable.

GetComponents

Returns an array of all the components of the desired type attached to a GameObject.
This is guaranteed to iterate through all components of the GameObject, and should avoided even more than GetComponent

GetComponentInChildren

As the name implies, it iterates through all children of the GameObject and returns the first component of the desired type.
Should be avoided even more than GetComponent

FindObjectOfType

Do not ever use this The power to find any object in a scene with a desired component sounds appealing, but it will iterate through every single object in the scene, searching through their components. It is a terrible p erformance killer and if you are caught using this you will be publicly shamed.

Using Scripts in Editor

While you are free to manipulate them as much as you want through code, MonoBehaviour components were intended to use in editor. Refer to this article on how to do as such: https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/Using-MonoBehaviour-Scripts-in-Editor/

Clone this wiki locally