CCL4
Course: CCL4 SS 2025 (5 ECTS, 3 SWS)
Student ID: cc231036, cc231032, cc231043, cc231045
BCC Group: B and C
Witch’s Brew
by Sara Beslic, Corinna Huber, Helene Urban, Nicoleta Dublea
Roles
Sara Beslic
Coding, Game Logic
Corinna Huber
3D Modeling, Documentation, Story and Game Design, Organisation
Helene Urban
3D Modeling, Game Trailer
Nicoleta Dublea
UI Design, Game Audio
Witch’s Brew is a dark, low-poly 3D adventure game set in a haunted forest. You play as Raven, a young witch who must collect ingredients, brew magical potions, and banish ghostly enemies that spawn from an ancient graveyard.
Guided by Wisp, a mysterious moth-like creature, players explore a small open world filled with spooky atmosphere and magical danger. This project was created to apply and combine skills in 3D modeling, animation,
Unity programming, and game audio. It represents our first complete game developed as a team.
Important Links
Github Repository
https://github.com/corinnahuber/CCL4PotionWitch
Documentation
https://corinnahuber.github.io/CCL4PotionWitch/
Tasks and Task Distribution
📊 View Task Distribution Sheet
Miro board
https://miro.com/app/board/uXjVINxA_V0=/?share_link_id=535119272679
User guideline
Connect Repository to Unity
either play the game directly in Unity (run Main Menu Scene)
or Build the project and play the built version
Note: Project is built with Universal 3D in Unity
Story
In the twilight-drenched forest of Black Hollow, a young witch named Raven stirs her cauldron, desperate to cleanse her haunted home.
Once a place of peace, the forest is now stalked by restless ghosts, echoes of an ancient curse. These spirits feed on fear, growing stronger in the dark old woods.
Armed only with her cunning and her potions, Raven must face each ghost and banish them all to restore the forest’s peace — or be consumed by the spirits that hunger in the shadows.
Ending
With the last ghost banished, a calm silence returns to the forest. Raven’s potions have driven away the darkness, and the woods can finally breathe again.
She stands among the whispering trees, knowing that peace has been restored — at least, for now.
Characters
Main Character
(Witch, human)
Name: Raven
Side Character
(Moth)
Name: Wisp
Enemies
Ghosts
Goal
The player’s ultimate goal is to cleanse the forest by defeating all the ghosts haunting the world.
To do this, they can craft up to five unique potions, each with its own effect. Ingredients are scattered throughout the world and must be gathered to brew potions at the cauldron outside the witch’s home.
When a ghost appears, the player must quickly choose the right potion and throw it at the ghost to kill it. But beware — if the ghosts get too close and deals too much damage, it’s game over!
System Design
Player role:
The player takes on the role of a witch in a third-person perspective. To cleanse her haunted forest of ghosts,
she must brew potions using ingredients found in the woods.
However, she must remain cautious - ghosts lurk in the shadows.
The witch’s Book:
Her ancient book contains recipes for potions, listing all the necessary ingredients she must gather.
Each potion has a unique effect, essential for battling the ghosts.
The ghosts:
Ghost health depletes based on the potion used (Burn = fast damage etc.).
Their movement and attack patterns will be polished later to align with the rest of the game visuals and logic.

