Showing posts with label design. Show all posts
Showing posts with label design. Show all posts

Thursday, October 4, 2018

FreeRails: Are we on the right track?

Track management is among the most often performed actions within any railroad simulation. It's also very close to the heart of the programming and design of any railroad simulation. Lately, I was interested in getting a better overview about how the track management in FreeRails work as well as possibly streamlining it and documenting it properly.

The map consists of an rectangular grid consisting of square-sized tiles. Each tile (except those at the border) have exactly eight neighbors which can be uniquely identified by compass points (north, north-east, ...) given the current center tile or by grid positions (row, column).

The total track on the map consists of many track pieces, where each piece connects two neighboring tiles (diagonal connections have ~1.41 (square-root of 2) times the length of horizontal or vertical connections).


Path finding of the trains works on a graph where the tiles are nodes and the track pieces connecting neighboring tiles are the edges.

Building and removing track works by adding and removing track pieces. In particular, the planning of a longer piece of newly built track is done by path finding again.

The track itself is visualized by rendering each tile according to its track configuration. The track configuration is an 8 bit value indicating if there is a connecting to one of the 8 neighbors from the current tile. See the attached image for some examples.

Track configuration encoded as 8 bit value
The track configurations are not independent from each other. For every connection on a tile towards a neighboring tile, this neighboring tile must also have a connection to this tile. This invariant must be obeyed by not allowing to change track configurations directly, but only by allowing adding or removing of track pieces at a time.

Track pieces have no direction, any train can go on them both ways. However, a train can change direction at every tile at most by 90 degree, effectively inducing some kind of directionality.

Track pieces can be single tracked or double tracked. There can only be one running train on each track piece (and trains have a certain extent, also measured in track pieces). However, stopped trains do not count as obstacles.

The track configuration of a tile is sufficient to draw it uniquely on the tile. Not all possible 8 bit values are valid.

Bridges and stations are a special case. Stations have a orientation and only allow track parallel to their orientation. Bridges span a water tile (other track cannot be put on water) and consist of two track pieces resulting in a parallel configuration.

That should be all for now. There is of course more (like trains). FreeRails currently follows the concept outlined above quite well. For some reason the track configuration is a 9 bit value (center part is also encoded and used to indicate no track at all) where I think that 8 bits would be sufficient and it's possible to change track configurations directly, whereas it's better to only change track pieces and change the track configuration only at a single place in the model.

Will be continued...

Friday, April 20, 2018

FreeRails: Back to the drawing board

This is a bit technical post.

Now is the time to go back to the drawing board, write down the existing design and even change it. One such issue is the overall design of the client/server framework. Looking at what is there and what is regarded as modern design I came up with this proposal.
Schematic of the proposed Client/Server design in FreeRails
The client is basically a Model-View-Presenter scheme with the View being very passive and easy to change if for example and Android or Web port is attempted. The presentation logic is in the presenter which updates the view and reacts on user input. The presenter/controller is a big black box here and needs to be detailed later. The client also contains a full copy of the model/game world, making him a thick client. He acts upon changes in the model and proposes changes to it. However, the model just reroutes these proposed changes to the server.

The server checks the proposed change for applicability and either accepts it or rejects it. It then applies the change to itself and sends it to all clients so they can apply it to their copy of the model and the user will see them. It follows that this way all the client models will be in sync with the server model, although they may lag behind. To make sure they don't miss anything, the broadcasted, accepted changes will be enumerated or similar.

One can see nicely, how the information flows in a circle, from the view (user input) through presenter, local client model, server model, local client model again, presenter again and finally a change is displayed.

I think this requires the lowest amount of coding effort while still delivering robust performance and good separation of concern and modularity.

P.S. For drawing the design diagrams I use draw.io which is an excellent tool and works for me like a charm.

Monday, February 5, 2018

FreeRails: Current development goals

I'm intending to bring the project to a state where it is relatively simple to implement all the intended features for a "version 1.0" release. I hope others will join and will bring it to the full feature release then. With limited resources on my side, bringing the game to this intermediate point may take some time.

The milestones I want to reach in any case (may take some time) are:
  • More complete description of the game design in the documentation
  • Clear separation of model, view, controller, server, client, serialization code
  • Reduction of dependencies and complexity of the code
  • Improved graphics and graphical user interface using JavaFX
  • Runnable, bug-free version with an installer
  • Some kind of roadmap towards version 1.0
If this can be reached within the year 2018, I will be happy. Also from then on, I can continue managing the project but probably not actively develop it any further due to time constraints. However, I would also consider it rescued then.