Event System


Have spent some time to clean up my code. Even though the game was only just started, but when I started to add more features, I realised the importance of following OOP Design Principles. Trying to break things down to simple functional parts and keep low coupling would make code easier to manage and reuse as well. 

There is a task in my game for rotating the cube. Let’s say I need to rotate the cube when something happens, for example, key pressed or player reached the bounds, and when the cube finished the rotating, something needs to be done. It’s the same as the event system which you give an object a task and the object gives you feedback after the task is done so that you can do follow-up stuff. There are some different way to do it. 

Create a flag and change it when the tasks are done. Check the flag in every update().

This is probably the simplest way of doing it. But it’s not efficient as you have to keep checking the value. Also, it would cause unnecessary delay since DoSomething is not called straight after DoMyTask was done. 

Class A: MonoBehaviour{  
  B b;  
  ....  
  void Update(){
    if (isReady) b.DoMyTask();
    if (b.isDone) DoSomething();
  }  
  void DoSomething(){}
}
Class B: MonoBehaviour{
  bool isDone;
  ....
  void DoMyTask(){
    ......
    isDone = true;
  }
}

Reference to each other and call the method directly. 

This way is straightforward but with high coupling, which means it can’t be reused separately. This is not going to work if B is reused in other classes.

Class A: MonoBehaviour{
  B b;
  ....
  void Update(){
    if (isReady) a.DoMyTask();
  }
  void DoSomething(){}
}
Class B: MonoBehaviour{
  A a;
  ....
  void DoMyTask(){
    ....
    a.DoSomething();
  }
}

Use Observer Pattern

This one is the standard way of doing the event system. You can check Wikipedia for more details. Basically, A is an observer and B is the object. B needs to have a notify-list. Any observer that wants to be notified needs to register to the list. When B in any state that observers are interested, B will call the action of all observers. The following code is only a very brief example.

abstract Class Observer: MonoBehaviour{
  void DoSomething();
}
abstract Class Object: MonoBehaviour{
  void Register();
  void Notify();
}
Class A: Observer{
  B b;
  void Start(){
    b.Register(this);
  }
  void DoSomething(){}
}
Class B: Object{
  List<Observer> list;
  void Register(Observer obs){
    list.add(obs);
  }
  void Notify(){
    foreach(Observer obs in list){
      obs.Dosomething();
    }
  }
}

Use delegate

This is the one I think is powerful but simpler than the standard observer pattern. You don’t need to define the Observer/Object Class, no need to register either. Low coupling and easy to use but still has the power. Only need to be careful if A is destroyed, you might need to remove the DoSomething because it will still be executed.

Class A: MonoBehaviour{
  B b;
  void Start(){
    b.OnTaskDone += DoSomething;
  }
  void DoSomething(){}
}
Class B: MonoBehaviour{
  public event Action OnTaskDone;
  void DoMyTask(){
    ....
    if (OnTaskDone != null)
      OnTaskDone();
  }
}

 If you don’t have many events, you could even create a static class for the event Action. In that case, A and B would not affect each other at all.

Get Pursuit

Download NowName your own price

Leave a comment

Log in with itch.io to leave a comment.