Skip to content

kristianklein/fpgappy-bird

Repository files navigation

FPGAppy Bird

https://github.com/kristianklein/fpgappy-bird

This project was created for a course in digital electronics on the fifth semester of Electronics and Computer Engineering at the University of Southern Denmark.

The project is an FPGA (VHDL) implementation of the game "Flappy Bird" using a Digilent Nexys 2 Spartan-3E FPGA trainer board and a Digilent PmodAD1 analog-to-digital converter. The code was developed using Xilinx ISE 14.7 on Ubuntu 18.04.

Project description

In the classic Flappy Bird game, the player controls a bird and must avoid obstacles by pressing a button to make the bird fly higher. In this project, the bird is instead controlled via an analog input (potentiometer, IR sensor or something else) that determines the bird's absolute vertical position on the screen. The video signal is sent out on the VGA port and the player's current score is shown on the multiplexed 7-segment display.

Components

A block diagram of the system is shown in the image below. VHDL modules are displayed as rectangles and external hardware as circles.

Block diagram

In the following sections, the purpose of each component is briefly described.

ADC interface and sampler

The PmodAD1 is a 2-channel 12-bit ADC with a maximum sampling rate of 1 MSa/s. When sampling a 12-bit value, it is necessary to sample 16-bits, the first four being zeroes. The first bit is generated by setting the chip select (CS) pin low and the remaining 15 bits are generated on the falling edge of the serial clock. All this timing is taken care of by the adc_interface module. When the start-input is set high, a 12-bit value is fetched from each of the channels. When the sampling is done the done-output goes high and the 12-bit values are available on the AD1 and AD2 busses of the interface.

The sampler module controls the actual sampling rate, by setting the start signal at an interval determined by prescaler input bus. The 50 MHz system clock is automatically scaled down by 50 to give a maximum sampling rate of 1 MHz (prescaler set to 0 or 1). Note that this is not currently supported by the adc_interface, which can handle a maximum of around 500 kHz. In the top module of the project, the prescaler input is set to 16666, resulting in a sampling frequency of approximately 60 Hz.

7-segment driver and binary-to-BCD converter

The display driver takes a 16-bit binary coded decimal (BCD) value, a 4-bit vector for the four decimal points, and the system clock as input. The 16-bit BCD value is generated by the binary2bcd module, which converts a 12-bit binary value to a 16-bit BCD value using the double-dabble algorithm.

In the display driver module, the 16-bit BCD value is sent to a 16-to-4 multiplexer and the 4-bit decimal point vector is sent to a 4-to-1 multiplexer. A 2-bit counter then controls which of the four BCDs and decimal points is shown on the 7-segment display, and at which position. The counter runs at a 1 kHz clock, so the digits seem to appear simultaneously on the display.

When playing the game, the player's current score is shown on the 7-segment display.

VGA driver, game renderer and graphics ROM

The VGA driver handles all timing of signals which is necessary to show graphics on a VGA display. The VGA standard calls for a display refresh rate of 60 Hz and with a display area of 640x480 pixel, it is necessary to scan 800 counts horisontally and 525 counts vertically, when including the front porch, back porch and synchronisation pulse. The clock necessary to achieve this is 800x525x60 = 25.2 MHz. Rounding this off to 25 MHz gives us a refresh rate of 59.5 Hz, which is close enough. The VGA driver is responsible for generating this VGA clock and setting the VSYNC and HSYNC signals with the correct timing. It also keeps track of the current vertical and horisontal position on the screen and determines whether it is allowed to set the RGB pins or not (RGB enable bit). The RGB pins should only be set within the display area and should all be zero during the front porch, back porch and synchronisation pulse.

The game_render module takes the vertical and horisontal position and the RGB enable bit as input and draws the actual game screen on the display. To draw the player and obstacle sprites on the screen, it also takes the obstacle's current x- and y-position, and the player's y-position as input. The player's x-position is constant. The player sprite ("Flappy bird") is drawn from the bird_rom module, which contains a 17x12 pixel bitmap.

Game state machine and game timer

The game_FSM module is a finite state machine that determines the current state of the game. These states are idle, running, paused and game_over. When the system starts the game is in the idle state. When the user presses the BTN0 push button on the board, the state changes to running and the obstacle starts rolling across the screen. If the button is pressed while the game is running, the game can be paused/unpaused. When the player collides with the obstacle, the game is over and can be reset by pressing the button.

The game speed is controlled by the game_timer module. This clock controls how fast the obstacle is moving and runs at a maximum of 6.4 kHz. The obstacle moves one pixel on the screen for every clock cycle, so at the maximum frequency the obstacle will pass the entire screen in one tenth of a second. This maximum frequency is scaled down by an initial value of 30, which means it will take around 3 seconds for the obstacle to pass the entire screen when the game is first started. For every two obstacles passed, this scaling value will decrement by one, resulting in a faster game speed.

Obstacle, player and collision detection

The obstacle's x-position is controlled by the game clock as described above. The y-position only changes when the obstacle leaves the screen after the player has passed it. A new random y-position is generated using a 16-bit linear-feedback shift register using only the 10 least significant bits.

The player's vertical position on the screen is determined by the ADC value. Since this value consists of 12 bits and there are only 480 vertical pixels on the screen, the three least significant bits are discarded, giving a 9-bit value from 0-511. The remaining excess values are removed by mapping the first 22 values to 0 and the last 22 values to 468 (also accounting for the 12 pixel height of the player sprite).

The y-position of the player and the x- and y-position of the obstacle is given to a collision detection module, which gives a signal to the game state machine if the player collides with the obstacle.

About

FPGA implementation of Flappy Bird

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages