Thursday, December 24, 2015

Battle System Updates (Part Two)

One of the main problems with the previous battle system (henceforth, lovingly referred to as BS-1) was that, while the system itself functioned properly, the presentation was somewhat lacking. In this post, I'm going to talk a little about the specific issues with it as well as the steps we went through to correct those issues. Afterwards, there will be a few screenshots showing the improvements. If this sounds boring, that's because it actually is. Anyhow, ze issues, in order of severity:


  1. Character panels were arranged horizontally, rather than vertically. Since each panel requires roughly 200 pixels to display all of the information, this effectively locks out people with certain screen resolutions. Granted, the panels did scale based on the chosen resolution, but this still works out to allowing something like six total combatants on screen for lower screen widths. This is why, during the demo, there were no situations in which enemy groups greater than three would be encountered. This would obviously cause issues, too, if (or when) we decide to bump the minimum party up to four.
  2. Vertical space was wasted by needing to show the actual charge counters of any currently charging skills. To recap, skills in Bevontule require a certain number of 'turns' (or charges) before they can execute. This was shown, in battle, with small...uh.. orbs that gradually filled as combat turns proceeded. This, of course, is a necessary thing to show, but surely, there is a more intuitive way to depict this... (spoiler: there is)
  3. The order of turns was completely fixed and determined at the beginning of battle based on each character's speed attribute. This meant that any skills that modified a character's speed attribute in combat would have no effect. This is an obvious problem since it would exclude any haste-type buffs or slowing debuffs.
  4. It was extremely difficult to follow the flow of battle--even though there were rules for which character would act next (for instance, if two characters reach full charge on the same turn, the character that entered the skill first would act, aka, in a left-to-right order). From the perspective of the player though, the currently acting character would seem to shift around without any explicit reasoning to it. 
  5. Minor complaint, but if a character performed an action other than a skill (such as moving or attacking), this was not reflected anywhere in the status panel. This was a surprisingly difficult thing to fix with the old system.
  6. Another minor complaint, is that the code was too tightly coupled with the battle system itself. I mean, yeah, it only is visible during battle, but that's no real excuse. 
  7. Shifting the status panels relied on Unity's animation system. I have learned to never again trust this son of a bitch. I could write an entire blog post about how incredibly flawed some aspects of this are, but that would be extremely boring (but very therapeutic.) Going forward, ideally, we would not rely on this system to handle the rearranging of combatant panels.

While this doesn't really seem like a large number of problems, fixing each of them required a pretty stupid amount of work. So, here is another list of the fixes that were applied:

  1. Rearrange character panels vertically on the right side of the screen, while reducing the overall vertical size of an individual panel. The horizontal size, ideally, would remain the same, but we could get away with increasing this if necessary.
  2. Remove the orbs and rely instead on a more intuitive method to show the currently charging skills as well as the turn(s) at which they would execute. This was the truly major overhaul and required rewriting massive portions of the battle system. Essentially, the idea is to actually slot in characters based on the total charge required by any particular skill. Each turn, every character is shifted upwards, thus replacing the system of updating the orb graphics. When a character reaches the top of the turn order, they would act. Contrast this with every character remaining in a fixed location and shifting the entire character bar, as was done previously. In practice, this sounds extremely straightforward, but like everything, the devil is in the details. This system would also need to account for skills that require zero charge (instants, much like attacking or using an item) and would also need to account for skills that require a charge higher than the number of currently displayed character panels, which is dependent on the number of currently 'alive' combatants. Furthermore, it would need to preserve the relative turn order for non-skill-charging characters. One way to think of it is that characters that are not charging skills are actually sorted based on their accumulated speed (more on that later), but characters that are charging skills are slotted in at very specific indices within the turn order list. To add a little more confusion, it also needs to account for character speeds. For example, what I said earlier about every character shifting up by one slot every turn is actually wrong and I am a lying bastard. It turns out that, if a character has sufficiently high speed, it can slot in ahead of 'slower' characters. Still, all of this must still happen without the turn order of actual charging skills being affected. Thus, if a skill has a charge of 1 turn, it cannot possibly take more than one turn to act (the exception being, if a 1 turn skill is already slotted ahead of it). Add all this together and you have a pretty big mess, which unfortunately, despite repeated attempts (and other blasphemous statements), took quite a while to untangle.
  3. To elaborate further on this, speed now correctly factors into the turn order. Ignoring any character skill charging, the idea is pretty basic. Every character has a speed stat (a persistent character attribute) and an accumulated speed stat (only used during battle). At the beginning of battle, every character's accumulated speed is set to its actual speed stat, which is then sorted in descending order to generate the initial turn ordering. When a character completes his turn, the accumulated speed is reset to zero, which essentially forces them to the end of the turn order when it is resorted. Otherwise, the accumulated speed attribute is incremented by the character's speed attribute. With this system in place, characters can then overtake other characters if their speed is sufficiently high. An issue arises naturally from this... since it is no longer guaranteed that a character will only move one slot, it becomes necessary to somehow communicate the next turn ordering to the player, ideally, without using additional space. Which leads into...
  4. The next turn ordering is actually shown when a character attempts to perform an action that would end his or her turn, but before the character has actually confirmed the action. To recap, certain actions can end turns, whereas other ones allow still other actions to be performed in the same turn. Here is a list of actions that a character could take in a single turn:
    1. Moving, then attacking
    2. Attacking, then moving
    3. Moving, then using an item
    4. Using an item, then moving
    5. Moving, then using a skill of any charge
    6. Using a skill with a charge of zero (an instant), then moving
    7. Ending the turn explicitly (now requires a confirmation press to allow the next turn order to be displayed. Also, this is probably a good thing anyhow to prevent a player from making a mistake)
  5. Fixed. Moving on... 
  6. Also fixed (for the most part). Just to elaborate, previously, the character bar ran its own update loop independent of the BattleManager (main class for handling battle-related tasks, go figure). This was a gd nightmare. Never again. This also means that the character bar is not updated each frame as it was before (ew), but now is only updated when specific conditions are met.
  7. I won't lie, I tried to implement the shifting (actual physical positioning of panels) via Animations, despite being burned by it in the past. This time, I vowed, it would be different and I would tame this stupid bastard. I didn't. First issue: you CANNOT animate integer values. Why the shit not. Second issue: animation updates do not seem to occur in tandem with any reasonable update loop (wtf?) Third issue: animations did not seem to honor the ending keyframe whatsoever. For instance, I want a value to go from 100 to 0 over the course of 1 second. Lo and behold, at the end of that second, the value would be 3 or some such stupid shit. Why, god, why. So yeah... this has all been fixed. 
