sábado, 29 de agosto de 2015

Input processing in Cabo Trafalgar (and 2)

Another of the risks to face when creating Cabo Trafalgar is making the inclusion of any new element expensive, in terms of work needed due to interactions with elements already existing in the game.




If you didn't design the way of creating new ships correctly, you might end up adding code per command relative to every possible different input available in the system. Likewise, you don't want to modify your ship's commands if you added a new input to your game.
Keeping the work in O(1) is paramount (yes, complexity can be applied to you as a worker).

My strategy for solving this problem is converting one 2-dimensional array into two 1-dimensional ones. Conceptually like this:

In plain English, what this mean is that I decouple actions from actions consumers.

On one side, all I care when I create a new Ship is that it creates "Commands", these are classes able to execute Ship's functions, they represents what a user might want to do. What a ship might or might not do will be determined by the collection of Commands it returns and nothing else. O(1).

On the other side, all I care when I'm creating a new input adapter is that it's able to use commands, generically. It's a simple interface with an execute, so I can focus in the WiiFit complicated bluetooth bridge or the Remote Controll connection, without needing to thing on the other end of the command. O(1)

This is the design implemented in Cabo Trafalgar with the flexibility and "inexpensiveness" in mind.



The story beings with a set of Command, provided by a particular ship (see AShipModelInteractive in the previous post http://cabo-trafalgar.blogspot.co.uk/2015/08/input-processing-in-cabo-trafalgar.html), these are the functionality our ship offers and we need to map it to inputs.

The first step is asking GeneratorBuilder what CommandGenerators are there available for each Command. A CommandGenerator represents a different input, they must be registered in GeneratorBuilder declaring what subclass of Command they support (so far, all CommandGenerators support all Commands, I haven't found an example of subclassing).

So here we have KeyboardCommandGenerator, registered in the GeneratorBuilder (using "registerBuilder" and declaring itself available for each Command it's asked.

As a user, we asked for CommandGenerators for some commands, and we retrieved a list of CommandGenerators per Command, now if that list was longer than 1, we should decide per command how we're going to use it. In this example, we have only KeyboardCommandGenerator so there's little point to choose, only one option per command.

Now we have a command and a "chosen" CommandGenerator, it's time to associate them by invoking on generateCommandStateListener, it takes the Command now, they keycode comes later.

Now we have a collection of KeyboardCommandStateListener, it's time to associate it with keys, up to the user, and the job's done. Each time that key is pressed, the Command in the Ship will be invoked.

The advantage of this design is the ease of adding more CommandGenerators, as I have a screen for choosing the right CommandGenerator per command, I can mix them in the same game.



No hay comentarios:

Publicar un comentario