Concept
For my midterm project, I created a game where the player controls a fish swimming through a river. The main goal of the game is to survive for as long as possible. While swimming through the river, the fish encounters different food objects and garbage objects. The player needs to eat the food to keep the fish healthy while avoiding the garbage. The fish’s health drains constantly, so the player cannot just sit still, and eating three pieces of garbage kills the fish.
The game is also intended to communicate a message about pollution in freshwater environments. Pollution in rivers can seriously affect the aquatic creatures living in that ecosystem. By making this the main idea of the game, I want the player to experience this problem through the gameplay rather than simply being told about it. Every piece of garbage the fish touches costs it a life, so the player quickly feels how dangerous a polluted river can be.
Implementation
I organized the code using several classes, there’s a Fish class for the player, a RiverObject class for every piece of food and garbage, a Bubble class for the background decoration, and a Game class that basically controls everything. The Game class has three states: a home screen, the playing screen, and a game over screen. While playing, the player steers the fish with the arrow keys and has three lives (shown as red circles) and a health bar that slowly drains. Eating shrimp, small fish or algae restores health and gives points, while colliding with plastic, a bottle or a can costs one life. Instead of writing a separate class for each kind of food or garbage, every type is stored as data (its size, the points it gives and the health it restores). Sound effects play when the fish eats food, eats garbage and dies. Another feature implemented was a high-score system using the browser’s localStorage, so the high score is still there the next time the game opens. A New High Score message appears when the player beats it. Images were generated using META AI and I used Claude AI to help me understand certain problems and the materials shared in class better. It helped me learn which tools or approaches would be useful for the what I wanted to do. The materials shared in class were also very helpful. Claude was also used to generate sound effects garbage collision.
Code I am Proud of
One part I am proud of is how the game gets harder. At first the game felt boring and easy to play, so I decided to make it harder as the player’s score increases. The game calculates a difficulty level from the score (one level for every 25 points, up to a maximum of 7).
// Difficulty level: goes up by 1 every 25 points (max 7)
getLevel() {
return min(floor(this.score / 25), 7);
}
That level is then added to the speed of every new object that is created:
let newObject = new RiverObject( width + 20, random(100, height - 50), objectType, random(2, 4) + this.getLevel() * 2, // faster at higher levels category, this.images[objectType.type] ); this.objects.push(newObject);
This allows the game to become progressively more difficult without requiring me to manually define a different speed for every level. Instead, the speed is calculated automatically whenever a new object is created. It also makes the difficulty system easier to adjust. The same level also shortens the delay between spawns, so the river stays busy even though objects cross the screen faster.
I am also proud of the health bar that I created which changes colour.
// How full the bar is (between 0 and 1)
let ratio = constrain(this.health / MAX_HEALTH, 0, 1);
// Green when healthy, yellow when low, red (flashing) when almost empty
let barColor;
if (ratio > 0.5) {
barColor = color(70, 200, 90);
} else if (ratio > 0.25) {
barColor = color(240, 200, 50);
} else {
barColor = color(230, 60, 50);
// Flash lighter and darker 4 times a second
if (floor(millis() / 250) % 2 === 0) {
barColor = color(255, 130, 120);
}
}
The colour of the bar changes from green to yellow and then red as the fish loses health. When its health becomes critically low, the bar starts flashing to create a sense of urgency. I implemented this using the constrain() function to keep the health ratio between 0 and 1, conditional statements to determine the colour, and millis() to create the flashing effect every 250 milliseconds. I am proud of this feature because it provides clear visual feedback, allowing players to quickly recognize the fish’s condition and react before it runs out of health.
Reflection
The hardest part was balancing the difficulty. My first version only made the objects faster as the score went up, but then the player often saw just one object on the screen at a time. New objects were still appearing every 1.5 seconds, while each one crossed the screen much faster than before. I fixed this by also reducing the spawn delay as the level increases (with a minimum of 0.3 seconds) and by capping the level at 7 so the game does not become impossible. It was also challenging to decide how the game should end. I first thought of running the game for a fixed time then the users could compare their scores, but then I decided to have a high score system so I added two ways in which the game ends. One when the health bar goes down and another is when the fish has collided with 3 trash items
If I was to improve this game in the future, I would add more variety to the gameplay. For example, I could introduce different river environments, additional types of pollution, or special objects that temporarily help the fish. The game would also be more interesting if the users could enter their username before playing and at the home screen the top 3 high scores with its username would be shown. This would make the game feel more competitive, as everyone would want to be on the leader board. Another improvement would be to include a short educational message or fact about freshwater pollution at the end of each game, helping players to understand real-world environmental issues. Overall, one of the most valuable things I learned from this project was the importance of organizing code using classes and methods. Separating the fish, river objects, bubbles, and overall game logic made the program much easier to manage.