Tactical RPG Prototype. Design and Postmortem.
The Tactical RPG genre, grid and distance based, is one that I always have a blast playing so I thought to myself, “Why not try and make my own, and learn some things along the way.” And boy did I learn a thing or two.
So for my first attempt I thought I would try my hand at rewiring my brain around data and not being able to physically see it. In Unity, I have mostly just done things through the inspector, serializing variable, putting on tooltips and headers to organize, and doing some minimal editor scripts to make things readable. So with this project, at least in the beginning, I wanted to see if I could wrap my head around data that I wouldn’t be able to see in the inspector, rather in the world itself. To populate a scene just by grabbing assets, buttons, and texts through code instead of drag and dropping them into the inspector. And honestly it was an interesting experience to learn that I had a decent grasp of folder structure and world space inside of Unity with C#. I’ll get more into that later.
How It Began
I started this project about July of 2019, I moved to San Francisco to live with a buddy who already had a job in the mobile games industry. I moved out there, set up my laptop and put out a bunch of job applications all over the place. So I started this project to keep me busy and my skills fresh. I set some base goals:
- 3 different classes that players could choose from
- Movement and Combat happening in one turn per character on the field
- A grid with hazards or different types of terrain.
And while I didn’t know how I was gonna do all of that I was definitely driven to learn.
So about a week after moving I got a job working overnight(10pm-6am) shift at Target. Working there, trying to pay rent, trying to get an Industry job, and work on my projects was rough. I got no sunlight, slept through the hours that my friends were actually awake, and was too exhausted to even talk to my family when they called. So I quit around November, and my friend was kind enough to spot me rent money for a month or two until I got another job. In that time I visited family, got my mental health up and worked more on this project.
So I watched videos on design patterns and data structures and kind of figured out how I could set up my grid. It made sense to me with my knowledge of things, and there might be a better way but that’s what I went with and it turned out to be easier than I thought. I made an Array, I had a folder, which I referenced through code to grab the single prefab in it for a tile in the 3D world, and it all worked. My next problem, which I didn’t think was gonna be a problem is how to show character “movement areas”.
Games like Fire Emblem(seen above) have the battlefield light up with color to show where you can move(blue) and the farthest range of your attack(red). I wanted to start simple and just show movement. So had the scene populate with however big the grid was coded to be, I had a single “Size” int to make the grid squared, and got some mouse inputs working for clicking on the tiles in scene. I put a “Tile” script onto the Tile Prefab that just lit up when you clicked on it.
I had a big problem with this which was trying to calculate a way to move a certain number of spaces in an (x,y) area, because you have 4 different directions to move in. The problem lying in the fact that some distances are negative and some are positive, but I wanted them all positive so that I could accurately count and use the result as in subtract from the “current movement” of the player.
I found that if you take your (x,y) and add them together as an absolute value (for negative just in case) then subtract the surround (x,y) coordinates individually you will get “how far away a tile is”. Example below, its just a modified distance formula with n being the space you want to move to and d being distance moved:
| (x0 + y0) – (xn + yn) | = d
It took me a while to figure this out ONLY BECAUSE I forgot that absolute values existed, thanks brain.
Switchin’ It Up (I didn’t save many pictures)
So after this I realized that I was getting ahead of myself a little bit. I was jumping head first into trying to create the grid an player movement, when I could just create a way for the game to play itself with AI, then after that works, slap some player control and inputs over that. Now I had some new goals:
- Create an enemy class with stats with a strategy class to dictate actions
- Populate a grid with said enemies
- Program movement along the grid
- Create script that will handle damage calculations between enemies
- Allow Enemies to die, becoming removed from the grid and the game
- Create an End State
- Maybe add skills if I feel like
At this point its about the end of January 2020, I had just gotten a new job working at a Starbucks, so time was taken away from me working on this. At least it wasn’t as much time as Target took from me so that’s nice.
After about a month more of working on this I had some basic interactive UI that could change things like grid size, and how many enemies to put on the board.
At this point I knew it all worked: Enemies would populate the “battlefield”, all of their stats would be randomized, and they has skills (I REALLY wanted to add skills). This is where the next problem occurred, I didn’t know how to program AI movement. I did not even know where to start, so I just improvised. I gave every enemy a target that they wanted to kill, that would change whenever their target was dead, and they would “move” towards their target with a hodge-podge series of if/else statements. And it worked for the most part. I would run into some null end states (enemies not moving towards each other, or they would only move and never attack) but nothing game crashing. So in the end, to test AI and to try to understand more how data works with no 3D elements, I learned a lot. This is what I got out of it:
and then a more massive scale:
So for the move to a 3D representation was not that difficult at first. I set up a folder system within Unity’s “Resources” folder and loaded spawnable objects through code, then populated the scene, attaching the correct scripts as needed, again, through code. This better helped me better understand the Unity Component system as a whole.
I then had to revamp and add character classes (warrior, mage, etc.) from the base of my enemy and strategy scripts. This wasn’t very hard, just time consuming, condensing variables into structs, adding new variables that I think I would need and making sure not to repeat anything with the inheritance tree I had created.
[picture of script inheritance]
then I had to add Camera controls, player interaction in the 3D arena and some actually decent UI design instead of just using the stuff from the 2D version
So here is where I spent a bunch of time just creating all of my UI inside of Unity. Once it was all set up, I created scripts for each menu screen (Character select, Grid setup, and Battle). They all are called and switched on and off from the Master script “UIHolder”. After I got most of it setup I took a huge break because I was majorly depressed during Covid and I just wanted to not be burdened with work. I was let go from my Starbucks job and lived off of unemployment for a while, then I had to move back in with my parents. So I wasn’t really in the best head space.
After a couple months gone by, and no junior developer jobs open, I went back to programming this game. I decided that I would get the character controls working during an actual fight. and it wasn’t really that hard, the first prototype I had with just the panels was a good stepping point in getting the tiles to light up and create only “selectable tiles” by checking the current game state with whatever colors were interactable. So I do not have a gif of it, but turn order was “Players -> Enemies, repeating”, meaning you could select your characters one at a time to get them all to move. Once all your characters have moved, then you pass the turn. However I already had an “initiative” variable so I decided to make the game more interesting and had the individual initiative stats decide turn order instead.
So I had a working version but it just felt wrong for some reason… and it was because my movement was still janky for the enemies. So I did some research and found Dijkstra’s Algorithm. I tried to recreate it in a way that would work well for what I was doing, and to not lie… it took a while. Trying to recreate it with the only information in the terms graphs, vertex, source, and Queue did not compute for a while in my head. I mean this with the fact that I had everything set up in an equal space (all movement = 1), and while I know it worked, I also needed this to return a list of spaces that would be traveled, so that I can truncate the list to the first x tiles, x being the maximum movement a player can move in one turn. This was so I can then feed the list of spaces into a different script that would move the 3D representation of the active “character” that has the turn space by space, instead of it just moving across 4 tiles to get to its destination.
After I got this working I just needed to flesh out the gameplay loop, which wasn’t that hard and it all worked!
So all in all, I finished it. I set out what I wanted to do, try to replicate a 3D grid style RPG which was a success. Was it a Great or Exceptional success… that’s not for me to say. I know that there are better design patterns to follow or data structures to implement and they are out there for me to learn. Unfortunately, I don’t know they exist until I find them or someone introduces me to the idea. You can only look up “Good design patterns Unity C#” so many times.
If there were things that I would have liked to implement it would definitely be a better Character Selection screen. I feel like it should be more of a Character Customization screen, with more options and better layout. a design I had below:
I also have the Inheritance Hierarchy for “characters” easy to set up stats, weapons, and skills. So I might go back and add some more classes for players and enemies.
ALSO a HUGE thing I learned is that, when working with arrays and managing grid ranges, you can just make another small array that houses move/attack range/skill range data instead of having a single “range” variable. This to me seems like a good idea, but then there is the offset thought of “well which would be more wasteful?” While I do not know a lot about optimization, I do know that a single int take up less space than a double array filled with ints. Then the question is well if I just have the data handy with the arrays am I saving more time by not having to call and do additional math with a single int per call of my function. The answer is probably “it doesn’t really matter with how good computers and consoles are nowadays” but until someone can tell me otherwise or I test it extensively, I will never know.
In all I probably spent like 2-4 weeks of actual time spent on this project, spread throughout an entire pandemic between depressive episodes. I might come back to or even remake this project in the future, but for now I need to create more things.
Thank you for reading!