Developing with DirectX Part 1
As part of another of my University modules, I undertook a piece of coursework that involved developing an application using Microsofts DirectX 3D API. This module was undertaken over the whole of the final year, which is indicative of how large a task learning a 3D API can be. The module started out with learning the basics of the API; its structure, history, main function calls, code examples etc. The final evaluation of our DirectX skills was conducted in the form of a large assignment involving creating a 3D application; not necessarily a game.
The exact words of the specification and the lecturer were “Make something that does something…” a mantra that the lecturer loves to use in all of his modules! However it is usually followed by a constraint, which in this case was”…in 3D using DirectX”. So we could make a game, or go down the route of some sort of data visualisation, a map or even an educational application. I went down the gaming route, which as you read more of this blog you will discover is a passion of mine. To little surprise to my friends I opted to develop a F1 based game, my other interest in life! Of course Formula 1 is the pinnacle of motorsport and involves huge sums of money and the best aerodynamics, engine and tyre technology in the entire world. Could I really make a game about it in a final year Uni module?
About the Game
From the point of view of the end user, you are looking at a F1 racing game that is focused around setting the quickest lap time possible. Upon launching the game you will see the menu system which will allow you to select a track and car to race with. This menu has been built using the new more user friendly DirectX interface components; they have been designed to be easy to use. So select a track and car from each of the drop down boxes and click start game. The tracks are complete with an infield, pit buildings, grandstands and appropriate skydomes. There will be a short pause before the game actually starts, there is no loading screen so be patient and wait for the game to start. Make sure that you have sound turned on and you will hear a Murray Walker sound bite to indicate the start of the game.
The game will then start with your selected track (either Silverstone or Montreal) and your car will be on the starting grid. The controls for the game are as follows:
- Accelerate: Up button
- Brake: Down button
- Turn Left: Left Arrow button
- Turn Right: Right Arrow button
- Toggle Onboard Camera: A Button
- Toggle 3^rd Person (Chase) Camera: D Button
You can then proceed to drive around the circuit, once you cross the start/finish line the lap timer will start.The game uses a selection of sound files to create a more in depth experience when driving (or crashing) your car. Upon each successive lap the lap counter will increase and the game will store your current, best and last lap times. You will notice that you cannot cut corners and drive through walls and buildings as the game has collision detection. The collisions will stop the car very quickly and ruin your lap time so stick to the track and it will pay off.
Structure of the Application
The structure of this application is a little more complex than the previous version (the game was developed in two separate iterations, for coursework requirements) but it is more efficient and logical from a programmes perspective. The main thing to look at is that the game is now using an object oriented structure. I have created a class called “Entity” which is used to define an object in the game world. This class has several methods and variables that define the attributes and behaviour of a game object. This entity class is used for the track, sky, track buildings and startLine. However the class is not perfect for every situation so there are two other classes that are abstractions of “Entity”. Firstly there is the “Wheel” class that is used to define wheels for the car, it overloads the render() method so that the matrices are not setup on every frame. This is because a wheels matrix will need to be multiplied to the cars matrix to ensure that the wheels move along with the car. The second abstraction is the “Car” class, this one was created as Entity does not provide all of the variables and methods needed to define a car, but it would not be necessary to include them for all Entities. While this new OO structure does allow for a lot of the processing to be taken out of the main cpp file there is still some processing handled there.
The application starts off in the WinMain() method, whereby the initalisation of the hardware, direct X and the creation of the game window happens. Upon the start of the application, and on subsequent device resets the light fotr the game world is created. The start menu is then shown by initApp(), this will then call the startGame() method when the user clicks the start game button. startGame() itself determines the users choices for car and tracks and calls the correct methods. The bulk of the games processing are carried out in the onFrameRender() and onFrameMove() methods. Both of these methods are called every time a frame is redrawn, and due to the fact that the frame rate is unlimited this could be hundreds of times a second.
Other information about the game:
- The models for the game have been made using Google Sketchup and a plugin that allows it to export to a DirectX mesh (.x)
- The track itself is one mesh while the each of the track buildings is a separate mesh. This enabled easy implementation of collision detection ****
- The sound files used in the game are .wav files that have been found on various sites on the internet and are not owned by myself.
Performance vs Good Practice
In the development of the application there had to be some trade-offs between performance and good programming practice. Firstly the implementation of the car shadows is quite simplistic, it is simply a flatten matrix of the car rendered with alpha blending. This creates the effect of a translucent shadow onto the track surface; however the effect completely fails if non-flat terrain comes into play. I chose to use this however as it a lot lighter on system resources, volume shadows use a lot of memory and graphics power. In the same vein I reduced the resolution of the in game textures to increase performance and reduce memory usage. This did not reduce the visual quality too much and reduced the memory footprint by about 30%. The final aspect that increased performance is that this version of the game is using object orientation, a lot of the processing (loading meshes, movements, collision movement etc) has been moved into separate classes. Previously all of this code was contained in the main cpp file and being run on every frame, however with the object orientation only the necessary code is run. It is also good programming practice to create an application in an object oriented manner, having a bulk of code in one place is frowned upon. Object orientation models the real world in a more realistic manner, by defining the attributes and behaviour of an object in a class. The use of OO has also allowed the usage of inheritance, the main class “Entity” can be used to define most things but some areas of the game (cars, wheels) require behaviour that this does not provide. So subclasses can be created that inherit the attributes and methods of “Entity” while adding new ones and overloading existing ones to create new behaviour. This reduces code duplication massively hence making the game more efficient and boosting performance.
Part two of this blog post will be looking at the starting point for development, evaluation of the product and some screenshots of the final game.