Key Features and Implementation Detail
Implementation Logic Explained
- Player collects the ingredients scattered in the world ( prefabs holding Item data).
- Collecting updates inventoryFieldUI and state with ingredient and its quantity.
- Opening the Book for checking the potions ( data stored as a List of potions holding their respective ingredients). Book is updated every time a player collects an ingredient.
- If all the ingredients are there for the potion the Brew button enables brewing.
- Player brews the potion and triggers immediate Update of the book and the Inventory including the potion appearing in the bottom bar.
- Potion that is at the first position is instantly equipped ( purple color) meaning that potion can be used for defeating a ghost. Clicking on a potion we can change which one we are using.
- Damage potion – removes 1/3 of the ghosts health
- Destruction potion – depletes the whole health and ghost is destroyed
- Stun – stops the ghost movement for a few seconds
- Ghost and fighting
Each potion and their effect on the player or the ghost is written in the PotionEffects and then called every tine when a player uses the potion on themselves or on the ghost. Again the use of potion triggers updating of the potion inventory ( bottom bar).
Ghosts are randomly placed around the world using setDestinantion on a navMesh and they roam around the place until they spot a player. If in the given range they start to chase us and the fighting icon appears- the time when we can fight the ghosts. When the icon is gone potion has no effect and cant be used.
If hit by a ghost, ghost goes into cooldown to give us a chance to escape. Every time we are hit the update method checks if we are out of hearts and ends the game if we are dead.
System Infrastructure

Update

Achievements
- Very proud of the characters we made, it was a long and hard process at times, especially the rigging and weight painting part for it to look good when animating, but we are really proud of the outcome
- We tried to make as many assets as possible ourselves so the whole game would have a nice feel to it, we are very happy with how the world looks and feels like
- We were able to implement almost every function we planned on having, we have a nice combat system, the inventory works really well, the witch is able to brew potions as planned and use them to fight off the ghosts
- Managed to implement the whole logic as we planned. Biggest achievement is understanding how to make the code reusable and clean and how to reference the data through the classes and pass the necessary data to make all the Updates instant and correct
Major Challenges and Solutions
- One of the biggest challenges was definitely the rigging part and adjusting the weight painting accordingly, it just took a lot longer than expected
- I faced a lot of challenges in Blender with exporting the right files and also animations not saving, but now I know how to tackle those problems correctly which will safe me a lot of time, energy and struggle in the future
- Handling Item Persistence and Recognition: When collecting ingredients, cloned items weren’t recognized as the same item by the inventory system and the book didn’t update properly. Fixed by correctly passing and referencing to the same item type.
- Inventory UI Index Out-of-Bounds: After using potions and updating the UI, selecting or highlighting potions caused index out-of-bounds errors. Added safety checks to reset selectedIndex if it’s invalid, and defaulted to auto-selecting the first potion only if none were selected.
- Wwise Integration Errors: One of the biggest challenges was integrating Wwise into Unity without causing conflicts across branches. After switching from the development branch to wwisedevelopment, Wwise just kept throwing errors when integrating into Unity. After troubleshooting for hours and clearing the Wwise cache from the project’s folder, I managed to finally connect Wwise to the project. I finally got help from a teacher who guided me through properly initializing the soundbanks and Ak components, and that resolved the issue.
- Wwise branch merging conflicts with every branch: The Wwise branch caused merge conflicts with nearly every other branch due to the large number of auto-generated files (.bnk, .xml, .json, Unity .meta files) that Wwise modifies. This made it very difficult to integrate the audio work without interfering with unrelated changes in other parts of the project. Due to the limited time and risk of breaking other working features, we decided not to merge the Wwise branch directly into the main development branch. Instead, the partly functional audio implementation can be found in the wwisedevelopment branch, where sound events are integrated and working.
Minor Challenges and Solutions
- Something I learned when 3D modeling was its very important to keep close attention to the normals of a model, because if the normals are flipped (red) unity won’t show those faces, and that can be really painful to fix, the solution is to just always keep checking on the normals in blender
- Challenges Faced in Door Teleportation System: The player didn’t appear in the right place after teleporting or changing scenes. In the beginning the data was also not preserving which when changing the room which is now fixed bot the player is still when teleporting falling in an open space. Tried to fix it but didn’t work so we left it as it is since it doesn’t affect the rest of the game.
Reflections on the Project
- The animations could be smoother
- Would have loved to make all the assets ourselves (like mountains, rocks and graveyard)
- Recording some of the audio elements would have been nice
- Learned how things really work under the surface and understood the need for planning and structure early on
- All in all we are proud of what we achieved in such a short amount of time, but there are definitely a lot of improvements we could have made if we had more time :)
3D Models
In-Game