Recent Posts

As you can see, the site has got a major visual upgrade in the form of a banner and background art. The same elements are also used on the YouTube channel and Google+ page, and were contracted from Taylor Osborn. I have also added sharing options with ShareThis-widgets that are available on the sidebar of every page.

This is a technical overview about the current state of the game. For a general description of the concept, please take a look at the previous post Introducing Battlefleet Engineer.

Core technologies

The vast majority of the game is made with C# using XNA 4 and .NET 4.0 frameworks. XNA is nowadays getting a bit outdated with only DirectX 9 support, but the choice was actually made a couple of years ago. The main points in its favor were my (limited) existing experience from C#, good documentation, maturity and price (free). There is also the option to port the game to MonoGame that is still being developed and supported, and would allow to make a multi-platform release, while XNA is practically limited to Windows only. The game isn't actually pure XNA, as it uses some .NET features as well that are not available in the XNA framework.

XNA doesn't really have extensive, mature, and still supported UI libraries these days, and I didn't want to use Windows Forms or WPF (Windows Presentation Framework) as those aren't really designed for real time game use. I considered multiple options, and finally settled to integrate Awesomium into the project and use that for all of the more complex and less performance dependent UI features. Awesomium is basically a fully featured web browser engine without UI that renders into a memory buffer. It uses the WebKit layout and V8 JavaScript engines from Google Chrome. This means you can very easily load and display basically any website, but my use case is to create the game's UI as web pages using the familiar HTML, CSS and JavaScript technologies and couple those to the core game logic. This makes the UI moddable, and enforces a nice separation of the game logic and UI code that helps to manage the complexity.

Currently there is about 24500 lines of C#, and 1800 lines of JavaScript code in the game.

UI & game graphics

The UI is made with JQuery UI, and communicates with the C# side throught a event-based interface that Awesomium provides. It is possible to easily execute JavaScript code from the C# side and call registered C# event handlers from the JavaScript side. I also use .NET's JSON serialization functionality for moving more complex data between the two. There are some limitations to JSON serialization, but basically I can just serialize any C# object, send it to the UI, modify it with JavaScript, send it back again and deserialize to get a C# object. This means that I don't need to write any transformation or "glue" code for each class to use their data on the UI. I was able to implement a debug/development UI very quickly using this method. The biggest downside is that communication between the UI and C# code has some significant overhead, and thus it is not practical to eg. send JSON encoded data structures to the UI on each frame, but for event-based UI update it doesn't really matter.

Debug UI overlay that uses dat.gui library for the controls.
On the C# side, all drawing is done through the XNA's methods. XNA provides basic functionality such as 2D sprite rendering with draw call batching, GPU state and render target management, asset (texture) loading, and supports custom vertex and pixel shaders. One of the main technical difficulties with this game when it comes to graphics is the very large number of modules that need to be drawn on each frame. One of the design goals is to allow battles that have several thousands of modules total, and each module must have its own texture sprite(s). The ships can't really be pre-drawn to textures either because the structures change, I want to support simple animations and visual module state changes, and it would require a lot of texture memory to hold full-size ship images of even a medium sized fleet. This is where the XNA's sprite draw call batching is vital; when all module graphics are on a single sprite sheet, it can draw all of their visible instances within a single draw call to the GPU. However, the requirement of a single sprite sheet also drastically limits the sum of all module graphics' surface area.

The main feature of the game graphics system I have implemented is real-time lighting of the ships. This is done by using pixel shader based deferred rendering that combines diffuse, normal and self-illumination textures for 3D shading. The system is very similar to what is nowadays a standard in 3D games, but applying it to 2D has some special caveats I'm not going into here. I have made all of the module graphics as 3D models with 3ds max and then rendered the diffuse, normals and self-illumination textures from those. The models themselves aren't used in the game at all.

My particular implementation uses separate render targets for diffuse, normals, self-illumination and lighting passes. The diffuse pass has the color with ambient occlusion "baked in", while the normal map describes a surface normal for each pixel, and self-illumination has the color of those parts that the lighting doesn't affect. Self-illumination is also used for the bloom effect. Based on the scene lighting parameters and the already rendered normal map pass, a light map is drawn utilizing a pixel-shader implementation of Blinn-Phong shading. The intensity values from each light is summed to create a single light map that is then used with the diffuse and self-illumination maps to create the final shaded image. The shading/lighting system currently uses simple diffuse and specular, but can be extended to eg. utilize an environment map for reflections etc. The deferred approach allows theoretically unlimited number of lights with linear performance cost, and I'm looking forward to implementing eg. plasma projectiles with point lights and other similar effects using the system.

