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 {
// ...
@Override
void simpleInitApp() {
// ...
}
@Override
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 {
@Override
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 {
@Override
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?