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.



Input processing in Cabo Trafalgar

If you haven't read multiplayer-modes-in-cabotrafalgar, you should do it now, as "mode 0 - 3" are explained there, otherwise you won't fully understand this article.

This should be the first of a series of articles to explain how to extend Cabo Trafalgar with more and different controls, modules and ships (these are, not by chance, the three dimensions Cabo Trafalgar relies on).

The aim of this article today is explaining why it's not a good idea to rely in the Jme3 Input Manager directly if you're planning to have several multiplayer modes like Cabo Trafalgar does.

In little words, we need to cover the following cases:


Player's input to local game
Player -> Keyboard Input -> Ship calculations locally -> Render locally


Ghost representing past game by same (local file) or (recordserver online service) another player
Downloaded game -> Ship position is set externally -> Render locally


Remote input to local game (multiplayer mode 1)
Remote player -> Remote input -> Ship calculations locally -> Render locally


Multiplayer (multiplayer mode 2 and 3)
Player -> Keyboard Input -> Transmitted to server
and
Server position calculations for all ships -> Ship position is set externally -> Render locally


Player's game is stored in local file or remote server for future ghost/reference
Player -> Keyboard Input -> Ship calculations locally -> Store to file / server


As you can see, if you want to cover at least two of these modes, you need to detach the following elements and combine them according to your needs:

Renderization (AShipModelZ): What we render is a representation of a ship (and other elements), whose position, rotation and scale is known to us, but not how or where they have been calculated. They can come from:
  1. Remotely calculated ship (ShipModelZGhost): This element takes a stream of data from a server (mode 2 and 3) or a file (mode 0) to know what's the position of the ship every frame.
  2. Locally calculated ship (ShipModelZPlayer): This element calculates following position, rotation and scale from previous + input. Input can be:
    1. Local input (keyboard, wiifit, joystick...) (InputManager -> KeyboardGenerator -> ShipModelZControlProxy)
    2. Remote input (mode 1) (RemoteInputCommandGenerator ->ShipModelZControlProxy)
Also, in mode2 and mode3, there's a need for transmitting user's input. It hasn't been implemented yet, but it would take InputManager -> KeyboardGenerator -> ShipModelZControlProxy -> ShipModelZTransmitter (inexistent yet).

Input will deserve another post itself, as it can be more complicated than it seems :)

In the diagram below, green classes belongs to the api, no real meaningful functionality on them, in yellow, ShipModelZ implementation of them:





viernes, 28 de agosto de 2015

Multiplayer modes in CaboTrafalgar

Multiplayer modes in CaboTrafalgar

Commands and Generators

Some common vocabulary needed for understanding following text.

Commands are the smaller representation of an action that a user can do, and it´s declared and generated by each Ship individually. Some ships will offer "rudder left", "right", "mainsail in", "out", while other can offer the same four plus "move weight right", "left". Commands are, therefore, up to the Ship creator and this game takes them and tries to find who can implement them.

Generators come into play then, once we have some commands, we ask the Generator Manager (or similar) how many generators we have available for each one.
There are some generic Generators like Keyboard, able to map all Commands, also Remote is able to map everything, but we might find other Generators restricted about the type of commands able to deal with.

Once we have Commands and the possible Generators, it´s up to the user map each command with the desired generator (they could be keyboard, remote, and also wiifit, joystick, or mouse, just as example).

Finally, each Command is mapped to the chosen generator through a finest specification, in case of keyboard, associating a key.

Multiplayer Mode 0, Offline competition (DONE)

This was the first multiplayer mode done in CaboTrafalgar, for which I have "recordserver". It stores all verified user´s games and best are shared so other users can see, learn and compete against them.

It offers a ranking with times and users to enhance competition.
Information uploaded comprises position, rotation and commands executed per frame, this would be later (not yet) validated by recordserver, who shares back positions per frame, but erases commands.

This way, another player can´t simply take other person´s record as his, commands are needed and game reexecuted to validate authenticity (not yet again).

In order to make this mode, I needed to introduce a Ghost class able to reposition a Ship every frame, which gave me the idea of the current class atlas (to be explained in other post).

Multiplayer Mode 1, Shared controls on a local game (DONE)

We now offer the option of sharing an arbitrary number of Commands to another player, but all calculations are still made locally (your computer, not any of CaboTrafalgar servers) and the rendering is also local to your sole screen. This is, you must be sharing with somebody in your room.

The transfer is made through a barcode able to be read by any SmartPhone that can open a web application with those shared controls on it (this uses our servers), or you could use our app for that (in progress).

As a result, commands travel from your guest´s device to our servers, only to be transfered back with no alteration to your computer, where they´re interpreted just like your own input. As much this is a local collaboration that these results would be uploadable to RecordServer as they were yours alone.

 

Multiplayer Mode 2, Multiplayer game

Little explanation here, who doesn´t know what´s this about? Game doesn´t happen in your computer anymore, you´re just rendering the movements our server will tell you, like they were Mode0 ghosts, and your input will travel far from your computer like it was a Mode1 SmartPhone.

Of course, not everything is always so simple, and some calculation could be done at your computer for fluidity´s and optimization´s sake, but the principles are the same, we need a server online where the calculations are done, and new speeds and positions are redistributed for clients to render.

 

Multiplayer Mode 3, Shared multiplayer game

This is the goal I aim from the first day, this game was always defined as a collaborative multiplayer naval battle simulator. A captain that delegates functions in other players inside the ship, and with help of other ships, fights another number of players collaborating in other ships.

Game again happens remotely, but controls can be shared remotelly as roles, or locally as controls, as a mix of Mode 1 and 2.