Physics & Movement

One of the core features of the game that sets it apart from other similar titles is the uncompromising physics simulation that doesn't cut corners to make the game easier to create or play. The actual simulation is handled by Farseer Physics Engine that is based on the very popular Box2D physics library. Implementing my own physics engine would have been foolish, simply because these free, fully featured and tested libraries have more code and effort put into them than all the other features currently in the game combined.

All movement control goes through the physics engine. This is true for both input from the player and from the ship's internal flight controller logic. In order to simplify the control of what can be dozens of thrusters on a large ship, they are grouped by function so that we get four translation groups (forward, backward, left, right) and two rotation groups (CW, CCW). The grouping can be done automatically by an algorithm that tries to find and group thruster pairs so that they have minimal negative effect while simultaneously maximizing the wanted effect. For example, the translation groups should yield maximum acceleration in the corresponding direction, and cause zero angular acceleration (and thus rotation) on the ship. Each basic thruster has a single degree of freedom, as the power can be modulated, but finding the best solution gets very tricky when omnidirectional thrusters with 2 DOF are added into the mix. The thruster grouping algorithm works in two steps: First is tries to find the best thruster pairs using max throttle on each thruster and sets them to groups. The second step is to balance the group by calculating thruster throttle weighting and using omnidirectional thrusters & reaction wheels to cancel unwanted linear and angular effects respectively.

The movement control of dynamic, modular ships that can take nearly any shape and have poorly designed thruster configurations is a very complex and difficult problem to solve. The fact that my physics simulation does not have any friction to balance things out and stop movement or rotation also makes this even more difficult. Even the tiniest of impulse can make the ship move indefinitely in some direction unless it is stopped by an exact counter impulse. The movement logic builds on top of the thruster grouping logic and cached values for each group's effect on the ship when it is fired. The current system for maintaining position and heading drives the ship by its local X and Y axes independently to the target coordinates, and thus requires all of the movement groups to function. Move-to-point logic uses the same principle, but is actually a rather complex state machine that first turns the ship toward the target, moves it, stops "drifting" if necessary, approaches the target etc. It works quite well for reasonably well designed ships.

In order to implement perfect control that can always stop the ship at precisely the wanted point, we would need a perfect model of the system to use for prediction. While the effects of individual thruster groups can be calculated precisely, the biggest control errors arise from unpredictable aspects such as overlap between thruster groups, lack of resources to run the engines, collisions between ships, and ship structure changes mid-maneuver. Prediction is required for everything, as each linear or angular movement needs to be done in two stages: acceleration and deacceleration. In order to know when to start deaccelerating, we need to predict how long it will take and then compare it to the current state. At this point of development, the thruster group overlap is the most notable source of error, as same thrusters can be used in multiple groups and the use of those groups can't really be predicted. For example, maintaining the correct heading very often interferes with linear deacceleration required to stop at the target position, causing the ship to overshoot.

Resource system

The resource system is currently used primarily for electricity, but can be easily expanded for all kinds of consumables. The main premise of the system is that there are producers, storage and consumers. Resource exchange depends on two types of connections between modules: Full and structural only, which dictate if the module can take part in the resource distribution. 

The basic working principle of the resource system is this:
  1. All generated resources are counted and temporarily pooled ship-wide.
  2. Resource logic queries all active modules about what resources they require, request and offer. For example: Thrusters don't have storage and require a certain amount of electricity when fired, while capacitors request electricity to fill their storage.
  3. Resource needs are fulfilled (required first) primarily from newly generated resources, and secondarily from stored (offered) resources. If generation was greater than requirement for a resource, the rest is sent to storage. (storage modules request resources they can store).
  4. Excess generated resources (that cannot be stored) are discarded.
The resource distribution order can also be modified by player-definable priority resource groups that first distribute within themselves and then any excess is given to the ship-wide distribution pass. In a nutshell: The game doesn't simulate moving of the resources from module to another per se, but the ship's structure plays a role, and the resource amounts are stored in the modules themselves. 

The flexibility of the system makes it possible to simulate balances such as heat production and dissipation that allow e.g. boosting weapon fire rate by adding heat dissipation modules to the ship. This is also one of my ideas to make more use from limited number of weapon modules. A large ship can make a better use of the same weapon module than a small one, because it can have more available power for charging it up faster and can dissipate the generated heat more effectively.

That's it for now, I'm looking forward to this first month (September) of much more intense development, and I will report on the progress at the end of the month. The main topic will be weapon and damage systems, the game will finally have combat aspects!

Posted by Tomi Monday, September 1, 2014


Post a Comment