TRAILER

Overview

Kardtana is a first person slasher, rouge-like game with a focus on fluid movement and satisfying card “slicing”. The goal of the game is to obtain money by slicing and dicing through cards in order to meet round-based quotas and obtain upgrades that provide the player with various stat bonuses and abilities.

The development of the project began end of May/beginning of June of 2024 and the development team consists of me and 3 of my university colleagues. We all act as general developers and are quite flexible between picking up tasks from multiple departments due to our small-scale team size. Additionally, we all engaged in discussion and critique regarding all the disciplines of development to make sure that the vision of the game is not lost.

Working on this project truly allowed me to tap into my potential as a developer by allowing me to practice already familiar concepts of development and UE5 but also forcing me to branch out to other unfamiliar areas of development like rigging and animation.

In terms of organisation team organisation, everyone from our team arranged weekly meetings via Discord to discuss progress and additional ideas for the project. For planning and idea generation we used Miro and task tracking ClickUp.

Engine: Unreal Engine 5
Source Control: GitHub
Team Size: 4
Development time: 4 months
Platform: PC
Year: 2024

MY CONRIBUTIONS

From the get-go, we wanted to make sure we nail down the game’s responsiveness/juice to high-quality standard. And for this project having a satisfying card slicing mechanic was a no brainer in terms of nailing the pillars of this game’s juice.

CARD SLICING

The card slicing system is based on what I call “procedural mesh slicing”.  

For it we have a Sliceable Mesh actor that has the proc mesh slicing already implemented which then I added onto the Enemy Character via a Child Actor component.

Sliceable mesh actor

Enemy character

Lets dive into the functionality of this system in more depth.

Starting off with the Sliceable Mesh actor, I have created an actor that has the procedural mesh and static mesh components. Using a “Copy Procedural Mesh from Static Mesh” the proc mesh replicates the static mesh of the card and then we destroy the static mesh of the card upon initialisation.

Copy proc mesh function upon initialise (Sliceable mesh actor)

The actual slicing occurs within the Slicing function that is being called when the card is last hit/killed. There the Slice Procedural Mesh function is fed the Plane Position and Plane normal of the hit result, which is them followed up by a Set Simulate Physics function responsible for doing what it says. Then the impulse of the mesh parts flying off is multiplied by the current speed of the character so that no different slice feels the same if the character is at a different pace. And also I added a “Set World Scale 3D” functionality in the beginning to massively increase the size of the mesh and then shrink it down later in the code without the player noticing. This is sort of a trick that makes the slicing feel better because in my testing I discovered that Unreal Engine is more responsive with slicing more voluminous objects compared to thinner ones.

Slice function (Sliceable Actor)

Then for the actual implementation of the Sliceable Actor into the Enemy Character blueprint I used a child actor component containing the Sliceable Actor blueprint which is hidden during the lifespan of the enemy card and revealed upon death. This is so that the animations are being handled by the skeletal mesh of the enemy character and when the character is dead the skeletal mesh hides and he Sliceable Actor is revealed in it’s already sliced form.

Enemy character outline (Child Actor circled)

Slice functionality (Enemy character)

Animations and animation programming 

Hand animations, for the animations I used the game Ghostrunner and real life recordings of myself hands as a references to nail down the frame by frame motions that might not be noticeable for a fast animations like ours or Ghostrunners but do subconsciously feel good in game.

For the card animations we asked ourselves how a card walk? We were thinking about implementing the card’s walking as a hop/jump but thought that wouldn’t look nice and could end up a bit buggy so we instead looked into the game Cuphead and the King Dice boss fight where the cards would bend from their bottom corners diagonally when they walked which looked pretty good.

King Dice fight reference (from Cuphead)

I didn’t exactly implement the diagonal bending but instead resorted to regular forward bend of the cards when walking which still looks pretty good on practice and it isn’t distracting as opposed to a jump.

Card walking animation

I did implement a jump animation that indicates a turn of direction for the card.

NOTE: The actual jump happens physically in game, the animation more of a twist that complements the actual jump.


“Jump” animation

And for the attack I initially wanted a “catapult” type bend where half of the card was bent backwards to telegraph the attack but instead we settled for a inwards central point bend.

Attack animation

Attack animation (legacy)

For the hand animations, in terms of programming, I used a two hand system. Meaning that both hands of the player characters have two separate animation blueprints.

 This allows me to make implementation of animations such as the Card Scanner Snap to play during mid attack or any other animation of it’s opposite hand since both hands are separate and won’t interrupt each other.

Scanner and Attack

Scanner and Attack while crouch-sliding

Player character

(Viewport Outline)

(Viewport)

Hands animation blueprints

(Right hand)

(Left hand)

This saved me a lot of time in terms of implementing more complicated animation blending systems that will make sure that animations on opposite hands won’t be interrupted by the other separate one.

Music and music programming

The soundtrack of the game currently consists of 3 different tracks from the phonk jazz genre which I produced with the help of preset samples from the online DAW Bandlab. You can find the full tracks below.

I did not want to compromise on the music of the game, especially the way it flows and loops in game. So for that, I wanted to make a transition system for the tracks that dynamically switch depending on if the player is in the pre-round (resting stage) of the game or during the round. So what I have here is 3 tracks, however that doesn’t mean that we want to loop them from beginning to end because let’s say that the I Was Chillin’  track has some more smoother and relaxing sections mixed in with some more energetic bassy ones. If the whole track is looped in during the round where there is a lot of action but the track is playing at the part where the music is more relaxed this will break the intended feeling of tension in the gameplay look e.g. think Doom (2016 or Eternal) with classical music instead of metal.

For this I have decided to different sections of the tracks and add them into 2 categories which I have labelled “chill” (for the relaxing vibe) and “medium+hard” (for their more moderate to intense feeling that represent the flow of action in game). By using these labels I have created a system that uses a Music Manager actor within the level that stores all of the transition events for the tracks and also some additional functionality in the already premade Wave Stats Manager actor calls the different events in the music manager depending on if the player is in mid-transition of the round or has already begun the round.


Note: Additional documentation for the music system is currently a work in progress. There will be a dedicated design document explaining the system in depth.