As a reminder, we’ve mentioned the following problems in the preceding part:

the worldUpdater relies on closing over the World instead of being supplied with it; similarly, the tickIncrementer not only reads but also changes an "external" value; the rendering logic is outside the system, because it needs to be invoked in a specific sequence in relation to the other operations, and we have no control over that sequence currently; related to all of the above, we have no way of signalling the stream setup logic what information we have in our executor functions; due to the lack of a definable ordering, we also run the risk of race conditions, despite everything being "executed" in the same thread - e.g. if we remove a body in one place, it can still be referenced in another, resulting in a crash of the app; we’re starting to have a god object, it would be good to remove the entire "stream engine" portion out of MainScreen soon.

If, right now, you’re staring dumbfounded at this list, wondering how we managed to solve any of these problems - then you’re on the right track!

The truth is, keyboard input integration has taken too much effort to tackle the pertinent problems. However, in the immortal words of Bob Ross, this is a "happy accident". Why?

Well, let’s see:

we now see that issue 4. will come to bite us in the hindquarters if we don’t do anything about it - already we needed to smuggle metadata in LibGDX’s objects, and this was only a trivial marker - what about potentially needed stuff such as health points, movement energy, etc. etc.?

the same applies to point 5.: we now have a specific, immediate problem to tackle - what will happen once we add collision detection and health point depletion? In our current state - chaos!

Furthermore (and related to point 5.), if you compare our current solution to other "reactive" implementation, you’ll find that it’s quite inflexible - in particular, it doesn’t support any sort of combinators ( .map , .flatMap , .filter , etc. etc.). Taking together that conundrum with the previously described issue, the following are all examples of "component" types we want to support:

(List[Body]) => () => Unit (1) (List[Body]) => SomeData (2) (SomeData) => () => Unit (3) Flow[(SomeData, KeybardInput), () => Unit, _] (4) Flow[(List[Body], TickDelta), SomeData, _] (4)

1 Sometimes we wont need the tick info…​ 2 …​sometimes we’d want to create custom data…​ 3 …​sometimes all we need is that custom data…​ 4 …​and sometimes we’d wish to use the power of stage combinators.

At the end of the day, we have a more comprehensive view of what we need to clean up, and more importantly, how. And that’s what the next part will (now, definitely, I promise!) cover.