Splitter
Karl-Walter Sillaots
Project Site
https://github.com/K-WS/Splitter
Project Build
Old Version
https://drive.google.com/file/d/1TqsbLghVHZVFChG-p0iql7p_fQmpBLiU/view?usp=sharing
Newer Version
https://drive.google.com/file/d/104WeQ4JBE60POuuJDC_mv5CgAkoQZCxz/view?usp=sharing
Project Video
https://drive.google.com/file/d/1d0uJ-5RBm-8dKUXY7tej5YH1TTZHca_d/view?usp=sharing
Project Idea (show)
For over a decade I have had a particular idea to create a turn-based RPG into a full game. Over time, the concepts on how it works have warped, until I finally concluded it into 2 key game mechanics. During this project, my plan is to realize one of these into a functional game prototype (in Unity).
Throughout many RPG games, there are allies that the main character can team up with to generally be more powerful, and in normal circumstances, the player is always encouraged to have as many teammates as possible at all times. The less there are available, the more disadvantageous for the player.
What I want to do is turn the idea itself into a double-edged sword: for there to be both advantages and disadvantages when you are solo or teamed up.
This brings the first half of the first game mechanic - calling on teammates during battle.
The player initially starts off alone, but can spend a turn to get additional help. However, I do not want it to just be that, oh no, that is just teammates with extra steps. There needs to be a penalty for doing so.
The second half of the first game mechanic - all teammates are part of the same character and calling on them requires your health to be partially sacrificed for them to be called, hence "splitting".
Splitting causes life to be reduced by a set percentage. Due to the many ways lost HP could be split as a consequence, I have decided to focus on one particular state, a 30/30/40 percent split (the image has it the other way), so that the split character always starts off with full health. If the main character has lost 40% of their health, they can not spawn a third helper without killing themself and can not spawn anyone at 70% lost.
If a split character dies, their body should not immediately return to the player, that would reduce risk, encouraging the player to take brute force strategies with teammates, healing once both have automatically returned to the player. Instead, a standard reviving system should be in place, either with the main character dying causing an instant game over and only them having revive access, or everyone having it and losing the ability to recombine/split when the main character has fallen.
Debuffs and buffs should have a stacking effect when an afflicted teammate recombines with the player, and could also include a small multiplier to make the player think carefully, if it is beneficial or too dangerous to recombine. However, splitting would not cause any any buffs or debuffs to carry over either, to keep a clean slate. There should also at the very least be a cap on how high the percentage can go, or a decaying effect on both buffs/debuffs, so the player could not just abuse the buffing part of the mechanics.
I am also considering if having any AoE healing effects would be a smart idea, or if they should be expensive and much less effective than regular healing.
Speaking of, there is usually a mana/energy system in RPG's as well. I have thought about the main character being able to constantly recover energy every turn as well, but not with the split characters, however this is not that big of a focus for the project right now.
Finally, in regards to abilities. By default, the main character could have a very limited number of abilities available from all other characters, but have to activate a subcharacters "form" to get access to that specific full set of moves, while not being able to use any moves from a split subcharacter.
(Oh, and if anyone here is thinking that enemies could easily cause high damage that instantly kills split characters, but would not do so on a unsplit main character, that is an intentional feature where certain key issues would be addressed by the second game mechanic.)
What should be done?
- Overworld
- A simple overworld (a box) that the player can traverse on, and an enemy to transition into the battle mode
- A player character that can move around in the overworld and can be used during combat
- An enemy model in the overworld, that causes combat when interacted (collided?) with.
- Combat
- An enemy script that contains all the basic code required to make sub-enemies out of.
- One aspect here is deciding if the enemy chooses their next attack randomly, semi-randomly or in a predetermined unalterable pattern.
- A turn-based mechanic to decide who goes when (speed stat? Perhaps combined with a cost penalty for each move)
- The ability to choose an attack and perform it, see any turn-based RPG system
- The main mechanic (splitting) available as an option to perform
- Possibly the exponential effect of combining buffs/debuffs?
- The ability mechanic, where the main character has to pick a subcharacter to use their full list of moves, but can not use any of split character moves.
- In order to properly start using the mechanic, there should be 3 splittable subcharacters by default
- Since this is still a CG course, some form of graphical presentation should be available for the characters, but I am not sure how much time I can put on this, especially considering that the previous year It took two thirds of the course to create 1 model with animations.
- An enemy script that contains all the basic code required to make sub-enemies out of.
- Other
- Preservation of world data when entering/exiting combat.
Milestone 1 (25.09) (show)
- Initialization, a very basic overworld with player and enemy character
- Time taken - ~2h.
- Depending on how much time there is over, start with setting up the combat scenario as well, UI, turn-based system, simple attack command, enemy code etc.
- Also figure out a method to efficiently transition from a world view to the battle view.
- Time taken, the rest of 5h and was only partially finished.
Summary
Building up the basic overworld went quickly. Creating a simple movement script for a controllable cylinder was simple enough, and adding colliders on both the player and enemy does not take particularly long either. Scripts for collision were also created so that it would be possible to creation a transition to the battle mode.
Going on from here was difficult though. I initially asked for advice from certain people on how to properly set up a transition from one screen to another, and while I got good advice, I would not have been able to implement it quickly enough without experience. So instead I relied on a website that gave a simple idea on how to set up a turn-based RPG. The transition suggested there is not the most efficient solution, but can be dealt with after the end of this course.
What I did end up finishing was a simple view on what the battle mode could look like in a separate Unity scene, some statistics that could be carried over from scene to scene for both the player and enemy, some parts of the code to transition. The focus for the next milestone would be to finish all shortcomings between the transition and complete the tutorial.
Milestone 2 (09.10) (show)
- Complete the basic scenario, this includes:
- Completing the transition to battle mode
- Time taken ~1h, left out the animation for now, done with Coroutine
- Creating the UI elements for battle mode
- ~3h
- Some form of basic combat implementation
- ~3.5h
- Completing the transition to battle mode
- Backup if the first part is completed early, try to put multiple controllable characters simultaneously
Summary
The tutorial lied.
What Happened?
Creating UI elements was not a particularly big issue, and it should not be either. The high amount of time on it is because it was worked on in tandem with the game logic, so it is not quite clear how much time either part took.
The game logic directly should not be an issue either. In battle, apart from some waiting moments (for figurative animations), both the enemy and player lose HP on their respective ScriptableObjects which persists even when the game is closed. The basic attack takes off 10HP for now, and the enemy takes off 10HP. every time damage is taken, instead of instantly moving the HP bar, it smoothly moves over to its new position.
As for the multiple players part, some minor things were added, like how their statistics should be accessed on the UI and where they should be positioned, but not much work was done for it.
The main issue is the transition.
The Transition
Now, it technically does work, but there is a core issue present with it that the tutorial I was following did not address - How are the player and enemy battle gameobjects fetched after a scene is loaded?
There was never any form of mention if the player/enemy gameobjects should have a DontDestroyOnLoad() Unity command on them to prevent them from being destroyed, or if it is supposed to have a multi-scene setup where the old scene is disabled rather than destroyed on loading a new scene.
The result is that loading in gameobjects from the original models in the old scene does not work. For now, I have simply disabled that part of the code and made placeholder models in the battle scene.
Another issue is that, in theory, the ScriptableObjects that each GO should refer to have a field for their battle GO as well, to fetch animations from. This does not work correctly either. I will have to address this eventually if I want to implement animations, but for now, since the main combat loop works, I want to focus more on refactoring the code there to actually function more like a turn-based RPG.
Milestone 3 (23.10) (show)
- Speed Stat - Implement the speed statistic to make decisions on who goes next, instead of simply swapping turns.
- ATK/DEF Stats - Some kind of attack/defense statistics and damage calculation for variety.
- Multi-Character Support - Figure out how to make ScriptableObjects in such a way that multiple playable characters can be supported.
- One idea is to precreate a ScriptableObject for each character beforehand, with only the max and current health being modifiable based on how much health the main character has.
- Post-Battle Bug Prevention - By extension, also make sure that post-battle, both max and current health of all characters is recombined with the main character, so that it would not be permanently lost.
- Splitting - Mainly, start working on the splitting mechanic.
- Optionally, depending on time, figure out ways to fix transition issues.
Time Taken
- Refactoring code and HUD
- 3h
- Post-Battle Bug Prevention - Done, needs testing (split implementation)
- 5m
- ATK/DEF Stats - Done, should be working.
- 30m
- Speed Stat - Worked on, should be finished.
- 3h
- ScriptableObjects - 1h, although not fully realized, a lot of code was refactored to accommodate multiple players.
Summary
Post-Battle
There is not particularly much to comment on. While it still needs testing, it is just a simple check to see if players 2 and 3 exist and if they do, take away their max and current HP values to give them to the main player once the fight has entered the "END" state.
ATK/DEF Stats
For now, this has only been applied to the player. A simple algorithm was created where ATK obviously acts as the base damage, with a little bit of randomness applied on, while the DEF of the enemy reduces it through a division (after being turned into a smaller value to prevent situations where you do 1 damage with regular stats).
Speed Stat
This was the most complicated part of the entire milestone. What I wanted was a speed stat that would act as a form of buffer. If one character has a higher stat than everyone else, then eventually, they will get an additional turn over them.
My solution to this was a state queue. The priority order in the case of equal speeds is Player 1, P2, P3, Enemy 1, ...
Whenever the queue is not empty, the game knows who goes next, just dequeue the next element. Otherwise all characters are looped through.
The first check is to determine who is eligible to go. For this, there is an additional speed buffer variable (currSPD) that initially is equal to speed. Every character whose currSPD >= speed is kept, while non-eligibles are put into another list for a separate case.
After this, if someone is eligible, their list is sorted based on their buffer values, so that the person with the highest buffer would go first. The smallest buffer is taken to loop through each eligible character, who gets their battlestate added into the queue and their buffer reduced by the smallest buffer. The game now knows who goes next.
If no one is eligible, the separate list where everyone is stored is passed, with their buffer being increased by their speed. The algorithm is called again to update the queue.
Bugs fixed
One of the main issues was HP values not being correctly represented on their respective bar, breaking rather quickly...
Other
- Multiple ScriptableObjects for splittable characters were created, with a public list in the Battle Manager holding them all in for now, although that could be done better.
- HP loss and gain code was modified to also ask for the player who got hit, which is cross-checked in a switch case to determine which HP bar should be losing/gaining in value.
- Additional buttons that become visible/invisible, depending on whose turn it is. The main character can split, the split characters can return back. (MC should probably also be able to call back themselves, but skipping that for now)
Milestone 4 (06.11) (show)
- Complete splitting mechanic
- If there is time left, start working on abilities for each split type. They do not have to necessarily be anything special, simply removing a set amount of HP or giving HP is fine for now.
- Possibly show that energy lost so that it is showable that it works.
Time Taken
7h of refactoring, adding code and components to make sure that splitting would be functional
Summary
The core goal was to fully implement splitting. I think the goal has been accomplished, but with some issues that I am not satisfied with.
Demonstration of splitting on an earlier build.
The video clearly shows that the system appears to be functional. New characters are splittable, HP is altered on split and recombination, splitting when 30% of filled HP is available on the main character, not allowing splitted characters to be resplit again, health being recombined post battle and so on.
There are several issues that bother me with this though:
1) The way it was implemented. Because of time constraints and issues with figuring out bugs, the quickest solution I found was a text box where the splittable character name is written in. What I would have preferred is either a list of selectable buttons or a wheel of buttons. Both methods would have required a lot of time figuring out and implementing an UI that supports such a thing.
2) Code. The code has become relatively unwieldy at this point and certain optimization ideas that I wanted to implement did not work. It appears that passing a reference to a function does not actually modify the original itself, causing me to have to write repeats of code and many if/switch statements. I would want to figure out a way to fix this, but again, time constraints.
3) Split characters do not have a death condition right now, and enemies do not attack them. The latter part is easy enough to fix, but I would need to figure out a way to add a "defeated" condition that allows split characters to continue existing, but need to be recovered so that they could continue using turns or returning to the player.
4) I still did not have time to verify if turn assignment is working as intended. Every character does get turns, but it feels like the ordering is wrong or does not apply an extra turn at a point where it should, although it eventually will do so.
Milestone 5 (20.11) (show)
- Figure out a way to implement abilities for characters and try doing it.
- Visualize the turn queue.
- If time over, the final goal would be to implement fusing, or giving the main character abilities from another character.
Time Taken
Around 8-10 hours.
Summary
I was right on the turn ordering having a bug. The issue is that the split character does not have their speed zeroed out when spawned, causing them to get an extra free turn before everyone gets reset.
In other parts, I generally managed to complete all of my required goals, but as usual, it required a considerable amount of refactoring to work.
Implementing Abilities
One ability has been created for each character. They are rather basic "use energy to deal more damage" types of moves, but otherwise show how the energy bars work and how abilities can not be used if there is not enough energy left. A second button for each character has been added as a more unique ability, but their implementations are something I am planning for the final milestone.
Turn Queue Visualization
An additional panel has now been added to visualize the turn turn queue cycle that is updated whenever the queue has run out of BattleState enums to use. The colors of all circles represent the the cylinder, with red being the enemy, the rest of the colors the playable characters.
Milestone 6 (04.12)
- Finish fusing, which in this case simply replaces the default character abilities (But not stats!)
- Finish the second ability for each character
- Healing - The main character can recover the HP for other characters
- Stagger - If Ice goes before the enemy, they can "stagger" and remove their turn for the current order
- ATK Up - Arcane can buff themself to temporarily deal more damage
- Flame - Fire can attack the enemy in such a way that causes damage over time for some amount of time.
- Make other characters attackable and have a "defeated" state for them
- Add some form of object moving from 1 character to the enemy to better visualize who is attacking who
- UI updates
- Make an UI update so that the user can visually see how much damage is done after an attack, not just updating the HP bar
- In the case of the damage-over-time effect for fire, some form of visualization that the enemy is afflicted by it.
- For ATK Up with Arcane, some visualization to show that they currently have the buff active
- Give additional text for the turn queue to simply display which turn it is currently
Time Taken
Around 11+ hours
Summary
Project Build has been updated. Project Video at the beginning has been updated to include the following video as a demonstration:
https://drive.google.com/file/d/1d0uJ-5RBm-8dKUXY7tej5YH1TTZHca_d/view?usp=sharing
Fusing
Is now fully operational, although not completely in the way I intended. Fusing into another character replaces the default moves with the splittable character ones. The original intent was to have them added on top of the default moves, but that is likely something to be refactored in outside of the project.
Second Abilities
- The main character can now perform a 100HP heal on any playable character currently on the field, regardless if they are alive or defeated. The amount was intentionally chosen since a lot of it would go to waste when split, encouragin re-fusing for healing.
- Stagger causes any targeted enemy turns to disappear from the queue. It does not do any damage though, so it will go to waste if no enemy comes after Ice.
- ATK Up gives +20 attack to the caster. Each time their turn begins, they lose 5 points of attack, until it is back to 0, so they get 3 turns of a weakening damage boost.
- Flame does not do any damage on its own, but will cause the enemy to lose 15HP for 3 turns, totalling at 45 damage.
Defeated Status
This is the only thing not shown in the end video, but if a split character loses all their health, they fall down and will no longer have any turns until healed. For now, the healing ability on the main character doubles as a heal and reviver.
An important note is that this only applies for split characters. If the main character falls, the battle is immediately lost.
Attacking
Whenever any attack or enemy aiming ability is used, a ball will fly from the person attacking to the target.
UI
- Damage is now visualized, showing exactly how much damage each attack has done.
- The damage-over-time effect of Flame is visualized by an icon.
- Same thing for ATK Up.
- Finally, whenever the turn queue is refreshed, regardless of how many characters are added in there, the turn goes up by 1.
Post-Milestones
- Consider adding the exponentiality effect, where the main character retains any and all buffs/debuffs from recombining allies with a small boost
- I have not checked if there are any bugs with flame, specifically if the enemy dies from it. I also have not enabled DoT effects for playable characters right now
- Make the enemy an actual threat. Right now it only does a random amount of damage between 15 and 20 per turn. Maybe give it some of the player abilities to use?
- Or give an AoE ability that can randomly trigger if there is more than 1 player on the field?