A FINAL REPORT
OF
MINI PROJECT
ON
CAR RACING GAME
BACHELORS OF TECHNOLOGY
COMPUTER SCIENCE ENGINEERING (AI & DS)
Jatin Kumar (Roll no.) 2202161630044
Arya Kush (Roll no.) 2202161630022
Under Guidance
Mr. Rakesh Patel
(Assistant Professor)
IIMT COLLEGE OF ENGINEERING
Knowledge Park III, Greater Noida
INDIA
INTERODUCTION
Games have become an integral part of everyday life for many peoples. The theme of our
game is to compete with the other opponents that are controlled by computer in a racing
Tournaments, the main object of this game is to survive as long as possible and get to the
High scores in the shortest possible time while avoiding the obstacles on the track .For this
Car Racing Game, we designed and accomplished a video game imitating the existing game
showed as Figure 1 with a projective view. In this video game, the player control one of the
cars to compete with other opponent computer players. The major elements of this game
consist of accelerate, break, score, speed, rank and bump. The player uses keyboard to control
the car to turn left or right, to hit a break or accelerate while obtain over 5 golden coins. The
theme of our game is to compete with the other opponents that are controlled by computer in
a racing tournament, the player’s goal is to get to the destination as soon as possible while
trying to avoid bumping to other cars or road object, which slows down your speed, within a
certain time limitation. The difficulty level of this game is determined by the time limitation,
golden coins probability, which refers to the chance you can accelerate and get higher score.
Figure 1 is a screenshot of our Car Racing Game when it begins. The top three columns are
rank, timer and score respectively. The bottom right demonstrates the current speed.
Every View of Design
This part shows the overall design of our software and hardware. This game consists of three
major modules. First part is the Game Logic Generator which calculate the logic of this
game, such as to detect bumps to obstacle, speed control based on keyboard input, opponent
control and road generation, and this module is based on software. The second part is the
Screen Rendering Module, we adopt the Sprite Graphics technique to decompose the display
screen into 7 layers, which will be explained in derails in later section. The last part is the
Audio Module which generate the proper sound under the control of game logic. The overall
design of the game is demonstrated in figures.
Tree and Cloud layer Sprite Elements.
The following content of this paper explain each module in details.
The overall design of Car Racing Game including Software and Hardware.
Display Modules
Sprite
The core of our video game display technology is Sprite, which utilizes small size of different
elements to produce repeatedly pattern of pictures, minimizing the requirement for large
screen pixels RGB information. The Sprite use multiple layers to overlap the pictures and
generate a movement effect by control the movement of small elements in different layers, by
this way obtain a video game display function.
The following figures shows the layers we use in our Car Racing Game, and the rank of
layers, the layer whose priority is higher will be displayed top over those with lower priority.
Sprite Merging (the priority ranks from low to high from left to right).
Each layer stands for one or several Sprite picture cluster, figures demonstrate several Sprite
Element that we use.
According the Figures, the Sprite Control Module’s job is to generate the 640*480 pixels
RGB value for VGA Controller based on the control signal provided by the Game Logic
Module. The Game Logic Module provides the X and Y coordinates for different objects, like
trees, clouds, cars, scores, speed, which is also called Sprites. These Sprites are like label
pictures store in ROM, and can be pasted to the screen according the X and Y coordinates.
We list Sprites we will use in our games.
\The estimated total ROM size = 348 KB = 0.35 MB, each Pixel is defined by 8-bit R + 8- bit
G + 8-bit B.
Sprite Controller
The diagram for the Sprite Controller Module is demonstrated in Figure
The Sprite Controller Module merges the different Sprites to generate the final RGB
information for displaying on the screen. On the Linux side, the software generates the
coordinate (X, Y) of different Sprites and passes coordinates to the Avalon Bus through the
Kernel Driver. Then these data accompanied with address information in update the register
file related to the specific Spite, the Sprite Controller fetches the RGB information from
specific Sprite picture ROM, which finally merges all the pictures according to the priority
and send to VGA module. The picture is finally showed on the screen. To make the Sprite
move, the software just update the (X, Y) coordinate register file continuously.
Background Generator
The lowest layer is the background picture, which cover the whole 640*480 screen, which is
so large if we use ROM to store all the pixels RGB information. Therefore, in our design, the
background, which contains road, land, sky and border line, is generated by hardware module
using algorithm. That is different from other Sprites whose RGB information is fetched from
ROM. We design a special module for Background Generation. The background is showed in
figure.
Challenge and Solution
I think the most difficult part in Sprite Module that I have concurred is how to debug in
hardware, especially debug the System Verilog code. Because Hardware Description
Language is totally different from other language that I have learned like C or Java, and the
Quartus doesn’t have anything like Debug Step by Step, this confuses me a lot at the
beginning of programing for this project, I seems lost every time my code doesn’t run as I
expected, and I have no idea what is going wrong. Then I learn from other experienced
classmates and searching in the Internet to find some hardware debug methodologies, I
learned that the debug in hardware is not like in the C or Java, it’s mainly about the timing
analysis, you should use the test bench code to generate the exact test signal to test how your
designed module will react to your test signals, and using the waveform function to have a
virtual picture for debug. This help a lot when I designed the Sprite Module, I use the test
bench to debug every small module and see how these modules response to my clock, check
every clock if the output signals is right, it’s very tedious but it’s also powerful to find what is
going wrong in your module. After I have learned this method, it accelerates my progress
dramatically.
Audio Modules
Audio Files Preparation
In the audio design, one background music, and two sound effects namely acceleration and crashing
are included in this project. All the three audio files are configured with sample rate of 44100 Hz and
16 bits quantization to ensure the sound quality. In order to store the sound files in the on-chip ROM,
we have to prepare MIF files with sizes small enough so that the audio files do not consume too much
memory of the on-chip ROM. The first step is to find out appropriate sound files. The acceleration
and crashing sound effects were downloaded in .wav format online. But the original files cannot be
implemented directly in this project due to the fact that the files’ sizes are much larger than expected.
So, we modified the .wav format files using MATLAB. We plotted the sample data of the two
original files, and picked representative pieces from the plots. Next, we reassembled the selected
pieces to create new sample data sets to represent acceleration and crashing sound effects. Then we
tested the new sound effects by simulating the looping playback environment in MATLAB, and
sounded the files. Finally, we chose the version that performed best in this quality and data size
tradeoff. In the next step, we converted the modified sample data into MIF using MATLAB. The
codes for generating “accelerate.mif” and “crash.mif” files are in the MATLAB Code section of this
report.
Audio Controller
The board in the lab provides the Analog Devices SSM2603 Audio Codec
(Encoder/Decoder). This chip supports microphone-in, line-in, and line-out ports, with a
sample rate adjustable from 8kHz to 96kHz. The SSM2603 is controlled via a serial I 2C bus
interface, which is connected to pins on the Cyclone V SoC FPGA. The schematic diagram of
the audio circuitry is shown in the figure below.
In this project, the Audio Controller is mainly consisted of four components, namely Audio
ROM blocks, Audio Effect block, Audio Codec Interface, and Audio Codec Configuration
Interface. The figure below is the function block diagram of the Audio Controller.
1. Audio ROM blocks. The audio data are well prepared in advance to take as little on-
chip ROM space as possible, while preserving the sound quality. The acceleration
sound (“accelerate.mif”), crashing sound (“crash.mif”), and background music
(“background.mif”) files are used to create ROM audio data blocks using
MegaWizard Plug-in Manager. The background music takes 32768 words
(word=16bits) memory, while each of the acceleration and crashing sound effects
takes 16384 words (word=16bits) memory. In total, 65536 16-bit ROM space are
taken for the audio data.
2. Audio Effect block. This block operates at 50 MHz clock rate and receives the
control signals passed from the software. When a valid control signal is passed to this
block, the corresponding audio data will be fetched from the Audio Data blocks, and
then passed to the SSM2603 Audio Codec through Audio Codec Interface.
3. Audio Codec Interface. This interface operates at 50 MHz clock rate. It sends the
audio data to the SSM2603 Audio Codec using shift registers.
4. Audio Codec Configuration Interface. This interface is used to configure the
SSM2603 Audio Codec parameters, such as 44100Hz sampling rate and so on, using
the 𝐼2𝐶 protocol. The two wires in the 𝐼2𝐶 protocol are labeled SDAT and SCLK
for Serial Data and Serial Clock respectively. In 𝐼2𝐶, data is sent a bit at a time over
the SDAT wire, with the separation between bits determined by clock cycles on the
SCLK wire. In this project, the FPGA is the master and the audio codec in slave
mode.
When the game is on, the software pass control signal “0” to the Audio Controller, and the
background music will be played. When acceleration happens in the game, control signal “1”
will be passed to the Audio Controller, and the acceleration sound effect will take place
repeatedly until the acceleration period ends. When there is a crash on either the boundaries
or the other competitors, control signal “2” will be passed to the Audio Controller, and the
crashing sound effect will take place. Each sound effect is played individually in this project,
and we do not support concurrent sounding in this game.
Problems Encountered and Solutions
The most severe problem we encountered during the audio design was to find proper audio
files that can fit into the on-chip ROM, while leaving enough storage for the rest of the
project. Initially, to play high quality audios, we loaded large audio files that took over 30%
of the ROM, such design is too costly to be implemented. Then we decided to search for
small audio files that are between one to two seconds long as alternatives. However, the files
were still larger than expected. Finally, we decided to customize the audio files using the
method described in the “Audio Files Preparation” section of this report. And it turned out
that we were able to load the properly modified audio files into the on-chip ROM and play
the sound effects that meet the design requirements.
Future Improvements
Background music and sound effects can be played concurrently. A circular queue can be
designed to handle the background music only. And a mixer can be designed to combine the
sound effects in circular queue and FIFO, and then send the mixed data to SSM2603 Audio
Codec in order to play the background music and the sound effects at the same time.
Game Logic Module (Software)
Game Play Flowchart
Software Flowchart
When the game starts, a traffic light will change from red to green signaling the start of the
game and all cars will start going forward. The other two opponent cars are set to have higher
speeds than the player’s car and one of them is the fastest. The detection of the USB
keyboard is in a separate thread and the system will be detecting if a key is pressed all the
time. When the left key is pressed, the player’s car will be moving towards left. When the
right key is pressed, the player’s car will be moving towards right. If the player’s car collides
with the road or other cars, its position will be reset to the middle of the road and its speed
will be slowed down. If the player’s car hits a coin, the score will be added up. When the
score is larger than or equal to 5 and the up key is pressed, the player’s car will speed up. If
the distance between the player’s car and the opponent cars is within the passing range and
the player’s car is still speeding up, the player’s car will be passing the opponent cars. If the
player’s car is not speeding up and the distance is within passing range, the player’s car will
be passed by the opponent cars.
Hardware – Software Interface
Each sprite stored in the ROM will have a center position with X and Y coordinates. The
function write_register is used to communicate between hardware and software which takes
an index of a sprite and its center location x and y as inputs. What we need to do in the
software is to use write_register to call sprites and put it to the positions we want.
Game Play Algorithm
Trees, clouds and road moving
Coordinates of three important points
In our game environment logic, the location and movement of environmental
elements are all have a relationship with the coordinates of central point ‘A’ which is
given by the hardware. By identifying vector AB and AC, we could easily put trees
and clouds in right location. The unit vector of AB and AC are as follows:
When encountered curve roads, the position and movement of trees could also be
calculated dynamically according to the movement of central point ‘A’.
Collision with road, coins and cars In our game, when player’s car hit the road margin
or other cars, it will be set back to initial position and stay twinkling in place for a
while as penalty. The judgment for collision is by comparing the distance of the two
central points’ coordinates.
As for coins, when cars hit the coins, it will get a reward for speedup if the
accumulated hit number of coins reaches five.
Surpass To be able to know when the player’s car is passing the opponent cars or
when it is being passed by the opponent cars, we keep track of how far each car has
travelled by three variables “car1_dist”, “car2_dist” and “car3_dist”. These three
variables keep increasing based on their different speeds – “car1_speed”,
“car2_speed” and “car3_speed”. In this way we are able to know two cars’ distance
by subtracting two distance variables. And we set a passing range so that when two
cars’ distance is within the range, there is a passing event. The player’s car can only
be passing the opponent cars during speed up and their distance is within the passing
range, where its speed is faster than the opponent cars’ speeds. And the opponent cars
can pass the player’s car if the player’s car is not speeding up and their distance is
within the passing range. During the process of speeding up, all the cars’ speeds are
set so that the player’s car’s speed is the fastest. If a collision happens, the player’s
car’s speed will be set to zero during the process of reset. The rank will be displayed
based on their distances travelled.
Numbers displayed (score, time, rank, speed) . We wrote three functions –
score_display, time_display and speed_display – to display corresponding numbers on
the screen. The score_display function takes the variable “car_score” as input and
output the correct score on the screen. If the number is less than 10, it will be put
directly on the units’ digit. If the number is larger than and equal to 10 and smaller
than 100, it will be divided by 10. The quotient will be put on the tens’ digit and the
remainder will be put on the units’ digit. If the number is larger than and equal to 100
and smaller than 1000, it will first be divided by 100 and the quotient is put on the
hundreds’ digit. Then the quotient is divided by 10 and its quotient is put on the tens’
digit and its remainder is put on the units’ digit. The other functions use similar
algorithm to display numbers.
Timer, we used a variable “gametimer” to keep track of the time elapsed. We increase
“gametimer” by an increment of 1 with frame rate and then divide it by the number of
how many frames per second to get the correct time.
Future Work Suggestions
1. The game modes could be set in different difficulty levels for player to
choose.
2. We may add joystick control in the game to make our game fancier.
3. The curve road part in codes could be added in a new thread in order to make
the curve appears more natural and smoothly.
4. We may possibly add more cars.
5. The score can be replaced by a nitrogen bar and the coins can be replaced by
nitrogen cans.
6. We may possibly add drift effect for player’s car.
7. The game should be able to pause.
Problems Encountered and Solutions
1. At the beginning when discussed the game logic, we thought the movement of
environmental elements was difficult to control. Because when curve road
appears, the trees must move in different directions dynamically with the road
direction. Then we came up with a solution which is to set two vectors that
could be controlled by only one point’s coordinates. This method simplified
our game logic and appears to be really helpful and elegant.
2. We had a hard time trying to get the keyboard to work. We kept getting the
same error from the system of not being able to find the libusb file. We found
out that in our lab3 file, which was the file we were using, the libusb directory
was actually missing. Then we copied the directory from lab2 file to lab3. In
this way we were able to get rid of the previous error but we got a new error.
Then we found out that the error occurred because lab2 and lab3 used
different versions. After we move everything from lab3 to lab2, the problem
got fixed and we were finally able to use the keyboard.
3. We were not able to make the keyboard function work in the main function.
We found out that using keyboard functions in the main function would
always interfere with our main game logic. Thus we used a thread and put the
whole keyboard function in the thread. And we opened the thread at the
beginning of our main function and end the thread at the end of our main
function.
4. We were not able to make the car move continuously by holding the key. In
the libusb_interrupt_transfer function, the last variable was set to 0. We tried
to increase this number and we found out that we were able to detect a
continuous hold of a key. This variable was called timeout (in milliseconds)
that is the time the function should wait before giving up due to no response
received. You put 0 for an unlimited timeout.
5. We were not able to define an accurate passing range. We were using three
variables named “car1_dist”, car2_dist” and car3_dist” to keep track of how
far each car has travelled and the distances between each other. However,
these variables were increasing very fast because they were increasing along
with the frame rate. The distances between them were increasing very fast as
well. Thus, it was very hard to define a range where a passing event should
happen. We then divide each distance variable with an integer and were able
to make them increase slowly and get a reasonable passing range.
Conclusion
From this project, we improved our skills in programming both hardware
language and software language.
In the Sprite Display Module design, we have gone through programing,
testing, modifying and assembling. We adopt Top-Down Design
Methodology, divide the big project into several small task and modules,
design general port interface. By this way, we improve our progress and make
our project easy to locate where the problems are because we use small
modules to limit the bug region. We believe the most valuable lesson we have
learned in this project is how to debug in hardware and how to locate the bug.
The bugs and problems we encountered through this project help us to
enhance our knowledge of hardware design.
During the audio design in this project, we have learnt that the physical on-
chip ROM limit should always be kept in mind during hardware design, and
all the data designed to be loaded on board should be modified to the correct
format beforehand. When preparing the proper audio file, rather than
repeatedly loading different testing audio files into the system and compiling
the whole program every time we change the audio files, we can simulate the
looping playback environment using MATLAB, and then load the qualified
audio file version on board for further testing. The simulation strategy is much
more efficient. Before integrating the audio module into the whole game logic
program, we should test the audio module by sending the expected signals to
examine whether the audio system can output correctly. Following such
procedure, we can save a lot of debugging, because we have divided the
whole design and testing procedure into multiple subsections which make it
easier and faster to locate the error locations.
We used the software to implement the game logic and hardware to display
graphics and audio sounds and communicated each other with software-
hardware interface. During this procedure, we’ve encountered a lot of
problems in implementing the game logic and keyboard control but we were
finally able to solve all of them though we still have a lot to improve.
Final Result