Truck making Games
TruckSimulation 16 is a simulation for mobile devices in which players can roam around in a big open game world. Christoph Eder explains how his team met this technical challenge with Unity and which problems they had to solve along the way.
For a truck simulation like »TruckSimulation 16« the gameplay is clearly defined: The player will be driving. For that reason the surroundings should be appealing and not be repetitive. The defined playground is the motorway network of Central Europe. Every street was to offer a certain level of reality in terms of course, landscaping and distinctive landmarks. Such a big, non-procedural game world requires considerably more space than the memory of a smartphone has to offer. That’s why it is divided into smaller bits that are dynamically loaded as required during the game.
In an ideal case, these landscape patches are completely created in a 3D modeling program. That way you have full control of the degree of detail and the visibility of the various areas and you can, for example, create tidy break-off edges at road ditches. Unfortunately, this approach is too time-consuming for the size of our world and thus too costly. One should also keep in mind that the Level Designers have to be familiar with a 3D modeling program.
Despite justified performance warnings we decided for the terrain that’s integrated in Unity. These terrains are defined through a heightmap and can be quickly created, amended and automated through scripts in the editor. Besides, the render quality of geometry (pixelerror) and textures (basedistance) can be easily adjusted to the performance of the device. The compromise between quality and memory usage meant a resolution of one data point per unit and meter.
The world with its landscape, houses, streets etc. was divided into square tiles sized 1024 x 1024 meters (image 1). A square kilometer is big enough to comfortly accommodate a huge city or a motorway junction, and not too small to make life hard for the Level Designers. In hindsight though slightly smaller tiles would have been better to reduce the memory usage and the load times. In an open game world it’s common to load and display three or eight adjacent tiles. After running a few tests though, we confined ourselves to only one adjacent tile. This is possible since we can limit the camera position through our road course. The player won’t notice it in practice, and it saves a lot of effort and memory. We set the visibility range in the highest visual quality to 600 meters, which is quite remarkable for a mobile game.
To drive through a landscape tile the player only needs about 20 seconds using the 200 km/h (124 mph) racetruck. A mobile device of a lower performance class (like the iPhone 4s or Samsung S3) can only just manage to load and display the next tile in the background in time. If there is a massive loss of performance due to other apps, the truck would drop through the map. In order to not interrupt the gameflow, tiles must be loaded in the background – asynchronously. Unity supports this by saving each tile in a scene of its own. In each of these scenes there is only one root node to easily unload it. Alternatively, we could also work with a pool of instantiated objects and a separate load system. Unfortunately, when setting a heightmap of a terrain, a Unity application always stops for a few milliseconds. That’s why slower devices experience choppy playback from time to time when reloading scenes. And we forgot to factor in »Mr. Physics«. Most scenes include hundreds, if not thousands of static colliders for guardrails, street lanterns, houses etc. The internal integration into the room partitioning procedure of PhysX takes roughly about several milliseconds.
Unfortunately, it’s slightly cumbersome to edit the terrain; fortunately, smaller tools from the Asset Store can help here. We tried out various terrain generators like »Terrain Composer«, but none of them were convincing. The floor consists of a mixture of small, repeatable textures (splat maps). The use of satellite photos is technically feasible and was also tested, however, it would take a lot of memory, even more media storage and way too much time to load.
In the course of the project we discovered several flaws of Unity Terrain:
- The virtual camera in Unity Editor has a fixed setting based on which the terrain renders artifacts which make an exact placement of objects more difficult.
- The built-in support of trees isn’t usable on mobile devices. If such a tree is placed on a terrain, the frame rate on the device is halved when rotating the camera.
- Only a few floor textures per tile can be used. When there are more than three, the performance drops.
- On some Android devices with Maali chips the floor texture is rendered incorrectly as a rough chessboard pattern. The workaround is to only use odd splat map indices. We moved the grass texture that’s used practically everywhere to second position.
- The terrain offers a performant collision detection which prevents the truck from dropping through the ground. In rare cases, this became only active after a few frames on mobile devices, so that the truck dropped down nonetheless.
As a test, the finished Unity Terrain was transformed to static geometry in a complex automated process (image 2). The number of polygons was considerably reduced using the mesh simplification tool »Cruncher«; for optimization purposes, we tried to leave the triangles close to the street untouched and removed any triangles below streets. Altogether, the rendering of this approach was more efficient, but it also increased the compressed size of the app from approximately 2 MB per tile to 3 MB. In an uncompressed state, this corresponds to 5 MB and 7.5 MB. With further development work, one could thin the polygon mass through occlusion culling in a more targeted manner in order to make this approach the preferred procedure. Unfortunately, the Cruncher API doesn’t have enough impact on the process. In the distance, Unity displays its Terrain with increasingly less triangles (dynamic level of detail, ROAM), which may result in penetration flaws with the street. That’s not the case with a static mesh.
For tunnel entrances, no visual or physical holes can be drilled into the Unity Terrain, even if some assets from the store say so. In order to compensate for that, we drew the Unity Terrain in the tunnel below the street and replaced the area above the street with the terrain converted to the mesh. Meshes in Unity can comfortably be edited with plugins like »Mesh Toolkit«.