Curse of Mermos was the final project at the twofour54 Gaming Academy developed by a team of five in just under 4 months. It is a lighthearted hack and slash game with fast paced action with challenging combat. Curse of Mermos has been green-lit and published on Steam on June 23, 2015. My roles in the project were game designer, lead programmer and project manager.
- Design, create and script gameplay systems for AI, combat, enemy wave generator and player mechanics
- Implement a data logging system to accumulate player data from the open beta to solve design issues
- Lead and assist the instructors in managing the teams task and project timeline
- Responsible for submission on Steam green light and publishing on Steam
Design AI Behaviours
Throughout the project I was also responsible of designing the behaviours of the enemies. We ended up with a total of 7 different enemies. It was important to us that each enemy would present a new challenge/strategy for the player and be able to come up with interesting gameplay scenarios when combining enemies together.
The scarrab is the most basic enemy in the game, he is a melee fighter with low health. They attack pretty quick so the player needs to get rid of them as quick as possible before they get too close.
The skeleton is the basic range enemy in the game. With the combination of melee and range enemies, the player now needs to be more careful about his positioning. The skeleton is a bit smarter than the scarrab as he would try to hide behind cover whenever possible.
Now that the player is used to ranged attacks, the Pharaoh Head challenges the player with homing bones. In order to avoid them the player must try to dodge at the last second. This enemy is difficult to kill from close range as he would always run away from the player at close range.
Aten is a rolling bomb! Once an Aten spawns, the player should take them out as soon as possible before they get too close as they deal tons of damage once the explode.
After the player is used to all previous enemies, Hathor is introduced to up the difficulty. Hathor is a healer who spawns healing wards on the ground that heals enemies over a duration of time. If enemies are too low on health, they would go to a healing ward to heal up. The best strategy is to go after the healers first or else you would be fighting for a very long time.
The fire mummy function is to attack the player from very far range by throwing a flaming fireball at him. This fireball deals AOE damage over a period of time in an area. This also hinders the players movement and allows him to think about his positioning really carefully. Once getting close to the mummy he would start attacking with a breathing fire attack.
Onuris is the toughest enemy in the game. He has very high HP and is the only enemy with one way to defeat him. Onuris would always keep his shield up, once he gets close to you he would slam his shield on the ground leaving his behind wide open for you to damage him.
The golden scarrab is a non hostile enemy. He spawns randomly between waves and has a large amount of souls in him that players love. Spawning this enemy between a lot of enemies can cause a lot of distraction to the player as he is available only for a limited time.
What are agents?
Agents are basically any character in the game. In our game we have Abdu, the main character and all others NPC’s (Non playable characters).
In order to have a neat and efficient system I set up our classes as such:
For an agent to function an agent brain needs to be plugged in an agent. Think of an agent as a ship and the brain as its captain. A ship cannot function without its captain. Every ship has common properties such as its speed, destination, armor etc. This way all common properties between our two types of captains (NPC controller and Abdu Controller) are coded only once. NPC controller contains all common functions between all enemies. This contains functions such as moving to a point, checking for obstacles, taking cover etc. Another class extends from NPC controller that contains the enemy logic. Since every enemy has a different behavior every enemy will have their own logic. On the other hand since we only have one Abdu in the game, all his logic is coded there.
Creating a wave system is a major part of our game since it’s a wave based game. Coming up with a robust system that creates interesting gameplay scenarios was challenging. Given the little time we had for our project I came up with quick and simple methods.
The following diagram shows what our wave system consists of:
- The wave manager contains all the logic needed to spawn enemies and keep track of the wave progress.
- A wave consists of multiple phases that are designed by the designer.
- Each phase has conditions when to start spawning groups.
- Finally groups are a set of enemies that you wish to spawn.
The following is an example of a phase:
The condition for the above phase is to start spawning after 5 seconds. You can also set another condition to start spawning enemies when there are a number of enemies left from the previous phase. Then you can set up the groups we want to spawn, we can also set a time delay between groups and decide on how to spawn them.
- Medium from Abdu: Enemies will spawn in a radius at a medium range from Abdu as shown in the diagram. Enemies will not spawn in the red circle.
- Random: Spawns enemies at random spawn points in the chamber Abdu is currently in.
- Outside Chamber: Spawns enemies in the chambers that Abdu is not in.
Through play testing we have found out that a lot of the times enemies will spawn all infront of Abdu since it picks a random spawn point. To improve on that I decided to always calculate the average position of where the enemies are and try to spawn enemies on the opposite side relative to Abdu. This way the wave system will always try to spawn enemies around Abdu instead of being completely random.
At the beginning of the project I have attempted to create my own collision system instead of using the physics engine in unity to avoid all sort of problems physics introduces. Since our game is more or less a 2D game(with no verticality) , I modelled all characters as circles and wrote a code for perfect collision between two circles using the following methodology found HERE.
Once a collision is detected though I needed sliding to occur which is described in the image below:
The white circles are the size of the collisions. The red debug line shows the input velocity of the character from the joystick. The blue debug line is the normal direction to the point of contact between the two circles. The green debug line is the tangent to the point of contact between the two circles.
Once collision is detected I break the red line Vector into two components, one in the normal direction and one in the tangent direction(green line). Then I will translate the character with the magnitude and direction on the tangent line(green line). This way instead of a character abruptly stopping, there would be a sliding effect which feels much more natural.
Going on with the collisions I attempted a test between more than one characters and succeeded. Issues started arising when collision occurs with more than one MOVING characters. Given the time of the project(14 weeks to complete a game from scratch to finish) I was forced to move on and use the physics engine for collision. I would love to come back to this problem some day though.
I was responsible to create a data logging system for the open beta. A lot of data is saved on to a note file such as health lost in a wave, number of potions used in a wave, numbers of souls collected in a wave and so on. All of those data were saved automatically throughout a play session and converted into a JSON format. Then this data was used as input into a tool created by one of the team members to be able to display it visually as shown below.
You may find out more at: