The project consists of a 2D version of Minecraft: The player can traverse the world, placing and breaking blocks to build structures. There will also be enemies the player can interact and fight with. This project is built for the Nios II processor using the C programming language.
The game begins by generating a world based on a seed, this includes the dirt and grass, and trees found in each world. A world is made up of 16 chunks, each of which are 64 blocks wide and 128 blocks tall. Each block is 8x8 while entities have pixel perfect accuracy, colliding with blocks.
When the program begins, a start screen outlines all the user controls and prompts the player to press E to begin playing the game. The player is then loaded into a 2d version of the game minecraft which is made using math functions to generate a unique world. The sky in the background cycles smoothly between 25 colours to simulate a day/night cycle based on program run time.
The player can move left and right using A and D keys respectively, and the player speed can be controlled by sprinting, ‘ctrl’ key, by crouching, ‘shift’ key, or by walking, no additional keys necessary. The player can also jump using the ‘space’ key when on the ground. This world also has a fully fledged collision system and physics so jumping and movement is affected by the physical environment and gravity.
The player can use the mouse and hover over blocks to highlight them. If a highlighted block is within 2 blocks of the player, the player can break it by left clicking. The player can place blocks using right click if a hovered block area is empty. If a valid location is not hovered by the mouse, a block is chosen to be placed or broken based on player direction.
Breaking or placing a block will also play a unique sound effect. The user can choose one of 8 blocks on their hotbar using the number keys which then can be placed. Once a block is broken, a miniature version of the block is dropped (4x4) which has entity physics. This means that the player can push this smaller block around and that it adheres to the world's gravitational rules.
The player also has a health bar which is shown in the UI above the toolbar, representing the player’s health. A red heart represents a point of health while a black heart shows how many points are lost. Once the player loses all 10 hearts, they die, causing them to respawn at the world's starting point with full health. Health can potentially be lost through fall damage if the player falls from a high point.
To run this game, you are required to have the following:
- A computer which can run
Intel FPGA Monitor Program 18.1orIntel FPGA Monitor Program 18.0. - A DE1-SoC board which can be interfaced with by the above mentioned computer.
- The program code file named ‘project.c’ which can be found on the Github page.
- PS/2 keyboard and mouse
- PS/2 Y splitter
- Speakers
Note: Running this project on the Nios II processor is low, however the De1-SoC board does include an ARM chip which can be used instead to have a faster frame rate. Installation guide is the same as the Nios II processor except for switching the architecture in step 3 from
Nios IItoARM Cortex-A9and explicitly adding the compiler flag in step 6 to include-std=c99.
- Begin by opening the monitor program (version 18.0 or 18.1 works).
- Create a new project by going to
File > New Project…. - Within the pop up window, specify a project directory1, project name and select
Nios IIfor the architecture then clickNext >. - Select the
DE1-SoC Computeras the system then clickNext >. - Select the
C Programas the program type then clickNext >. - Click the
Add…and select theproject.cfile on your computer folder system and add-lmto the additional linker flags2 then clickNext >. - Connect the DE1-SoC to the computer via the USB-Blaster II using the Type A to B USB Cable, then click
Refreshand ensureDE-SoC [USB-1]is selected for the host connection then clickNext >. - Select the
Basicas the linker section presets then clickSave. - When prompted, select
Yesto download the Nios II system to the DE1-SoC board. - Once the system is loaded, click the
Compile & load the current program configuration and start the debugging session.
- Plug in keyboard and mouse using a Y splitter. A speaker could also be plugged in for audio.
SW 9corresponds to the first PS/2 component address whileSW 8corresponds to the second PS/2 component address. Toggling a switch on will set the address to be used by a keyboard whilst switching it off will set it to be used by a mouse. Based on which PS/2 port of the splitter each component is plugged into, flip the switches accordingly. If the PS/2 keyboard is plugged into the purple side and the mouse is plugged into the green side of the splitter port, setSW 9high and setSW 8low.- Press the
Ekey to start the game and enjoy!
E - start game
A - move left
D - move right
Space - jump
1-8 - switch selected blocks
Ctrl - sprint (faster left and right movement)
Shift - sneak (slower left and right movement)
Mouse position - crosshair movement
Left click - break block (up to 2 blocks in front of the player)
Right click - place block (up to 2 blocks in front of the player)
This project utilises many of the I/O available on the DE1-SoC board and has unique infrastructure built to support the gameplay and rendering. I/O refers to the input and output of the program, specifically, this program uses the Nios II memory mapped devices to interact with the VGA DAC (digital to analog converter), PS/2 ports, switches, LEDs and Audio CODEC.
Using two 240x512 (240x320 of visible screen) to write into one array while reading from the other array to prevent any writing and reading from the same memory.
Using the PS/2 keyboard protocol, we take in all the byte code data from the PS/2 register to register all the make and break codes.
Using the PS/2 mouse, we take all the byte code data which is in packets of 3 (for the default mouse) to move the crosshair on the screen.
Using the two PS/2 registers, the user will specify what type of input is in (and therefore can be hot swapped during runtime).
Because we desire to have both mouse and keyboard inputs at the same time, we use the switches to swap between mouse and keyboard input polling to ensure whichever input is connected, the user can specify and the dual PS/2 registers will act accordingly.
To ensure user feedback, we use the LEDs to show whether the first or second register is in keyboard or mouse mode.
When a block is broken or placed, a loaded sound file is placed into the audio CODEC FIFO to be played back to the user.
A lot of the infrastructure was built using structs to ensure proper organisation of different features like entities or chunks. It also allows for global arrays to be set without worry of clutter in the code base.
Each block is an 8x8 pixel box that uses texture arrays to display each block on screen. Transparency is achieved by assigning the 0x0 as transparent so anytime the processor receives a 0x0 colour, it will not draw that pixel so any colour behind will be visible. This can most easily be seen with the leaf blocks.
Each chunk is made up of 64 wide and 128 tall arrays of blocks, which each block can be broken or placed. We also ensure that we are only using information that is on screen and therefore needed. Every world is created with 16 chunks to give a large world size.
To create interesting worlds, the world generation uses custom formulas to create the ground and populate the world with trees. The ground is created with two height maps (one for ‘mountains’, sharper peaks and one for ‘hills’, simulating rolling hills) that are smoothly interpolated between (with another function). To populate with trees, another function is used that provides an average tree density over the entire world and will clump trees in regions.
y_h: hill height map, y_m: mountain height map, w_h: hill weighting, w_m: mountain weighting
double y_h = 3 * (pow(sin(x/10),2)*sin(x/15+2)/1.5 + cos(x/35)*sin(x/20));
double y_m = 4 * (pow(sin(2*x/25),3)*cos(x/15) + pow(sin(6*x/35), 2)*sin(7*x/15)/2);
double w_h = pow(sin(x/30), 4);
double w_m = 1 - w_h;int x = 64.0/tree_density*i + 12*sin((double)i/4)*pow(cos(2*(double)i/7), 2);Generic entity controller is used to do collision detection, acceleration and entity specific movement such as velocity and position. Using a generic entity controller, we use it for our player and item entities. We have separate hostile, passive and item entity arrays for displaying and updating all entities. We also have a cap on the hostile, passive and item entity arrays individually avoid low performance and we have an index for each array as a ‘guess’ for the next available space for adding an entity, if that spot is filled, we loop through until we find an open spot or loop through the entire array (we then don’t create the entity).
We have 25 different colour states for different times of the day and night cycle, to ensure a smooth display, we interpolate (we take the percentage between the two colours and combine each R, G, B value separately before recombining) between the current colour and the next colour to make dynamic sky colour.
| Aryan Hussian | Alwyn Tong | |
|---|---|---|
| I/O | --- | --- |
| VGA Output/Rendering | WD MR |
|
| PS/2 Keyboard | WD MR |
|
| PS/2 Mouse | ET |
WD MR |
| Sound | WD MR |
|
| Gameplay | --- | --- |
| World Generation | WD MR |
|
| Block Textures | WD |
WD MR |
| Start Screen | WD MR |
|
| Player Movement | ET |
WD MR |
| Entity Collision | WD |
MR |
| Toolbar | WD MR |
|
| Health + Fall Damage | WD MR |
|
| Day and Night Cycle | WD MR |
|
| Items | WD MR |
WD - Working Draft, MR - Major Revision, ET - Edited