- Home /
Calling all functions with same name
Hi, so I'm making this game and I want to use an interface which I called "IGameStates" it holds pause, continue, die, and restart. Now, I want to implement these functions in different scripts and call all of them at the same time for example when the player dies, all scripts with the Die function will be called. I'm sorry for my bad England :D and thanks in advance.
Nothing in C# does this automatically or even conveniently. You witness something that seems like this in the Unity framework, in the likes of Update, FixedUpdate, Start, Awake, etc. The primary point at which Unity invokes this magic is based on the fact that the classes which respond to these functions are derived from Unity base classes which inspect the reflection characteristics of the class, and call those where they are found to exist. You don't quite have that same relative viewpoint of your classes unless you insist on for$$anonymous$$g it, and it isn't particularly convenient.
I note that my primary language is C++, and while I know C# I can't claim high expertise in C# as I can in C++. That said, the approach I'd consider involves delegates. I would create a container of delegates which register all of the "Die" methods to be called, then fashion one method which loops through these registered delegates, calling all of them in each occasion that it is appropriate. While I can think of several alternatives that may seem more convenient, I also have reason to believe all other approaches require more CPU attention at runtime.
@JVene thanks for taking the time to reply, I will try to learn your approach and try to implement it, I will let you know when it works with that. Thanks and have a nice day!
You can do it my potato way which is all IGameStates always have "SignUp" function. Which litterally just reference itself to a static class (singleton most likely). So now you just have to call static class to access to all function with Interface.
The professional way to do this is to reflection entire assembly on awake to find all interface.
https://stackoverflow.com/questions/26733/getting-all-types-that-implement-an-interface
But it was just to much of hassle for me. Here is the example code that i use for random stuff https://pastebin.com/v$$anonymous$$XsQEFx
@NoDumbQuestion I will try those too after trying a delegate approach, and I will try to see which one is more convenient. Thanks to you too and have an awesome day!
A simple, entry-level way to do this would be to use a centralized manager and OOP to do your lifting (as pointed out by @NoDumbQuestion) .
For a more elegant solution, you might want to look into events. Reflection can simplify your problem significantly, but it tends to make things difficult to read and I'm too ignorant to know how well it's supported across platforms.
The interface:
public interface IGameStates
{
void Die();
}
A poorly scaling "manager" example:
public class GameState$$anonymous$$anager
{
public static List<GameStateBehaviour> subscribers;
public static List<GameStateBehaviour> Subscribers
{
get
{
if (subscribers == null)
subscribers = new List<GameStateBehaviour>();
return subscribers;
}
}
public static void Attach(GameStateBehaviour behaviour)
{
if (Subscribers.Contains(behaviour) == false)
Subscribers.Add(behaviour);
}
public static void Detatch(GameStateBehaviour behaviour)
{
if (Subscribers.Contains(behaviour))
Subscribers.Remove(behaviour);
}
public static void EmitDie()
{
for (int k=0; k<Subscribers.Count; k++)
{
Subscribers[k].Die();
}
}
}
Your behaviour:
public class GameStateBehaviour : $$anonymous$$onoBehaviour, IGameStates
{
protected internal void Awake()
{
GameState$$anonymous$$anager.Attach(this);
}
public void Die()
{
Debug.LogFormat("{0} received a death notification", this.name);
}
protected internal void OnDestroy()
{
GameState$$anonymous$$anager.Detatch(this);
}
}
Some example listener:
public class GameStateListener : GameStateBehaviour
{
new protected internal void Awake()
{
// Allow the initial subscription to happen.
base.Awake();
}
}
Then some way of checking if it works:
public class GameStateExample : $$anonymous$$onoBehaviour
{
// Update is called once per frame
void Update ()
{
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.Space))
{
GameState$$anonymous$$anager.EmitDie();
}
}
}
In my example, I just made attached a GameStateExample to an empty object with 7 GameStateListeners. Pressing spacebar should produce 7 messages, which will be reduced / increased if you want to delete / copy them while the scene is running.
Answer by TheKnightsofUnity · Sep 27, 2018 at 11:31 AM
Hello,
the solution for your problem are delegates.
public interface IGameState
{
void Die();
}
public class Foo : IGameState
{
public void Die()
{
...
}
}
public class PlayerController : MonoBehaviour
{
public event Action OnPlayerDied = delegate { };
public Foo foo;
private void Awake()
{
PlayerDied += foo.Die;
}
private void PlayerDied()
{
...
PlayerDied.Invoke();
}
}
This way, when method PlayerDied is used, all methods that were registered to the Action OnPlayerDied will be invoked.
All the best,
The Knights of Unity
Your answer
Follow this Question
Related Questions
IPointer Events don't seem to be working 3 Answers
Parent Event Handler Overriding Child Handler 0 Answers
Catch pointer events by multiple gameObjects 6 Answers