Galaxian Arcade Study
Galaxian Arcade Study
Team #27
Danh (Danny) Vo and Weijie (Jeff) Yuan
Mentoring TA:
Javier Castro
Abstract:
Galaxian Revolution represents a coalescence of the classic arcade game Galaxian and a
novel hand motion based controller scheme. The project involves the design and
implementation of three different module blocks: video processor to detect hand motion
and translate into game commands, the game logic itself which governs the flow of
gameplay, and finally the display output to the monitor. The successful integration of
these independently designed blocks is also a crucial component of the project. Through
five weeks of planning, designing, implantation, and integration, the project is fully
functional and can be enjoyed by adults and children of all ages.
Table of Contents
1 Introduction -------------------------------------------------------------------------- 4
2 System Overview ------------------------------------------------------------------- 4
6 Conclusion --------------------------------------------------------------------------- 18
7 Acknowledgements ----------------------------------------------------------------- 18
2
Table of Figures
Figure 1: Galaxian Game Logo ------------------------------------------------------------ 4
Figure 2: Screenshot of Galaxian ---------------------------------------------------------- 4
Figure 3: Overall Block Diagram----------------------------------------------------------- 5
Figure 4: Video Processor Block Diagram ----------------------------------------------- 6
Figure 5: Demonstration of Median Filter ------------------------------------------------ 7
Figure 6: Routing With and Without Area Constraint ---------------------------------- 8
Figure 7: Game Logic Block Diagram ---------------------------------------------------- 9
Figure 8: Alien FSM State Transition Diagram ----------------------------------------- 12
Figure 9: Game FSM State Transition Diagram ----------------------------------------- 14
Figure 10: Game Title Screen -------------------------------------------------------------- 15
Figure 11: Game End Screen --------------------------------------------------------------- 15
Figure 12: In Game Screen ----------------------------------------------------------------- 15
Figure 13: Display Output Pipeline Diagram -------------------------------------------- 17
3
1. Overview
Galaxian is a classic arcade game released by Namco in
1979. The game features a horde of aliens creatures
which attempts to destroy a spaceship controlled by the
player. The player can shoot bullets at the aliens in an Figure 1: Original logo of the
attempt to exterminate them. A novel feature of the game Galaxian game1
is that periodically, aliens swoop down from their
formation and make kamikaze attacks at the player’s ship. Galaxian was a huge success
for Namco and spawned a large number of sequels, including Galaga (1981), Gaplus
(1984), and Galaga ’88 (1987).
The following sections in this document detail the design of the system, the process of
implementation and debugging, and the end result of this project. Possible improvements
to the design process and the system are also discussed at the end of the document.
2. System Overview
The system is divided up into three main blocks (see figure 3). The video processor
block contains code which interfaces with the video camera to get the relevant pixels. It
also uses various algorithms to detect the desired object, and track its velocity and
position. The video processor is designed and implemented by Danny Vo. The game
logic contains all the images, rules, and interactions which make the game operate. Jeff
Yuan is responsible for the design and implementation of the game logic. Finally, the
1
Image © Namco, 1979
2
Image courtesy of Wikipedia (http://en.wikipedia.org/wiki/Galaxian)
4
video output module takes the image information from the game logic and efficiently
outputs to the display. This block is implemented by Danny Vo.
Between the video processor and the game logic is a selector which allows the game to be
controlled by either the video processor input or labkit buttons. This allows for multiple
ways of controlling the game. It also was helpful in testing and debugging the
connections between the different modules.
3. Video Processor
The main purpose of the video processor is to provide the control input for the game logic
block. The video processor interprets the user input in the following setting:
The user holds an orange ball in his or her hand with the ball in the view of the
video camera. As the hand is moved from left to right or vice versa, the video
processor calculates the velocity and the direction of the ball. From this
information, the video processor provides appropriate control inputs for the game
logic block.
In order to process the ball’s movement, the video processor must be provided with
streams of pixels from the video camera. The code for most of the camera interfacing
modules is based on those written by the 6.111 staff. In particular, the adv7185init3
module is used as the driver for the video decoder. The ntsc_decode4 module takes in a
stream of LLC data from the adv7185init and generates the corresponding pixels in
YCrCb format. These pixels are then written into the ZBT ram by the ntsc_to_zbt
module and read out by the vram_display module. The video processor then takes in
these pixel values from the vram_display and processes them.
Some minor modifications have been made to the modules mentioned above. In
particular, the ntsc_to_zbt module is changed to extract an 18-bit value from the 30-bit
YCrCb value provided by the ntsc_decode. Then the ntsc_to_zbt writes two 18-bit
YCrCb values which correspond to two adjacent pixels into each row of the ZBT ram. In
3
The adv7185init module is written by Nathan Ickes
4
The ntsc_decode module is written by Javier Castro
5
addition, the vram_display module was changed to take into account of the fact that two
adjacent pixels are stored in the ZBT ram.
Originally, the object_detector module was implemented to detect green LEDs in the
RGB color space. The detection algorithm looked for pixels which have the green value
greater than a threshold value of 251. However, this particular scheme performed poorly
due to two main reasons: high sensitivity to noise and low robustness to changes in the
environment. In order for the detection to work, the camera must face downward to
avoid the ceiling lights or any surface reflection because they also have green value
greater than the threshold value. Furthermore, the camera must be blurred to reduce the
amount of noise produced not only by the surround environment but also by the LEDs
themselves. The sensitivity to noise is mostly resolved by implementing a median filter
(discussed below). The low robustness to changes in the environment has its roots in the
RGB color space, which does not separate brightness and color. In other words, as one
increases or decreases the green value, the brightness is simultaneously increased or
6
decreased. Thus to the detection algorithm, a green LED is no different than a ceiling
light. This problem is overcome by doing detection in the YCrCb color space.
0 1 2 3 4 Row 15
Row 17
ball noise
Figure 5: A median filter is used to reduce noise in object detection. Pixels in row 15 pass through the
median filter since there are more than four consecutive pixels which pass the threshold test. On the other
hand, the two pixels in row 17 are rejected by the median filter.
The low robustness issue is solved by switching to YCrCb color space and a better
threshold test. YCrCb color space separates brightness and color. Specifically, Y value
contains all information about the brightness of a particular pixel. The new threshold test
is composed of testing all three color value: Y, Cr, and Cb: the object_detector has three
ranges of value for Y, Cr, and Cb. A pixel is recognized as belonging to the ball only
when its Y, Cr, and Cb values fall within the corresponding threshold range.
7
which denotes which action the user is currently performing: left, right or shoot. The
shoot action is triggered when an upward velocity above a certain threshold is detected.
Figure 6: Comparison of project component placement on the board, with and without an area constraint.
After combing through various Xilinx manuals, a method was discovered that would
allow the mapping of components on the board to be constrained within a certain area.
This allowed for a more concentrated placement of components to be near the ZBT, thus
eliminating the problem of having long path with high propagation delays. After
applying this area constraint, the system consistently obtained good results on every
compilation. To illustrate this point, figure 6 shows the difference between a layout
obtained without using a constraint and one which used a constraint. As one can see,
8
without using an area constraint, Xilinx ISE just randomly “optimizes” the placement of
components all over the FPGA chip. After applying the error constraint, the placement is
limited to the bottom left hand corner of the chip close to the location of the ZBT.
4. Game Logic
The game logic block is responsible for creating the actual game play. It instantiates all
the sprites seen on screen, and interprets user control into actions that are reflected on the
screen. The game logic block (shown in figure 7) is composed of about ten modules
which perform a variety of tasks. The main module (game_logic.v) exists as a foundation
from which all other modules are instantiated and connected together. Then there are the
game objects modules (ship.v, bullet.v, alien.v, and alien_formation.v) which represent
the objects that appear directly the game. In addition, these modules perform calculation
for the location of the objects in each frame. All game object modules are connected to
the collision detector (collision.v), which reports any collisions to the game logic. A
game FSM module (game_fsm.v) coordinates the sequence of actions in the game,
including when certain automatic actions of aliens are triggered. Finally, there are
modules (startscreen.v, endscreen.v and background.v) which are responsible for loading
stored image from ROMs onto the screen.
9
4.1 Main Game Logic
The main game logic module (game_logic.v) is responsible for instantiating all other
modules of the game logic and facilitating the signal connections between them.
Specifically, the ship, bullet, and alien (16 instances of it) modules are instantiated. They
are connected together with the collision detector, which is also instantiated in this
module. The game logic module also gathers together the sprite output (3-big RGB
signal) from each game object, and combines them together into a single video output
signal (a more in depth discussion of this is present in section 5).
Contained within the main module is a minor FSM which directs individual modules to
perform their respective calculations on specific clock cycles. The FSM makes one pass
through the following states (in order) during the vertical blanking period in each frame:
• S_NONE: latches in the value from the user input control (either labkit button or
video processor).
• S_UPDATE_SHIP: sends a signal which triggers the ship module to begin
calculation of its position in the next frame. Also disables the ship if it is found to
be colliding with another object.
• S_UPDATE_BULLET: sends a signal which triggers the bullet module to begin
calculating its position in the next frame.
• S_UPDATE_ALIEN: sends a signal to all the alien modules, which triggers their
calculation of position in the next frame. Also disables any aliens which are
found to be colliding with another object.
• S_DELAY: self loops in this state for 3 cycles, to give alien modules sufficient
time to finish its calculations.
• S_END: reset back to the first state, and terminates all calculation for the current
frame.
An alternative scheme that was considered involved taking the RGB values of all pairs of
objects and passing them through an AND gate. If both of these objects are trying to
write to the same pixel, the result of the AND operation would be a “1.” The reason this
scheme was not used was due to the need to optimize. In the method above, only the
highest bit of each addition is inspected. But in this implementation, each bit of the result
10
must be implicitly checked. The different in performance is probably not too great, but
the simpler and more optimized solution was chosen to minimize the chance that a timing
issue would occur.
4.3 Timer
Because many of the modules in the game logic trigger actions after a certain delay, it is
desirable to have a timer module which can count up to some number. The timer, when
enabled, counts up from 0 to the value set as the parameter TIMEMAX. Upon reaching
this value, the timer asserts the expired signal and resets its counter. Because the system
clock runs at 65Mhz, it would be unreasonable to trigger the count on the rising edge of
the system clock. Instead, the count is incremented on every new frame. This allows a
much smaller register to be made in order to keep the count. This utility module is used
by the alien module, game_fsm module, and others. While each of these modules can
create its own custom timer, it is much more efficient to refactor this code into a single
module.
The ship module also calculates the position of a ship in any given frame. It does so by
taking in the input from the controller signal, and moving left or right accordingly. The
speed of movement (in pixels per frame) is specified by the speed signal. This value is a
constant if the controller being used is the labkit buttons. However, if the controller used
is the video processor, the speed can actually vary according to the speed with which the
player moves his hand.
11
vcount for displaying its sprite. However, alien has a three frame animation, so the
module must cycle between 3 ROM images, and read data from each in turn. A timer is
created which counts from 0 to 2, and the three time values are mapped to the three
different frames of animation. At each time transition of timer, the output of a different
ROM is set to the RGB output of the module.
The alien module must also calculate the position of the alien object in each subsequent
frame. A simple FSM is used to keep track of which behavior pattern the alien is
currently engaged in. As can be seen from the state transition diagram (figure 8), the
alien FSM operates in a cyclical fashion, with one sink state (S_DEATH):
• S_FORMATION: This is the starting state, where the alien moves back and forth
(to the left and then to the right) near the top of the screen. All the aliens move in
a formation of sorts with all other aliens. The exact coordinate of the alien is
calculated by a helper module (alien_formation.v). This module takes in as
parameter the speed of the alien while in formation and the range of movement
(how many pixels to the left and right). It calculates the position of the alien from
these pieces of information. It is important to note that the calculation made by
the alien_formation module is persistent, meaning that calculation is made even
when the alien is not in the S_FORMATION state. A transition is made to the
S_PRECHARGE state when the signal start_charge goes high.
• S_PRECHARGE: This is an intermediary state between S_FORMATION and
S_CHARGE. The alien moves downward for some number of pixels
12
(parameterized in the module) before transitioning to the S_CHARGE state. The
reason for this state is to prevent two aliens from running into each other.
• S_CHARGE: In this state, the alien moves downward toward the player’s ship. It
tracks the player’s ship’s position, and attempts to collide into it. The vertical
speed of the alien is fixed, and the horizontal speed is limited to a maximum value.
This gives the player a reasonable chance to avoid the alien. Upon reaching the y-
coordinate of the ship, a transition is made to the S_RETURN state (assuming the
alien does not collide with the ship).
• S_RETURN: This state indicates that the alien has gotten past the position of the
ship in the y-direction, and is exiting the bottom of the screen to reappear in
formation at the top. The desired coordinate for the alien in formation is
calculated by the alien_formation module. When the alien gets close enough to
its formation position, it transitions back to the S_FORMATION state.
• S_DEATH: This state is reached when the enable signal of the alien goes low.
This indicates that the alien is killed. This state can be arrived at through any of
the other states. However, the only way to transition out of this state is through a
system reset.
13
this delay effect. The intention here is to give the player some amount of time to
be ready before the ship again appears on the screen. A transition is made back to
the S_ALIENFORMATION state after a few seconds of delay.
• S_GAMEOVER: In this state, the end game screen is displayed.
14
frames) and added to vcount. This makes the background image appear to shift, and
create the intended scrolling effect.
Figure 10: Title screen, as Figure 11: End screen, as displayed Figure 12: In game screenshot,
displayed on the LCD on the LCD as displayed on LCD display
One serious problem discovered during testing was that images displayed onto the screen
appeared to have some pixels shifted. After some investigation, the cause of the glitch
was discovered to be a delay in the readout of pixel information from the ROM. The
calculation necessary to compute the address for reading from a ROM took one whole
cycle. In addition, it took another cycle to read from the BRAM. In total, there was a
two cycle delay from when an output for a particular pixel is needed, to when the data
5
This module is taken from Binary to BCD conversions project on http://www.opencores.org.
15
can be read out. This caused certain pixels to be shifted from the end of one pixel line to
the beginning of the next. While it was possible to implement a prefetching mechanism
to calculate the address of pixels two cycles ahead, it was overly complex and proved to
be unnecessary. The “quick and dirty” solution was to simply modify the image stored in
the ROM so that at the left and right end matches the color of the background. This way,
when a reading offset occurred, it was not noticeable.
Another problem encountered in the design process was in the collision detection module.
At first, it appears that collisions that happened on the screen were never detected.
However, after some investigation using a logic analyzer, it was apparent that the
collision detector did not “detect” on the right clock cycles. The collision detector was
only active during the vertical blanking period while collisions happened at values of
hcount and vcount before the blanking period. After this discovery, the solution to the
problem proved to be relatively easy.
5. Video Output
The video output block is responsible for outputting a single 3-bit RGB signal which is
sent to the LCD display. All the code for this block actually resides in the game_logic
module. This is due to the fact that the video output block must takes in RGB signals
from many different modules in the game_logic. Thus, its operation is directly coupled
with the output of many game logic modules. The discussion of its operation is separated
into a separate section for clarity.
One of the major problems with this is the strict timing constraint. The system is driven
at 65 MHz which restricts all the computations to be completed within 15ns.
Additionally, there are 21 different modules output different 3-bit RGB signals. Thus, if
these signals are naively connected to a giant “OR” gate and the video output is taken
from the resulting signal, glitches would definitely occur on the LCD display.
To eliminate these glitches and to create a smooth image, a more sophisticated technique
must be used. The original plan was to use double frame buffer architecture: create two
BRAM, one is used for writing and one is used for displaying to the LCD. Double frame
buffer architecture allows the system to writes pixels which are displayed in the next
frame to one of the BRAM while the displaying is reading from the other one. This
avoids the issue of changing the data while displaying. The original plan as stated above
was to create two BRAM with 3-bit width and 393216 (512*768) bit depth BRAM.
However, Xilinx logic core generator did not allow this, even though in theory there are
enough BRAM: the XCV2V6000 contains 144 BRAM and 2952K bits total while the
above architecture requires 2359K bits total. Another option was to use the ZBT ram as a
frame buffer. However, due to the difficulty in timing with the ZBT, and the fact that one
ZBT is already being used for video processing, this idea was also rejected.
In the end, a pipelining solution was chosen. Pipelining increases latency in exchange for
high throughput. In other words, it allows the computation, which originally has a
propagation delay greater than one clock period, to be divided into smaller computation
16
over several clock cycles. Since glitches in the display are caused by incomplete
computation within one clock cycle, pipelining would effectively eliminate these glitches.
In the video output block, a 7-stage pipeline is implemented for each of red, green and
blue channel. Figure 13 illustrates the green channel pipeline. The red and blue channel
pipeline architecture is analogous to the green one. Furthermore, vsync, hsync, and blank
signal are also pipelined so that when a pixel comes out of the pipeline stage, they still
match with their original vsync, hsync and blank signal. In addition, the pipeline stages
also implement priority in pixel overlay. There are two different layers: the background
and the game components layer. The game components layer takes precedence over the
backgrounds. This function is implemented by the multiplexers as can be seen in figure 9
below.
alien_rgb[1]
alien_rgb[4]
alien_rgb[7]
alien_4_g
alien_rgb[13]
alien_6_g
alien_rgb[19]
alien_8_g
alien_rgb[31] background
behind game
alien_12_g
logic
alien_rgb[37]
alien_r
alien_rgb[43]
alien_rgb[47]
display_gamescreen
ship_rgb[1]
bullet_rgb[1]
gameinfo_display_rgb[1]
gpixel[1]
logo[1]
background[1]
startscreen[1]
endscreen[1]
display start
screen or display_startscreen
end screen
vsync gvsync
hsync ghsync
blank gblank
Figure 13: Diagram for the 7-stage pipeline used in video output block
17
Originally, the system vsync, hsync and blank took one the value of the ZBT hsync,
vsync and blank: the ZBT hsync, vsync and blank were delayed by three clock cycles to
synchronize with the ZBT. However, due to the requirement for selecting between the
ZBT and the game logic hsync, vsync, and blank, the ZBT hsync, vsync and blank were
delayed by two clock cycles instead. At the third clock cycle, depending whether the
system were displaying the game logic or the ZBT, the system hsync, vsync and blank
would take on the corresponding hsync, vsync and blank value.
6. Conclusion
Our final project attempted to integrate the classic video game Galaxian with motion
detection based controller scheme to create a new gaming experience. This system
involved the design and implementation of two main components and the integration of
these parts to form a functional system.
Given an opportunity to repeat this project experience, significantly more time would be
devoted to planning out the modules before starting implementation. This would have
reduced the amount of time used to scrap existing implementation and create something
new from scratch. Time management could also have been improved to space out the
work more evenly through the five week period. Although the objectives for this project
were successfully implemented, the final week felt quite rushed.
While noting the possible process improvements above, the project as a whole was a
tremendous success. This project allowed us to experience the whole design cycle of
idea generation, preliminary planning, coding, debugging, and integration. The valuable
lessons we learned here will undoubtedly prove invaluable to us in our future careers.
7. Acknowledgements
We would like to acknowledge the following people for their ideas and contributions to
this project:
• Professor Terman – Numerous inspirations on game logic implementation, help in
debugging video processing code
• Javier Castro – Ideas on implementing pipelining, help in debugging
• Cassie Huang – Inspiration on project idea
• Gim Hom – Answering numerous technical questions, providing ample supply of
coffee
• Kevin Miu – Constructive criticism of game art, ideas on collision detection
18