A 3D dungeon crawler game, inspired by “Gauntlet”, on a Raspberry
Pi
About this project
For this project, we were tasked to create a 3D dungeon crawler
game, inspired by the classic arcade game “Gauntlet”, running on
a Raspberry Pi 4. This project uses 3D graphics using OpenGL,
support for diffuse and specular textures, Phong-based lighting
from multiple sources and .obj model loading. It also uses the
Bullet library for physics, as well as ImGui for the UI. For the
gameplay, it contains a procedural dungeon generator, two
different player classes and three unique enemies.
This is a solo student project made during my 1st year at Breda
University of Applied Sciences.
My contributions to the project
Since this is a solo project, everything was done by me. A
list of my biggest contributions can be seen below:
3D rendering using OpenGL ES:
During this project, I used OpenGL to implement a 3D
renderer, as well as a bunch of neat graphical features.
These will be listed below.
3D model loading and rendering:
I used the Assimp library to add support for loading
.obj files. All meshes and textures are read and loaded
into the engine. To reduce memory usage, unique models
are loaded once and are stored in a resource manager.
After they're loaded, they can rendered.
Lighting using the Phong lighting model:
All 3D objects that exist in the level are lit using the
Phong lighting model. This means that they have ambient,
diffuse and specular lighting. When rendering an object,
the three closest lights are used to light the model. In
order to only apply specular highlights to areas of a
model where it makes sense, support for loading specular
maps (on top of diffuse maps) has been added.
Line drawing:
In order to make the debugging process for physics
objects a lot easier, line drawing was added.
Physics using the Bullet Physics SDK:
I implemented Bullet, which was a requirement for the
project. I use Bullet for adding collision to the level.
Whenever a new game object is added, a physics object is
added. This object contains all information that Bullet
requires for creating physics objects, like its shape
(box or sphere), what it's mass is and what it's group
and mask are.
When running in debug mode, the physics collision shape is
drawn using the line drawing system mentioned above. This
makes it easy to debug whether the collision shapes look
correct and whether everything is working as expected.
This image demonstrates the player standing in a room
with a bunch of enemies. All objects, like the walls,
the enemies, the player and the projectiles, have
collision boxes. These boxes are visualized using the
line rendering.
Procedural dungeon generation:
In order to make the game more interesting, I
implemented a procedural dungeon generator. The dungeon
generator guarantees that there'll always be an exit, a
key to the exit and a valid player spawn.
The way it works is that it creates a large room in the
center of the map. Next, the generation system picks a
random reachable wall tile and checks if it's possible
to create a new room + hallway.This process repeats
itself, and the dungeon will continue to branch out.
After a while, a maximum number of "branches" are
generated. When this is the case, the dungeon generator
goes back to the center room and picks the next wall
tile to branch out from. This process repeats until
either a maximum number of rooms are generated, until
there is no more space left in the level or until all
wall tiles in the center room have been checked.
This generation system has proven to be very reliable, and
has resulted in the generation of interesting and
maze-like dungeons.
A gif demonstrating some of the dungeon generation
results.
Three different types of enemies:
In order to make the gameplay a bit more interesting, I
decided to implement three enemy types. These three
enemies all have different attacks and health points.
The three enemies will be listed below:
Melee enemy:
The melee enemy does what it says on the tin: it attacks
the player using a melee attack. When the player
collides with the melee enemy, the player will take
damage. This enemy deals relatively minor damage and
spawns in Easy levels.
Shooting enemy:
This enemy shoots slow-moving bullets at the player.
When the player is hit by the bullets, they receive
significant damage. The player is also damaged when
colliding with the enemy, making this enemy a bit more
dangerous. This enemy spawns on Intermediate
levels.
Throwing enemy:
This enemy throws projectiles at the player if they are
within a certain range. Projectiles move along a cubic
Bezier curve, resulting in smooth movement of the
projectile. The throwing enemy can only throw
projectiles every second or so. The projectile deals a
significant amount of damage when it hits the player.
The enemy also inflicts damage when colliding with the
player, making the enemy even more dangerous. This enemy
spawns on Hard levels.
UI using ImGui:
I added ImGui to the project, which I used for
easily creating and rendering UI. This includes a main
menu, a pause menu and in-game UI like a score counter
and the player health. To make it look a bit better, I
changed the ImGui window properties to show nothing but
the text, and changed the default ImGui font with Comic
Sans.