Skip to content

Modern quid-earning pet-keeping and zombie horde simulation game for the Object-Oriented Programming class (2024). (No actual OOP exists in this project.)

Notifications You must be signed in to change notification settings

Sinono3/quidmasters

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Quidmasters: Petbuilder

This repository contains the source code for the game Quidmasters: Petbuilder.

Dependencies

  • SFML >= 3.0.0
  • C++23

Explanation

The source code is over 1700 lines of code, so the following explanation is a brief overview of how the game is structured.

Let's explain how the game's inner workings are by looking at the main function. We first open the SFML window and init the GameState. This is a class which contains all the state of the game. Everything that the player sees is merely an interpretation of the GameState. Then we create an object of type Assets which loads all of the game assets on its constructor. We set the stage (a field inside the GameStage) to be at the menu (GameStage::Menu). We then begin the game loop, which is a piece of code that will execute every frame of the game (roughly 60 to 144 times per second, depending on your monitor). We can divide the game loop into two parts: update and draw.

  • During the update phase we call functions that both read and modify the game state. We call each of these functions systems. It is here where we calculate the game logic.
  • During the draw phase we call functions that read from the GameState and write into the sf::RenderWindow.

systems::player::movement

This system is occupied of the player's movement. Depending on which keys are pressed (W, A, S or D) we create a vector pointing in the direction chosen by the player. We normalize this vector to avoid having a greater magnitude during diagonal movement. We add this vector to the player's position. Finally we also calculate the vector from the player to the mouse, to make the player look towards the mouse.

systems::player::hunger

Occupied of the reducing the nourishment of the pet over time. This nourishment is refilled when killing zombies.

systems::player::fog

Makes the player lose sanity when going out of the viewing area. This is to discourage using the outside as an escape.

systems::player::loseCondition

Checks if the either:

  • the player's health is equal to or below 0
  • the pet's nourishment is equal to or below 0
  • the player's sanity is equal to or below 0

If any of these is true, we set the GameStage to game over.

systems::player::quidPickup

Occupied of checking the player's collision with coins on the floor. If this occurs, we add tha quid to the player's pouch, also playing a sound effect.

systems::player::warnings

Makes the pet scold you when he's hungry, requesting food immedieately. Or else. Increases the volume of a heartbeat sound effect as your health lowers.

systems::player::guns

Advances all of the cooldown timers for the guns. Checks if the player is clicking, if so request to fire the currently selected gun. If the cooldown timer for this gun is over, then we can reset the cooldown timer and spawn bullets. Spawning bullets involves:

  • Getting randomly generated values for the damage, knockback and bulletSpeed (according to the gun specification)
  • Generating an amount of bullets with these values. The amount depends on the gun.
  • Setting the position of these bullets to be at the player position.
  • Setting the velocity to be the forward direction of the player.
  • Adding the generated bullets to the global bullet vector (in GameState).

This system also handles gun switching. It checks if any of the 1-9 keys were pressed, and if so, it tries to switch. If the user does not yet have that gun, the switch is simply ignored.

systems::bullets::physics

Iterates through each bullet in the global bullet vector. For each bullet, we apply the velocity to the position. After that, we check if the bullet's collided with any enemy simply by checking the distances with all of them.

(Interjection: Yes. This is a bit slow. We don't use quadtrees or other optimizations like that. The time complexity is $O(mn)$ ), where $m$ is the amount of bullets and $n$ the amount of enemies.)

If the bullet has collided with an enemy, we remove health from the enemy and play a sound to let the player know they have hit an enemy.

systems::bullets::homing

One weapon produces a special type of bullets: homing bullets. These bullets "chase" the enemies. They work by being affected by a gravitational/electric field generated by the enemies. This accelerational field is generated at a point $\hat{p_x}$ by adding all of the accelerational fields for each enemy at $p_i$ with the formula:

$$ a = \sum_i \frac{C}{|\vec{p_i} - \vec{p_x}|^2} (\vec{p_i} - \vec{p_x}) $$

$C$ is a constant that we can tweak to our liking.

We approximate this field discretely by creating an 80x60 matrix of vectors, each element representing one square unit of the game in the viewing area of the screen. We use the previously shown formula to calculate the field for every point.

After, we iterate through each homing bullet and get where it lands on the matrix. If it does land on an entry in the matrix, we get the acceleration and apply it to the bullet, modifying its velocity.

systems::waves

In charge of spawning the enemies, starting and ending waves and breaks. The system begins by checking if we are in breaktime or not.

  • If not in breaktime
    • Check if all the enemies due on this wave have spawned already.
    • If no enemies are alive and all the enemies have already spawned, the wave is over
      • If this is so, we set the break time to 10 seconds and we set the GameState.inBreak to be true.
    • We advance the enemySpawnTimer. If it reaches 0:
      • We restart the timer.
      • We spawn an enemy of each class.
  • If in breaktime
    • Advance the break time timer
    • If the timer reaches 0:
      • We set the set the new enemies due-to-spawn in this wave. (This basically consists of filling an array where each element corresponds to an enemy type with how many enemies of that type will spawn)
      • We set GameState.inBreak to false.

systems::enemy::ai

Accelerates the enemies towards the player. Limits each enemy's speed according to their max speed. Applies the velocity to each enemy's position. If the enemy is colliding with the player, apply damage to them.

systems::enemy::collision

If the enemies get too close between each other, we apply oppossing accelerations to separate them. This works to prevent all the enemies converting to a single blob, letting them be blobs instead.

We also limit their positions, to prevent them from straying too far from the viewing area.

systems::enemy::death

Checks each enemy's health to see if it has gone below 0. If so, we remove the enemy from the game and spawn a coin drop.

systems::message

Makes messages emitted by the pet disappear after a while.

systems::store

Handles all of the store logic.

systems::music

Cross-fades music tracks depending on the wave the player is in.

systems::hacks

Enables three hacks:

  • Pressing all the keys to write BINGO at once, gives the player 10k quid.
  • Pressing the KL keys skips the wave and gives the player the quid that corresponded to the remaining enemies.
  • Pressing the HSK keys skips the breaktime.

Compiling from source

Linux/MacOS

Install the respective development SFML package available in your distribution. In MacOS you can install SFML using brew install sfml.

Then you must clone the repository and run make:

$ git clone https://github.com/Sinono3/pou
$ cd pou
$ make run

The game should compile and run after these steps.

Windows

You need to install MSYS2 and download the 64-bit UCRT MinGW toolchain and SFML with it. You can do so by typing this in the MSYS2 UCRT64 terminal:

$ pacman -S base-devel mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-sfml

After this simply run make run inside the terminal and inside the project directory and the game should compile and run.

Windows (Visual Studio)

If you instead want to compile this using Visual Studio, you will have to create a project in Visual Studio and manually configure includes and linking for SFML.

About

Modern quid-earning pet-keeping and zombie horde simulation game for the Object-Oriented Programming class (2024). (No actual OOP exists in this project.)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published