In this update I'll talk about the new interface for creating World instances, the World.Builder!
, which is a BSD-licenced small Java framework for setting up Entities, Components and Systems.
World instances were created on the spot before, like this:
Fairly straightforward.Thing is, this class was quite fragile:In short, too many movable parts and easy to break.I decided that I wanted a very specific initialization step for the World instance, moreover, now I had a very specific need: I wanted to initialize observers in a specific order, and I wanted to process observers in a specific albeit different order. The issue presented itself when I wanted to initialize the renderer before a few systems that depended on it, but I wanted to actually render after those systems were processed in the game loop.I also decided World would be immutable. You configured it, got your instance, and that's it. No observer tracking inside nor any sort of checks at runtime, just one initialization step and you're done.Ended up using the Builder pattern to create an additional mutable object that held all the data the World needed, which implemented a "build" step that created your immutable World instance. Interface looks like this now:Enabled/disabled state is handled by the observer itself, and now you can specify an order number.You got two flags, 'initializeByOrder' and 'processByOrder', if any is set to true, your observers get initialized/processed by the provided order respectively. What happens if you set it to false? They get initialized/processed by order of appearance. That way you can have one order for processing and a different order for initialization. Hooray!The 'build' step just sorts the observers as needed, initializes them, then creates the World instance passing the sorted observer array, which will indicate the processing order. The builder makes sure each observer passed isn't null, so to avoid any other checks later. The obtained World instance is immutable, ie, you cant add/remove observers, nor set the 'data' field, which brings me to...Another feature I wanted is arbitrary data passing. Each system has a World instance, and you *can* extend that World instance to add whatever you needed, but it becomes annoying to use when you have to downcast it like "((WorldSubClass)this.world).myMethod()" each time you have to use it inside an EntityObserver, since observers only know about "World", not any subclasses of it. So instead I added an additional (nullable) field:'data' is an object field, so you can put whatever you want in it. This also deprecates the old "delta" field in World, if you want to keep track of delta times, make your own data objects that does it.You can use it like this:'data()' is a generic method, it casts to "T" inside. So in theory you could do "SomeOtherClass data = this.world.data()" and it would compile, but you'd get a ClassCastException at runtime if data isn't of SomeOtherClass type. Its a fair trade-off I think.Another nice thing also is that that 'data' object can be used as a context, to say, share data among systems, create your own event system, whatever you need. I currently use it to share the resource manager, a window object reference and time deltas between frames for example.Well, thats the new World Builder, I'll describe the new Injector later, cya!