Oliver Nyholm
AI and Gameplay Programmer

Spite - Ragnars Mjöd



C++ | Action RPG | AI | Pipeline


About the Game


Spite - Ragnars Mjöd was my sixth project at the Game Assembly. The game was created in our own C++ and DirectX11 engine, Yellowsnow over the span of 10 weeks at 50% work time. The projects reference game was no surpise, Diablo 3.

"After an all night bender with your friends you wake up alone in the snow and surrounded by the undead. Battle draugr and ice giants to recover your stolen mead!"


Main contributions


AI


Gameplay

  • Created leap ability at alpha stage.
  • Participated in creating ActorComponent that collected movement data from ControllerComponents. (PlayerController, AIController, BossController).

Pipeline

  • Was part of exporting and importing the navmesh to the engine from Unity via Houdini. Unity has a magical navmesh that needs to be tweaked a lot when trying to export it.
  • I worked close together with the Technical Artists this project and helped them when needed.

Tools

  • I continued working on the particle editor when new features were added to the particle emitters.
  • Added debug "one-liners" to be able to visualise lines, boxes, spheres during development.
  • Created a system to toggle between player's camera and a camera to move around freely with for debugging.

Engine

  • Added support for Instanced rendering.


Draugr


The Draugr's behaviour tree can be found here.

The biggest obstacle to overcome of the project was maintaining the base enemy, the Draugr. The draugr were melee entities which the level designers spawned A LOT of. As there were a lot of enemies, I had to do several optimization to reduce risk of low framerate. One solution was that all enemies entity ID:S were placed in a grid, reducing the amount of enemies to check around them when using steering behaviours. Another one was that when enemies were far away from the player, they had leaders that would do pathfinding and checking sight to the player, while the "minions" were idling.

The way leaders were determined was by a simple function that was called when enemies were spawned or when their current leader was killed. Below is the code for finding a nearby leader. The game had a PollingStation, which the enemies used to get entity IDs from. In this case, they asked for a list of all current leader IDs. If there was none nearby, they become the leader and add themselves to the list. If they were previously following a leader, they changed their state to engaged, moving towards the player.



Another issue that needed to be solved for the Draugr was that when there were so many melee entities, I could not have 50 units all grouping around the player trying to attack whilst trying to separate at the same time. To solve that issue, I placed 12 attack slots that the Draugr could fight at. This would only allow twelve characters to attack the player at the same time, which brings me to the next issue; making sure the others wait for their turn.

The solution to that issue was to check in front of the Draugr, seeing if there were any other units waiting for their turn. Below is a node in the behaviour tree, that was called only a few times per second. First, they would check if they had an attack slot, and would in that case ignore if there were any others waiting ahead of them. They would also ignore checking if there were any others waiting in front of them at a certain distance, which would allow them to try move closer, creating more circular formations surrounding the player. If they were close enough, they would also ignore the fact and just hit the player instead. Finally, if none of the above statements were given, they would raycast and check if there was another enemy waiting in front of them.