Dracula Must Live
Overview
- Written in: Unreal Engine / C++
- Development period: 4 weeks
- Team size: 8 people, of which 4 programmers
- Source repository
- Itch page
My largest contribution was implementing the player's core weapon, the Grim Reaper's Scythe, which is thrown and recalled to damage enemies. Its base behavior has many nuances, but it also features three unlockable abilities which have two futher upgrades each, making it a very complex tool for the player. I also implemented the system that determines how the waves of enemies spawn, the minimap, one of the spells, and numerous other more minor things.
The unupgraded scythe has four basic states:
- Held, the scythe doesn't do anything and stays in the player's grip.
- Thrown, the scythe moves in a line at a constant speed, damaging enemies it hits, getting stuck if it hits an enemy or object straight on.
- Stuck, the scythe doesn't do anything and stays in the enemy or object it is stuck in, even if the enemy moves.
- Recalled, the scythe quickly returns to the player's grip regardless of distance and cannot get stuck on the way, ignoring walls and hurting hit enemies.
Pressing attack when the scythe is held throws it, and pressing it again when it's thrown or stuck recalls it. These states are reprensented in the code with a simple enum. Using a finite state machine is usually preferable to switching on an enum in multiple places (and there are even many things usually even better than that!), but not in this case. The scythe's states have so much fundamentally intertwined logic (even more so when factoring in the upgrades) that splitting the logic of the states into different objects wouldn't work well. Decoupling logic of different states won't help when the logic in fundamentally coupled.

The simplest of the unlockable abilities is the piercing attack. When activated it will never get stuck in an enemy, letting you damage large groups of enemies all at once. However, you have to precicely press attack when the recalled scythe reaches your hand for it to activate. Implementing it only required a slight modification to the enemy collision logic. Instead of deciding whether to get stuck or not based on if the scythe hits straight on or grazes, is just never gets stuck.

The coolest unlockable ability is the dash (probably). It lets you dash to the location of the scythe dealing contact damage to enemies on the way. You activate it by holding the attack button (when not holding the scythe) until the crosshair indicates it's charged and then letting go.
The Scythe is its own actor that sometimes attaches to other actors (player held or stuck in enemy). The "ScytheHand" is a SceneComponent attached to the Reaper Character. It's the Reaper's CharacterController which recieves input, so the ScytheHand has the role of forwarding the input to the Scythe. The charging of the attack button is also handled on the "ScytheHand" component, since it decouples the Scythe from the exact input method. It's also the ScytheHand's transform which the Scythe snaps to after being recalled to the player's hand.

The last ability is the charged throw which knocks enemies into the air and levitates then there for a bit. As the name implies it's activated by holding down attack, like the dash, except you charge it while the scythe is held. When it hits enemies it call a function on them that toggles their AI pathfinding movement and replaces with physics movement. This lets it apply a strong impulse upwards to fling the enemies into the air. A second or so after landing the enemy switches back to its AI pathfinding movement.
The charged throw ability without any upgrades in action.
The charged throw may not be so interesting on its own, but it's the ability with the most interesting upgrade. It's the range increase upgrade. The ability upgrades all essentially just buff numerical values, and a range increase fits that pattern. But the collider of the scythe is just its 3D model, and scaling up the entire scythe would look very strange. To avoid that I made the range increase not change the collider, but activate an additional one. Performing a charged throw with this upgrade unlocked will make a larger translucent spectral copy of the scythe appear around the scythe. This is a collider which damages enemies and knocks them into the air, but it's spectral so it doesn't get stuck in walls or enemies. Of course, the smaller physical scythe in the middle can still get stuck in things.

The Grim Reaper's Scythe with the larger spectral mesh visible.
The charged throw ability with the increased range upgrade unlocked in action.