Today I’m going talk about a few technical aspects of my game, including the battle system and how the game stores data, both of which turned out to take a lot more thinking and programming that I had initially thought.
Battle Basics
At the core, my battle system is quite simple; it is turn-based, and the player chooses what each of their characters does in each turn. When I first tried to make the battle system, I had planned to make it so that the player would be on their own battling up to three enemies. However, after finishing this, I wanted to add allies to help the player, so I then decided to go with a grid-based battle system.
There are six potential locations for the allies and six potential locations for the enemies, with 12 potential locations in total. Different locations may give different bonuses, and the player can move the characters around during battle to use the bonus to their advantage.
During an attach, the characters’ attributes are used to calculate the results. The basic attributes are health, mana, strength, defense, and agility. Although these attribute names will probably be renamed to fit the theme of my game better (such as “mana” to “battery”), the basic idea is that these attributes will be used to calculate battle logistics such as who attacks first or how the damage is calculated.
Refactoring Code
There were two major points in which I had to rethink my battle system, largely due to my lack of preplanning.
The first point came when I decided to add allies. When I first made the battle system, there was only one player battling a few enemies. However, after finding this too boring, I created an “Ally” class alongside my “Player” class. Since I first created the “Player” class without planning to create an “Ally” class, the two ended up completely separate and independent from each other, despite having many similarities. For instance, both allies and players have the same attributes such as health and mana. They both level up in the same way and accesses the same set of skills. Thus, this separation of “Ally” and “Player” soon became very confusing and counterintuitive to work with.
My first problem with this was the nomenclature. By having “Ally” and “Player” separate, it is implied that the player isn’t an ally (when in fact, it is). Naming variables and functions can be surprisingly difficult but it is also very important for being able to understand the code a few weeks down the line. This may not seem like a big deal, but it slowed down my progress a lot.
One example of my terrible sense of naming is “totalAlly,” which counts the number of allies PLUS the player, while the name may lead one to think that is just counts the number of allies. This inconsistency is part of the reason why I decided to spend a bit of time cleaning up my code.
The second turning point came when I realized that the “Ally” class and “Enemy” class were very similar as well. Continuing with this trend of cleaning up my code, I decided to completely refactor (restructure) my code. Since “Ally,” “Enemy,” and “Player” are all so similar, I created a class named “Character” which all three inherit from. Below is a graphical representation of how my classes changed throughout the development of the battle system.
Text Files
All the enemies in my game were initially stored in a text file. The text file is nothing complicated, and there’s no code in there—it’s essentially just a database with keywords and values which are transferred over to the game.
The text file corresponds to each map in the game, meaning whenever the player is in a different map, they are subjected to a different set of enemies. Thus, whenever the player goes to a different map, the program deletes all the old enemy data and creates new enemies based on the new data. When a battle is encountered, this enemy data is then copied over to the “Battle” class instance. During the battle, any changes to the enemy such as damage or buffs/debuffs only applies to the copy of the enemy, not the enemy that was initially loaded in for the map. After the battle is over, the “Battle” instance is completely reset so the altered enemy is completely gone, leaving me with only the original enemy data.
Like enemies, the ally information are all stored in a text file as well, with the program only being coded to interpret the text files. However, since allies persist throughout the game and don’t change based on the map, it is simply loaded in at the beginning of the game and stays there.
Skills
Skills are also stored in text files containing data such as “mult” for multiplier, “max” for maximum damage possible, “min” for minimum damage possible, etc. At one point or another, the game will load in data for the skill which each character has access to. Whenever one is in battle, the “Skill” instance would calculate how much the skill should damage/heal/buff/debuff.
When I was first creating skills, I had initially planned for each character to have a vector (list) of skills. However, I thought that it might be easier to have a centralized list of skills, and the characters would only hold data about which skill to access via the skill ID. Since each skill would already be loaded in the list from the beginning of the game, it would be easy to swap out one skill for another because the character only needs to store a different integer (skill ID), whereas my initial plan required the program to open up a text file and load in the skill data which takes significantly more time.
Conclusion
Although I’ve tried to optimize my game, there are still many areas that are unoptimized, both in terms of speed as well as memory usage. However, with a lot of the technical aspects of the game being completed, I have also started to work on many more of the artistic and creative elements of the game, such as story writing and character creation (which I’ve already shown a glimpse of in my previous post). I’ll be continuing these posts over the summer, so stay tuned!