How to make update loops and custom controls event-driven? (Or not)

I’ll preface this by stating that I did try to RTFM prior to posting this question (!) and have read both the Hello Update Loop and Custom Controls documentation in the wiki.

I’m trying to understand the way jME devs are supposed to update scene objects (Spatials) and am just hitting a mental barrier, probably because I’m thinking about it the wrong way.

I come from an enterprise, message/event-driven background (not gaming) and so, to me, I think about updating game objects from reactive perspective, and would have imagined the API for the main game loop to look something like:

// Pseudo-code
class MyGame extends SimpleGame implements LightEventListener {
    // ...

    void simpleInitApp() {
        // ...

    void onLightGeneratedEvent(LightGeneratedEvent lge) {
        // TODO: Update game objects that need to respond to 'LightGeneratedEvent's...

…and I was imagining the API for each Spatial’s update mechanism to look something like:

// Pseudo-code
class BuzzSpatialControl extends AbstractControl implements LightEventListener {
    void onLightGeneratedEvent(LightGeneratedEvent lge) {
        // TODO: Update this spatial however it should react to this event...

Instead, both the main game loop and spatial controls are “time-based” (rely heavily on a tpf argument).

This makes sense (I think), since in a game we have a loop and are constantly performing checks & updates to game state on each iteration. But I’m having a tough time (mentally) getting out of an event-driven frame of mind, and seeing how I can update my game state, not via events/messaging, but via the tpf argument passed into this API methods. In other words, how do I go from event-based updates to time-based updates?

For instance, say I have two Spatials on a scene graph (a FizzSpatial and a BuzzSpatial). The FizzSpatial randomly generates light (and perhaps a respective LightGeneratedEvent). The BuzzSpatial spatial reacts to the FizzSpatial, and when it radiates light (that is, fires a LightGeneratedEvent), the BuzzSpatial, say, rotates a certain amount.

Since the 2nd spatial is managed by a BuzzSpatialControl, I’m not seeing the “forest through the trees” on how a FizzSpatial could fire a LightGeneratedEvent and be reacted to by the BuzzSpatial, because the BuzzSpatialControl's updates are handled via the controlUpdate method, which is time-based:

// Pseudo-code
class BuzzSpatialControl extends AbstractControl {
    void controlUpdate(float tpf) {
        // TODO: How do I respond to LightGeneratedEvents and *only* rotate if one has been
        // emitted by the FizzSpatial?

I guess I could just ignore the tpf argument and implement some event bus (maybe use Akka or Guava), but I feel like that vehemently flies in the face of the intention behind this API design? Yes? No?

FizzSpatial is a spatial… not a game object.

Spatials are “view”. Game objects are “model”. You are intertwining them in really bad ways.

In the end the question I have is “how?” How does this “fizzthing” randomly generate light?

Maybe you still need events. Maybe you need to read about entity component systems (will blow your mind probably)… maybe polling is still best.

The visual game loop will poll because it’s entire job is to update the scene every rendered frame. The rest of your game can do whatever.

Thanks @pspeed

Can you please confirm that this article is the best source for these “entity component systems”:

I’m reading it now but want to make sure I don’t miss any other (important/critical) reading on the subject. Thanks again!

Yeah, that’s an ok start on the topic from a specific library’s perspective. (My library so I’m biased to say it’s GREAT! heheh Though note that I didn’t write those docs.)

You can also try more general background on the concept:

…etc… which were just the first two google links when I searched for entity system.

Edit: added a note that I didn’t write the jme zay-es docs. You can see a start of the “official” zay-es docs here: Home · jMonkeyEngine-Contributions/zay-es Wiki · GitHub

…though that’s more supplemental at this point.

Thanks for all those! The wikipedia article is interesting. Any thoughts on the listed drawbakcs (“Inter-System Communication” and “Cost of iterating through entities”)?

The first “drawback” to ECS (according to Wikipedia - don’t shoot the messenger here!) is that it can get very complicated when lots of systems are writing state to various components. I think could be easily overcome with a proper event bus communicating between “systems” (hence achieving the event-drivenness I was trying to describe earlier!), or possible even an actor system.

As for the second, the article is basically saying that each “system” needs to maintain its own list of applicable entities, and that if this list grows too big, iteration can bog down performance. This wouldn’t affect any game that I’m currently capable of writing, but I could see it being an issue for a substantial game.

I’m curious on your thoughts here (regarding a possible solution), but off the cuff I’m thinking you could delegate list iteration off to a Runnable or any other mechanism (Akka actor/actor pool, etc.) that executes the iteration asynchronously (but hopefully quickly!) in another thread. Thoughts?

Other than that one hang up I think I “get” ECS’s and how I could use them to allow game objects/entities to interact with each other. I guess my next logical question is: how do I connect the “view” (Spatials and their Controls) to the “model” (the ECS)?

Thanks again (enormously!).

This is a sign of poor design, actually. It’s not a drawback, it’s an indicator. You’d have had the poor design either way but now it becomes obvious.

Almost never a need for events. That’s usually a sign you are missing a component.

What’s the alternative? And anyway, not all systems need to iterate over their entities.

The only drawback really is that you can generate a lot of garbage. Modern JVMs are very good at this. And that’s partially because you get multithreading for free with Zay-ES. So components are immutable which means if you want to change one you make a new one. (Like Java’s String class is immutable.) That’s what gives you multithreading for free. Every “system” can be a separate thread and Zay-ES doesn’t care. It will still efficiently pass changes around as needed.

There are a couple examples you can look at. Asteroid Panic is probably the simplest.

There is also a networked example of a not-quite-a game using my SimEthereal library:

…but it does show ES usage.

I wrote 5-6 blog posts howto start with ES on first post is Entity Component System Part 1 « fprintf it results in an invader like game. Mostly copy paste with some rudimentary explanations.

and transfered it also to zay es wiki Zay Es Case Studies · jMonkeyEngine-Contributions/zay-es Wiki · GitHub just work through the Invader chapter.

ES or any system (OO, functional… whatever) doesn’t hide true complexity. It makes it manageable. A full on MMO RPG game is complex and ES won’t make it simple. What it does is keeps concerns from interfering with each other.

The price is that you can get hilariously funny bugs when you have a “compose bug” for example. That is i have a component on a entity that shouldn’t be there. I had turrets fly off and hit bad guys because i put the “bullet” component on a turret by mistake.

You obviously want to have a clear MVC type pattern. But i should say this doesn’t mean no events.

I use events. BUT they are all in the update loop. It just made some things a lot easier. Events are only generated and consumed in the update thread. And they don’t change model state. Only View state. So something like “explode that guy”. Or “shoot sound”. Of course these don’t look like a event system with a event queue. Its really just callbacks. But that means its all on the update thread. Anything can change the scene graph safely and it just made some stuff easy. Perhaps it is more of a bus? rather than call back events? Meh.

So i am keeping it. :smiley:

1 Like

I do that also with systems and use components. For example I have a sound system which cares for sound components (the component is the event). Footsteps containes sound, position and a 200 ms decay component.
Upside I can also have text based sound system :slight_smile: