Pandalf was the final product of our second-year project. The assignment was to create a game and publish it on Itch.io. We decided to make a top-down roguelike because it allowed us to manage performance effectively by keeping the levels small, given the limited visibility inherent in a top-down perspective.
In Pandalf, you play as a red panda wizard, striving to survive as many rounds as possible. Occasionally, you'll come across your home village, where you can buy new spells and customize your loadout. You face off against an army of bears, including black bears that are tanky and hit hard but move very slowly, spear-wielding bears that are fast but fragile, and honey-throwing bears.
Throughout this project, I learned a great deal. I developed intricate systems such as an inventory and shop system, and an enemy spawner. I also learned to work with inheritance and scriptable objects. It was an educational and enjoyable project, and I am proud of the end result!
👤 Role: Game Developer and Designer
👥Team Size: 3
⏱️ Time Frame: 8 Weeks
⚙️ Engine: Unity (C#)
Everything I did outside of programming:
Designed a large part of the game
Implemented all the animations and logic for the animations
Created the gameplay trailer
Everything I Programmed:
Movement of the player
All the enemies (AI, pathfinding, abilities health and damage)
A shop for the player to buy new spells
A inventory system where the player can inspect and equip his new spells.
All the player UI (Healthbar, manabar, exp bar, ability icons)
All the UI windows in the game (Shop, inventory, controls screen, etc)
A health and damage system
Camera effects
Level transition system
Enemy spawner
A soundmanager
Player level system
Difficulty manager (System that increased the difficulty of the game each round)
Creating the shop and inventory UI was a significant challenge, especially without the final art. I had to use my imagination to incorporate all the elements. We aimed for a shop to buy new spells, display spell attributes upon selection, and a UI tab to view and equip owned spells by dragging them into slots. Although I had previous UI experience, this system was on a different level.
I decided to learn scriptable objects so I created a scriptable object script to store all spell data. This data stored things like the title and description to damage and range. This allowed easy access to spell information anywhere by referencing the scriptable object. When a spell is purchased, it’s added to an array of owned spells. Dragging a spell into a slot equips it to the player's staff. This approach lets us add new spells without changing any code.
I was also tasked with creating the game's enemies. The players fight an army of bears, and I wanted each enemy to be distinct. I started with a base enemy script to handle common functions like taking damage, dying, and setting its spawner. This script included variables for health, movement speed, damage, and the experience dropped upon death.
The first enemy I created was a fast bear that runs towards the player, stabs with a spear, and then jumps back. Using navmesh, the bear follows the player, attacks when close, and jumps back after the attack.
The second enemy throws honey at the player, creating a pool that slows and damages over time. Unlike the first bear, this one maintains distance to throw honey, adding a dynamic element to the level by shrinking the player's walkable area.
The third enemy is a big black bear that acts as the tank. It’s slow but deals massive damage and has a lot of health.
Since our game has no ending and players can continue as long as they complete levels, we needed an effective enemy spawning system. As a roguelike, the game requires a way to randomize enemies each round to keep it fresh and replayable. I developed a system that randomly selects and spawns enemies at various points around the map.
For each new level, I simply create spawn points around the map and add them to the enemy spawner. The enemy spawner uses a weight system: each enemy has a weight value, and spawning an enemy subtracts its weight from the total level weight until it reaches zero. The total weight increases with each round, making the game progressively more challenging.