Log 16: Back From Break
- Kassandra McCormack
- Jan 28, 2024
- 6 min read
Oh boy, relaxing and not working is hard work. Although I'm glad to be back to work on my game, so I suppose it worked.
The first thing I did was re-design some mechanics. Specifically how activating Overpowered works, and how extra health works.
It all started because I didn't like how in order to activate extra health as a result of hitting all the morphing QTEs I would have to give the player a full-heal no matter how badly damaged they were at the start. I want Overpowered to be a fun tool that makes the player feel (as the name implies) over-powered, what I don't want is to inspire reckless gameplay and using Overpowered as a crutch and an essentially free full-heal. So I split the extra health into its own variable again, which required re-working the damage animation algorithm, but I'll get to that later. But, then I realized that originally the player could activate Overpowered by either getting all the QTEs during the morphing sequence, or activating all their items and then healing. Because the items could be used at any time, I was essentially allowing players a free full-heal and power enhancement, when I wanted it to be a special once a level event, or a clutch moment in case they are in a difficult fight and get de-morphed and have to morph again (at present de-morphing isn't possible, but I am planning on adding it). So now Overpowered can only be activated by getting all the morphing QTEs. While this might encourage players to hold off morphing as long as possible, or save it for the boss fight, that will need field testing in order to know for sure. And if it does, then I just need to increase the already considerable pressure to morph earlier (no access to special abilities, mounts, ultimate attacks, lower attack and defenses, etc.).
So that was the Overpowered re-work, the health re-work was (as I said) splitting health and extra health to different variables, so that the extra health acts more like a shield that can be overlaid on any health value. This way players get a little more breathing room if they're low on health, but not enough to fully dissolve all tension that comes from being low health. Of course this, unlike Overpowered which only required I unhook a function call, required serious re-work on how my health system works. Specifically, how the damage animation algorithm works (as you can't heal extra health): I now had to balance 2 numbers that (because I want there to be rollover damage if it is higher than remaining extra health) can change at different stages anywhere on a single curve (in order for the animation to appear smooth and continuous).
It took me a couple days to figure out how to do it because initially I had wanted to calculate percentages of total damage and then use that to split the animation curve at an arbitrary point and use those split curves in separate timelines, but you can't do that in Blueprints (or if you can, I found nothing about it online), so I had to figure it out mathematically.
Initially I thought I was going to have to calculate damage percentages and either multiply or subtract them from a new second linear alpha value, and somehow translate that into the position on the initial easing alpha curve. But that wound up being a dead end and a headache. Fortunately I was well(-ish) rested. Eventually I figured out that I didn't need percentages (at least not how I was using them) or second timeline values. What I did was take the total change multiplied by the alpha value from the timeline curve, this would give me a smooth transition over the entire curve. Then I subtracted from that the projected change in regular health in order to get the amount that extra health would be changing, divided by the change in extra health in order to get a new alpha value (clamped between 0 and 1) to re-multiply by the change in extra health. That might seem a waste to divide then multiply by the same number, but the trick is in the clamping. By clamping the value to a range of 0 - 1, when the extra health runs out it won't dip into the negatives (thus multiplying by a negative change amount, increasing the extra health rather than leaving it at 0). For the alpha for the regular health, I just divide the total change by the projected change in health and clamp that between 0 and 1, then re-multiplying by the projected change in health, this way before the rollover point I'll still only get an alpha of 1, but after that point it will start decreasing steadily to 0.
Yay I solved it! All by myself, no online research required.
Except that I noticed a graphical bug with the health bar animation, getting damaged the animation was taking far less than the prescribed 1 second. It turns out I was accidentally compounding my math by setting new values to the predicted values, thus the next frame the predicted values were now less and then a larger value subtracted from them and so on and so on. This was easily remedied by not setting the new values and instead simply passing the calculations directly into the dispatcher call and leaving the values as is. So now instead of (with numbers simplified for example): 3000 - 100 = 2900, then 2900 - 200 = 2700; I would have 3000 - 100 = 2900, then 3000 - 200 = 2800, etc. Now the only reason the animation is jumpy is because I'm not a good enough artist to make the grayscale on the graphic smooth enough.

The next thing I did was to continue working on the Overpower buff, after considering its re-design.
Setting up a function to activate the Extra Health, the timer, and the lightning aura particle effect was easy enough. I had to develop an altered form of my stat timer macro to allow for multiple stat changes at once on a single time, but that was more or less a couple foreach loops to cycle through the stats. The hardest part was the fact that Overpowered gives infinite Musou usage by reducing all costs to 0. And figuring out how to do that while it proved easier than initially feared, it also uncovered a couple pieces of broken code.
Making all Musou costs be nothing wound up being easy because I already have a function on the Stats Controller that anything wanting to cost Musou has to call; So I put in a branch that if the character is Overpowered, to ignore the passed in cost and just subtract 0 from the Musou. The broken code I uncovered, however, is that in some of the places that I called this function from, specifically the Power Attacks, I don't check to see if the character has enough Musou for the attack, meaning it is possible for the character to infinitely spam Power Attacks while their Musou goes into the negatives. Obviously not what I want so I had to create a new check function to put in place earlier in the Power Attack code.
The last thing I worked on (before testing everything and fixing what inevitably broke) was the deactivation of the Overpower state. Specifically in two ways: the first and easiest was based on the timer macro I had set up previously, the second was if the player loses all their extra health. I had to add a couple extra checks into the Decrease Health Event, so if the extra health previously exists and then goes to 0 it calls a function that I leave blank in the Basic Character, but that I overrode and filled in the functionality in the Playable Character. All it had to do is get rid of the extra health remaining (in case the power up expired from the timer), canceled the timer (in case the power up expired from the health), disabled the infinite Musou in the Stats Controller, and disabled the aura particles. To the disabling of the aura particles I added a bit of juice and had them actually disperse out when deactivated.
The burst of the electric particles took some work. Initially I created a float user parameter in the Niagara system that controlled whether the death event would trigger, then before I deactivate the system (killing the emitter and particles) I set the event to trigger with a probability of 1. This, of course, didn't work as when I deactivate the system, it deactivates both emitters simultaneously, and without the burst emitter being active it won't burst. So, I have to leave the system active at the same time as I "deactivate" it. Something I learned is possible is to create a custom float from a bool parameter. This is helpful because by setting both the electric aura to have a probability of 0 or 1 based on a bool parameter (false and true, respectively), I then set the "Generate Death Event" probability to be the opposite. This way I can have the particle system be always "Active" but until I turn on the bool new particles won't spawn, and when I turn off the bool the particles already there will run out their lives and when they die (which is fairly quickly) they burst.

Comments