Jump to content
  • Advertisement
Sign in to follow this  
ibequa

Unity Implement game state callback methods

This topic is 1000 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

In my game engine I want to have start() and update() callback methods much like in Unity3D. They will form 'GameListener' interface, which the user should implement to get to them. How do I implement these callbacks without adding any listeners?

For example, in libGDX, you have to implement ApplicationListener(or ApplicationAdapter) interface to get access to render() and start() methods without adding any listeners.

public class SomeGameObject extends ApplicationAdapter {
public void create() {} // called when game is started
public void render() {} // called when need to render 
}

I can implement similar behaviour using the observer pattern, but it requires additional line, smth like:

ApplicationAdapter.addListener(this);

How do I do without it?

Edited by ibequa

Share this post


Link to post
Share on other sites
Advertisement

What exactly is wrong with registering a callback? Why is calling addListener such a burden? Perhaps if you can explain that then someone here could recommend an alternative pattern that fits your needs.

Share this post


Link to post
Share on other sites

Say I have this:

class Core {
   void createWindow() {
     // called when window is created
     // ....
     render();
   }

   void render() {
     // called every frame
     // updating the game
     // actual rendering
   }
}

Now, in engines like unity3d or libgdx, you only have to implement a class/interface to get access to the callback methods (start(), update(), awake(), dispose() e.t.c). For example:

class Player : MonoBehaviour {
  void Update() {
    // no addListeners() and stuff, just inherit MonoBehaviour
  }
}

How to implement it?

Edited by ibequa

Share this post


Link to post
Share on other sites
I assume Unity uses C# reflection and then registers the callbacks kind of automatically. For every script you check if it implements a callback and register it. Unfortunately this is not so trivial in C++.

Share this post


Link to post
Share on other sites

I don't know unity, and I am not even sure what language you use, but can you test for having implemented an interface in the constructor of a base class?

If so, you can do all the addlisteners there.

 

Beyond that, you seem to have jumped on the idea of unity, without much consideration whether it is a good idea for your program. That's a dangerous thing to do.

Share this post


Link to post
Share on other sites

I think Dirk is correct in that Unity makes use of C# reflection to set up the callbacks. The is the only way as they are not overloaded methods. They probably still do the registration behind the scenes as reflection has a huge overhead that would hammer performance if done each time the method is called. For Javascript they would just use the dynamic nature of the language to do this.

 

It looks like you are using Java? If so have interfaces for the various methods and then you can see if the object implements the interface and go from there.

 

Explicit registration has some benefits as you might miss the interfaces off a class and then wonder why it does not update etc.

Share this post


Link to post
Share on other sites
class GameListener
{
public:
  GameListener()
  {
    this->gameInstance = Game::CurrentInstance();
    this->gameInstance->addListener( this );
  }
  ~GameListener()
  {
    this->gameInstance->removeListener( this );
  }

  virtual void start( ) = 0;
  virtual void update( int delta_ms ) = 0;

private:
  Game * gameInstance;
};

class MyGameObject : public GameListener
{
  void start() override
  {
    // something...
  }
  void update( int delta_ms ) override
  {
    // something...
  }
};

The listener adds or removes self as a listener in constructor and desructor.

 

You have two options if Game::CurrentInstance() is not constant through the application runtime.

 

First option is to make sure that you set Game::CurrentInstance() to right value before each instantiation of each GameListener.

 

Second option - I use this option in my game - you can change the code so that the right Game instance is passed to constructor of MyGameObject which will then pass it to constructor of GameListener.

Share this post


Link to post
Share on other sites

The listener adds or removes self as a listener in constructor and desructor.
That fails as soon as you have more than one interface to attach yourself too, in a language without multiple inheritance (ie Java and C#), and the OP doesn't have code that looks like C++ ("extends" keyword in the first post).

Share this post


Link to post
Share on other sites

 

The listener adds or removes self as a listener in constructor and desructor.
That fails as soon as you have more than one interface to attach yourself too, in a language without multiple inheritance (ie Java and C#), and the OP doesn't have code that looks like C++ ("extends" keyword in the first post).

 

 

Hm, I am not one of people who think that Java and C# are sane languages.

 

Nevertheless, I think that "default interface implementation" introduced in Java 8 could be used to do this. I don't know if C# has something equivalent.

 

Another solution that does not require multiple inheritance and resembles typical Java code comes to my mind. In Java, you usualy have one class (eg. GameObject) which is inherited by all game objects. In constructor of this class, you can try to convert the class into all possible interfaces and register them all. This can not be easily done in C++ (because you can not cast self to inherited class in constructor or destructor), but it should work in Java and C#, where the focus on RAII is not so strict.

Share this post


Link to post
Share on other sites


The listener adds or removes self as a listener in constructor and desructor.

 

That's a bad idea since the sub-class's constructor will not have been executed at the point where addListener is called and you store a reference to the object before it is fully constructed.  If some other thread were to trigger a callback at that moment then who knows what state the object might be in? Even things like final fields might be observed to be uninitialized which would lead to some very bizarre bugs.

 

Getting back to the OP's question: MonoBehaviour extends Component, and GameObject has an AddComponent method (which looks a lot like AddListener, just with a different name). My guess is that the Unity editor is calling AddComponent behind the scenes where you can't see it, but it's still there.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!