- Controls:
- Use the mouse to select an attack option from the 3 different attacks.
- Each attack will do a random amount of damage.
- The goblin will attack back after each attack.
- To win, you must defeat the goblin before he defeats you
YouTube Link: https://youtu.be/1z48uRbFQiE
In order to run the executable, you must first unzip the file called “Game Files” and inside that folder will be a executable called “TurnBasedGame” which you can then double click to launch.
In this project I have used multiple SDL dependencies such as SDL.h, which includes the main SDL2 library. This is used for handling graphics, events and other low-level operations. SDL ttf, this is used for rendering text that work with TrueTypeFonts, and SDL Mixer, this is used for handling audio in my game.
The currentState variable of GameState is used to manage the game's different states (MENU, PLAY, GAME_OVER, EXIT). The game updates and renders different components based on the current state. This is a characteristic of the State Pattern, where the behaviour of the system is dependent on its state.
> - The game logic in handleEvents(), update(), and render() changes depending on whether the game is in the MENU, PLAY, or GAME_OVER state. > - For example, in handleEvents(), it checks for the state before responding to button presses (if (currentState == GameState::MENU)).The game mechanics are based on a turn based combat system where the player and an enemy take turns attacking eachover.
The game transitions between different states using the GameState enum.
Menu: Where the player can start the game.
Play: The actual combat phase where the player and enemy interact.
Game Over: When either the player or the enemy dies
The player and the enemy engage in combat where the player can choose different types of attacks. Each attack reduces health and the turn alternates between the player and the enemy.
Player Actions:
The player can select from a list of attacks (e.g., "Slash", "Kick", "Fireball").
• After selecting an attack, the player's attack is executed, and the enemy takes damage.
• If the enemy is still alive after the player's turn, it will counterattack
• The game checks if either the player or the enemy has died (i.e., health reaches zero).
•The combat flow is controlled in the handleEvents() and update() functions:
•In handleEvents(), the player selects an attack via mouse click:
•The combat flow is controlled in the handleEvents() and update() functions:
player.selectAttack(i); // Select attack based on button index
player.performAttack(enemy); // Perform the selected attack
After the player's attack, the enemy can counterattack if it is still alive:
if (enemy.isAlive()) { player.receiveDamage(rand() % 30);} // Enemy attacks the player
The game checks for victory conditions (game over) in the update() method:
if (!enemy.isAlive() || !player.isAlive()) { currentState = GameState::GAME_OVER; }
Both the player and the enemy have health points that are reduced when they take damage. The health is displayed in the UI, and when it reaches zero, the game ends.
The renderHealth() function renders the health of the player or the enemy:
renderHealth(enemy.getHealth(), false);
renderHealth(player.getHealth(), true);
The player's health is managed through the Player class and the enemy's health is managed through the Enemy class. Both classes have methods like receiveDamage(int) and isAlive() to manage health:
player.receiveDamage(rand() % 30); // Random damage from the enemy
The health text is rendered as part of the game interface in the renderHealth() method, where the health is displayed in red colour:
SDL_Surface* textSurface = TTF_RenderText_Solid(font, healthText.c_str(), textColor);
The game logs each attack, storing messages that describe the player's and enemy's actions. These logs are displayed in a box at the bottom of the screen.
Attack log messages are stored in a std::vector attackLog and rendered in the renderAttackLog() method. The log is updated whenever a new attack occurs:
std::string attackMessage = player.getName() + " attacks " + enemy.getName() + " with " + player.getAttackOptions()[i] + ". ";
attackLog.push_back(attackMessage);
The renderAttackLog() method takes care of displaying the log with proper text wrapping:
std::vector wrappedLines = wrapText(font, *it, attackLogRect.w - 2 * sidePadding);
I carried out various tests when creating this game to ensure there were no major problems at launch. Some of these tests included:
Making sure the game window launched in the correct dimensions
Making sure the SDL libraries and components like SDL_ttf and SDL_mixer are properly initialised
Ensuring the background music plays at launch, and the start menu has the correct background texture
Making sure the start button functions
Verifying transition from MENU to PLAY state
Verify transition from PLAY to GAME_OVER state
Verify transition from GAME_OVER to MENU state
Ensure the player can perform an attack
Ensure the Enemy can perform an attack, and make sure it happens after the player attacks
Verify correct calculation of damage
Test player's health depletion
Test enemy’s health depletion
Verify button states (Normal, Hover, Pressed)
Verify correct attack buttons are displayed and interactable
Test attack log displays correctly
Verify health UI renders correctly
I am very confident and happy in what I have achieved just by using SDL and C++, this was my first time using and experimenting with SDL and I feel like I have learnt a lot during this project. I also am happy with the progress I have made in strengthening my c++ skills as I now feel more confident in working with classes and object-oriented based code. What i would do differently if I had to do a project similar to this again is learn how to use animation in SDL, I’m not sure if there is a method on making animation using SDL but if there is i would want to learn about it and implement it into my work. I also would like to have added more enemies and a lives system so the player could keep playing after defeating an enemy, but unfortunately, I did not have enough time.
Thank you for taking the time to read this report - Morgan Hodge