So, if you were somehow able to get through that massive wall of text, here are a few (by few, I mean 12) images that show off the new and improved battle system (I am calling this iteration BS-2-Fast-2-Furious.) 


First picture: Moroch is the currently acting character. The new turn order bar is displayed on the right.


Second picture: Moroch chooses to use Siphon (for whatever reason). Note that the turn bar updates to show Moroch's new position in the list before the action is confirmed. Since it has a charge of 3, he gets slotted in at, you guessed it, position 3. Keep in mind that these are 0-based indices, which is necessary because a skill with a charge of 1 would then be slotted in at the very top, which is something we want to avoid. (Also ignore the obscenely and unnecessarily long information bar)


Third picture: Apolith is the currently acting character. Note that the new turn order was 'locked in' once Moroch confirmed the command. Currently charging skills are indicated with a blueish tint. Additionally, the name of the skill appears below his panel.


Fourth picture: Since Apolith's judgment is somewhat clouded due to all of the steroids he uses, he contemplates using Resolve for a moment. Again, the next turn order is shown, and Apolith is slotted in an index 1, whereas Moroch has moved up to index 2.


Fifth picture: ...But since he's all roided out and shit, he decides that violence is the only acceptable course of action, so he chooses to Bludgeon the nice little plant instead. Charge time of 3, index 3. Checks out. Something interesting to note: If he had a skill that had a charge time of 2, he would still be slotted in at the same spot as if he had chosen Bludgeon. This is because characters cannot 'interrupt' other characters if they are slotted in at the same position. Thus, the person who selects a skill first still gets to act first. In this case, then, a charge time of 2 and a charge time of 3 have the same result. 


Sixth picture: Not to be outdone by Apolith's blatant disregard for the sanctity of life, Bodom chooses Backstab. It has a charge of 3, and gets slotted in at the end. Note that in this particular case, a skill with a charge of 1, 2 AND 3 would produce the same result. Interestingly, this opens up the possibility that a system could be added where skills can be 'overcharged'. 


Seventh picture: Skipping ahead a little, plant bro lashes out at Apolith and breaks his neck, by the looks of it, but still only does a small amount of damage, so he's fine. You can't tell from the picture really, but Apolith's character panel is flashing red to indicate that he is currently taking damage. Also note that since an attack without movement doesn't end a character's turn, the 'next' turn order is not yet shown. 


Eighth picture: Plant bro decides to end his turn because he's a plant and can't move. JK, he can totally move, but it would screw everything up. Note that he has been shifted to the end of the turn order upon selecting End Turn.


Ninth picture: Moroch uses Siphon. Even though it is not explicitly shown, any character who performs a skill is automatically slotted at the end of the turn order after the skill executes (aka, his accumulated speed is set to zero)


Tenth picture: Apolith uses Bludgeon. 


Eleventh picture: Bodom uses Backstab. Don't look at Apolith's face. He uh... had an accident.



Twelfth picture: Just like World War I, everyone decides to stop fighting for a bit and put aside their differences. It is a magical time indeed, when Humans, Onichians, Rootsouls, birds and plants can all come together to appreciate the joy of Christmas.