As part of my Digital Design module for my Electronic Engineering degree I was tasked with writing an verilog project using an Altera DE1 FPGA. At the time I was quite addicted to Super Hexagon. The game mechanics were simple enough that It would be feasible to do an FPGA implementation. All source code can be found on my github: https://github.com/samp20/SuperHexagonFPGA
The core of the whole project is the VGA driver. This is what will ultimately display the graphics onto the screen. To get the data to the screen I chose a pipelined approach for calculating the pixels. On each pixel clock the VGA driver module would output an x/y coordinate. Each coordinate is then clocked through the pipeline and processed until an RGB colour appears at the other end. This colour is then fed back into the VGA driver module. The huge block diagram in the gallery shows the details. Below is a highly simplified version:
An Issue I came across during development was finding a way to allow the player to be killed when colliding with the front of a wall, but still allow the player to bump into the sides. This was achieved by storing the player's old and new coordinates. If the new coordinate collides, but the old one does not then the player's position is reverted back to the old coordinates. This collision logic was embedded into the main game state machine:
Another interesting part of the project (It was all interesting!) was the wall generation. The currently active walls are held in a 6bitx128 array in RAM. Two pointers index this array, one for making the walls move inwards towards the player, and another for updating the walls with new ones when they go off screen. New walls are sourced (pseudo)randomly from a set of 16 predetermined patterns. An example of such pattern is shown below:
walls_maze = 6'b011111; walls_maze = 6'b000000; walls_maze = 6'b101111; walls_maze = 6'b000000; walls_maze = 6'b110111; walls_maze = 6'b000000; walls_maze = 6'b111011; walls_maze = 6'b000000; walls_maze = 6'b111101; walls_maze = 6'b000000; walls_maze = 6'b111110; walls_maze = 6'b000000; walls_maze = 6'b011111; walls_maze = 6'b000000; walls_maze = 6'b101111; walls_maze = 6'b000000;Once all the walls and player are in place the only thing left to add is crazy spinning and flashing colours to distract the player. The spinning was achieved by applying a rotation to the initial x/y coordinates by multiplying by sin and cos functions. Colour changing is done by a simple lookup into an array of predefined colours based on whether a wall, the player, or the background is present at any particular pixel. There are a total of 4 colour schemes which change every time the spinning gets a little crazier.
All of this results in the following game (sorry about the screen glare):
Unfortunately there wasn't enough time to add sound to the project. Figuring our how to drive the audio codec IC would have been another entire project itself.