Astral Plague 0 is the first iteration of a much larger project by the same name (without the 0). The project began in January 2024 as part of my Digital Media and Interaction class as Kennesaw State University. Our team was tasked with choosing a game and adding a twist to it. Our team opted to choose Sekiro: Shadows Die Twice with the twist of demaking it(ie. making it 2D with pixel art).
I was responsible for all of the game's design and implementation. I also acted as the team lead, organizing meetings, sending out deadlines, and ensuring our team had a coherent plan.
There is sound, I recommend it primarily for the second clip. The music on the left clip is from Elden Ring, can't take credit for that.
SoonTM
Coming off the back of working in Unreal Engine for the months leading up to this project, I wanted to challenge myself to make a bespoke ability system somewhat similar to Unreal Engine's Gameplay Ability System. There were two main reasons for this challenge:
One of the big reasons I wanted to do an ability system was for greater control over my entities states, as the Gameplay Tags system from Unreal Engine is brilliant. More soon!
I would be lying if I said this project wasn't full of hurdles and mistakes, because it was. I want to take a brief moment to point out some mistakes I made and how I would do better next time.
Early on when we decided to work on a demake of Sekiro we knew we wouldn't have time for many enemies, in fact we originally only planned to have a boss and a training dummy the player could practice on.
This was primarily for scope reasons but also because of time constraints -- we had a lot to make in a short amount of time.
While from a pure developmental perspective I think this worked out, the final product ended up being slightly stale as the player can breeze through the level without fully utilizing all their mechanics.
The most obvious example of this is the parry, our central mechanic. Aside from the boss, the other main enemy we developed was a floating eyeball that would periodically attack in a circle around itself.
It was simple to implement and gave us some content, but it wasn't fun. Simply put, the player never needed to parry this enemy.
This was exacerbated when we decided to create a second version of this enemy that was ranged... meaning you couldn't parry it at all. Sure you could block its attack, but it wouldn't actually make use of the enemy's posture bar.
This meant that the two main enemies both ignored the parry system almost entirely. So how did we end up here, well honestly it was partly my fault but also due to the number of animators we had. Our team was blessed with two talented animators who split the work.
Our first animator would work exclusively on the player, doing all the attack, walk, and jumping animation (as well as others). While our second animator would then work on the boss, and when she had time also try and get some enemies done.
What we needed was another animation, but we also needed better core designs for the two enemies we had. Simply put, the enemies we did make didn't cut it. They were cheaply made and we knew that. However, from a pure design POV I could've done more.
For one, the ranged enemy could have a deflection mechanic added. This would've allowed the player to not just parry its attacks, but also deflect them back towards the enemy. While this wouldn't have solved the overall engagement issue, it would've helped to a degree.
Second, we should've relied on our existing resources to create more enemies. Practically, this means recoloring the player model (or another's) to make another enemy with our existing animations. WE also could've tried to rely on outsourced animations from a marketplace, but that would've been questionable.
Left depicts the "Training Dummy" while right displays the ranged enemy.
Part of the theme of this class was that we would pick a game and add a twist to it and then our professor would do the same mid way through the semester. This is a great idea in concept, but given the already pressing time crunch things got dicey.
For our project we were given the twist "Mega Man", does that make sense to you? Well it didn't to our team until we decided to take it literally... make your game like Mega Man. Thankfully we had a MegaMan modder and expert on our team to help us out.
This lead us to the twist of giving the player three elements they could swap between: Fire, Ice, and Lightning. Each element had its own capabilities like fire dealing burn damage, ice dealing posture damage, and lightning adding a ranged attack on the tail end of your combo.
This was actually really cool and somewhat easy to implement as most of the elements worked within the Ability System I designed and were simply recolors of the base model (i.e. a blue sword)
Where we begin to encounter problems is in with the functionality. All three elements worked great implementation wise, but there was a clear winner in terms of strength: fire. The fire element offered significantly higher DPS than the other elements and somewhat trivialized combat.
I was able to solve this somewhat with some careful balancing, but the problem remains to an extent. The second issue arose as a result of not having a clear cut manner of activating these elements.
Originally the idea was that the player could parry X amount of times to unlock the element temporarily (i.e. 30s activation), but due to time constraints I was unable to do this. This mean that the player could freely, at any time, toggle between the three elements.
Now realize for a moment I said three elements, but there is actually four. The default attack is technically an "element", but it just doesn't have any buffs. This meant that the original attack combo was now completely useless.
The obvious solution to this is the implement the aforementioned system which further emphasizes the parry mechanic, but I think the problem goes further than that. I would probably argue that the ice element is by far the best designed, as it makes creative use of the posture system while not adding any significant overhead.
Compare this to the other two, fire and lightning, which arguably require specific scenarios to be useful (even though fire did the most damage). To make proper use of these elements we need a lot more content. But look, I don't want to keep saying "We had no time!" as that doesn't help anything.
With what we did have, what could I have done better?
Well for one, we should've only added ONE element and focused on its implementation. Like I mentioned I think ice was the best, so if we focus specifically on how the player can use that element we get a lot more bang for our buck.
For example, the player could've had a portion of the level where they needed to freeze a platform to reach a higher point or perhaps they need to slow down an enemy to escape, there is a lot we could do.
This also would've made for a more cohesive experience as the player would be forced to engage with our systems to a higher degree, instead of cycling through the elements at random.
I don't like Unity. That probably isn't a shock to hear in 2024 and beyond, but honestly they don't have enough native resources to make me regularly use their engine. It is somewhat strange too considering they are the go-to engine for 2D yet many of their tools don't work there, like NavMesh.
This is furthered when you consider they don't have a native behavior tree/Ai architecture system like Unreal has (two actually, BTs and StateTree). I don't want to complain though, so let's jump into the problems I encountered and how I fixed them.
First off, behavior trees. This was one of my biggest challenges as our game revolved around combat. We needed complex and interactive AI otherwise combat would cease to exist. To fix this I immediately launched into developing my own BT system.
At first I was planning to do it raw, go full c# with no visual interface, and this worked for a little while. However, as the complex of my AI spiked I needed something better to work with.
From there I turned to the glorious work of open source where I found a visual BT system for Unity, but it still needed work. While the system itself was fine, a lot of the nodes didn't work the way I needed them to so I had to do some overhauls to better support 2D NavMesh and attack combos.
None of what I did was fancy, but it got the job done. I was however very unsatisfied with how I ended up implementing states (i.e. attacking, dying, running) as they will sometimes break and cause the AI to stop moving.
The second major limitation was not having a NavMesh that natively worked in 2D. While I considered working with pathfinding algorithms like A*, that seemed like it would take time I didn't have. Once again I turned to the world of open source, but like last time I still had to make changes.
Namely, the 2D NavMesh system that I found didn't support "flying", or at least not in a way that made sense. In fact the 2D NavMesh I found wasn't even for side scrollers, it was for top down games. Through a series of not so pretty code tweaks and some finagling with game objects,
I managed to make a NavMesh that allowed for two distinct layers: ground and air. It might not seem complex... but it was challenging to get working in 2D.