- Home /
Should I use "universal" functions for my game?
What I'm referring to with "universal functions" is a group of those which I can use in every script of my project. For example, let's say I have different scripts that are assigned to different objects whose purpose is remove health from my player whenever something specific happens. To remove the health from my player, I think it'd be better if I used a function called "takeDamage()" that takes an int as argument. Do I/Should I create a new function every time I want to do so? If the answer is no, how can I reference functions from another class? I can't call a new instance of a class that inherits from a MonoBehaviour. Many thanks in advance.
Answer by Namey5 · Jul 24, 2020 at 03:18 AM
In short, yes - we want to try to limit code duplication as much as possible. If you do the same action multiple times, instead think about using a function that does that for you. For objects that need to be modified individually, then you will need to assign/get the specific instance that you want to change. However, there are some things we can do to make this a bit easier. For example, if we know there is only one player, then we can define a static variable that points to the player's instance - which can then be accessed from anywhere;
public class Player : MonoBehaviour
{
//Define an instance of the player that we can access from anywhere
public static Player MainPlayer;
[SerializeField] private float health = 100f;
private void OnEnable ()
{
//If there's already a player in the scene that isn't this, disable this script
if (MainPlayer && MainPlayer != this)
{
enabled = false;
return;
}
//Set the MainPlayer reference to this instance
MainPlayer = this;
}
//Not necessary, but un-set the MainPlayer when we disable it in case you want to change player objects
private void OnDisable ()
{
if (MainPlayer && MainPlayer == this)
MainPlayer = null;
}
//Then have the publicly accessible damage function
public void TakeDamage (float damage)
{
health -= damage;
}
}
...
//Then, to damage the player from somewhere else, you can do this;
//Take 50 damage
Player.MainPlayer.TakeDamage (50);
This is known as a singleton, and only works if there can only be one in the scene - otherwise, we would need some way of finding which object we are supposed to be taking health away from. However, C# is an object oriented language, so we can even take this a bit further. Let's say that we had both a player and enemies that had health and took damage in the same kind of way. Well, if we define a base class and inherit both from that then we only need to write the health code once and share it across both players and enemies alike;
//'Character' inherits from MonoBehaviour so that it can be attached to objects in Unity
public class Character : MonoBehaviour
{
//This is 'protected' rather than 'private' so that we can still access it from sub-classes
[SerializeField] protected float health = 100f;
public void TakeDamage (float damage)
{
health -= damage;
}
}
...
//Player class inherits from Character and automatically gets health and damage functions
public class Player : Character
{
public static Player MainPlayer;
private void OnEnable ()
{
if (MainPlayer && MainPlayer != this)
{
enabled = false;
return;
}
MainPlayer = this;
}
private void OnDisable ()
{
if (MainPlayer && MainPlayer == this)
MainPlayer = null;
}
}
...
//And so does the Enemy class
public class Enemy : Character
{
[SerializeField] private float damage = 20f;
public void DamagePlayer ()
{
Player.MainPlayer.TakeDamage (damage);
}
}
Now, you might not want to do this, but it's more just to show that there are many ways to get around having to write the same thing more than once - the rest is up to you.
Thank you so much! This is probably the best answer I could've ever got!
Your answer
Follow this Question
Related Questions
Converting this JS code to C# 1 Answer
How to keep Text file going in different scenes? 2 Answers
Help with Input.GetAxis??? 1 Answer