This post shows an example for a layered game architecture as being developed for the game Diabolus Ex Machina (abbreviated as DEM).
The most important requirements are
- being capable for single and multi player games running the same code base and only switching the used net implementation
- platform independence, for targeting desktops and mobile devices with a common code foundation
- abstraction and hiding of low level details from, for example, OpenGL and TCP
- strong focus on dependency management, complete avoidance of cyclic dependencies, broken up into ~16 dedicated projects and accordingly built JARs
- separation of 3rd party libraries usage into dedicated sub packages and projects
- emphasis on interfaces for hiding implementation details and providing various implementations
- event driven communication overall
The following big picture shows three main components:
1. Libgdx as abstraction for the target platforms Windows, Linux, OSX and Android, as well as for OpenGL graphics, sound and game physics.
2. GameRoots as framework for game logic, ai, network, sprites, tile maps, actor and input handling, sound, etc. However, there is nothing related to any concrete game in there, thus no dependency is pointing up to the DEM component.
3. The game itself with its screens, implemented game rules, lobby and anything else uniquely required.
At the top level, GameRoots is separated into three packages:
- frontend, the client, responsible for graphics, sound, input and client side movement. Always running on the player's machine
- backend, the server, holding game logic and AI, controlling all player clients, receiving player input, sending world updates back. Either running on a dedicated game server, or for single player games on the player's computer. In case of the latter, without networking involved.
- shared, anything needed from both frontend and backend. For example, sent and received events, actor movement, utilities like collections classes and math functions.
Consequently, shared does not know frontend or backend but is used by both packages.
A scene is the place where all game actors live in. All dynamic game objects are actors, regardless whether they are living creatures or dead level items of any sort. Actors of the backend are a relatively abstract view of the game world, with little or no knowledge about graphical representations for example.
Scenes and actors form the model and representation of the game world with the highest number of incoming dependencies.
The place where actors come to life. Actor have a brain which is driven by various goals. An actor brain is always in one state and takes decisions with the help of recorded memories of visited opponents, taken hits, known paths, etc. Typical states are for example MovingState and WaitingState, typical goals ShootGoal, DodgeGoal, WaitGoal, FindPathGoal.
The AI operates on scenes and actors. After taking decisions new events are sent to other actors, to directors and player clients. Events are received from players, directors and the game AI itself.
Similiar role like movie directors, only that there is not one but are many specialist directors at the same time. There are specialists for collision detection, building a field-of-view, using inventory and level items, watching health points, applying physics, etc.
Receives player input events and forwards them to addressed actors and responsible directors. Vice versa, directors send events to the AI, other directors and player clients.
For actors finding paths from point a to point b.
Event driven communication with all clients. Uses the "real" network for multiplayer games or an in-memory model for single player games. Does not know about scenes. Only receives events created by directors or AI classes.
The game rules and factories for creating new actors at runtime based on predefined build plans.
The game server for bringing together network services, connected clients and directors.
The game world on the client side and the model of the applied MVC pattern. Inhabited by puppets, the client side representation of game actors. Puppets are controlled by server events and, for a responsive game feeling, immediately by player input.
The controller of the applied MVC pattern. Moves puppets according to server events, player input and game physics.Works on received server events and sends player input back to the server.
The view of the applied MVC pattern. Home of view puppets, the visual representation of scene puppets. Each scene puppet can be shown in different and multiple ways, in 2d, 3d, as map point, etc.
Listens for player input and forwards it to controller classes.
For communicating with the game server. Sending and receiving events as well as downloading game resources. Concrete implementations allow to communicate directly by event queues inside a VM for single player games or by TCP for multiplayer games.
Anything for the sonic game experience independent of any particular audio player implementation. Namely, loading and organizing of sound resources, setting volume and pan positions dependent on player positions.
This is the interface to the Libgdx game library. Usage of textures, lights, particles, playing of sound, etc. is encapsulated here and only here so that the main part of the frontend packages is independent of 3rd party libraries and would allow to switch to other libraries like Java2d for example.
Everything that is required and useful for both client and server.
For example, actor movement and game physics are applied in the same way on both client and server side.
Naturally, events exchanged between client and server are located here as well.