Doopwee Games Logo
 
 

BLOG 3 - More UI and Gameplay

June 15th, 2025

Here's what I was able to accomplish since the last blog:

  1. Added Enemy info on highlight
  2. Added hover over tile highlights to make it clear where your cursor was.
  3. Added confirmations of battle actions like move location and attack.
  4. Added Camera Controls to the HUD.
  5. Localization Text Component and Editor Rules
  6. Added a battle complete popup when there are no more opponents.
  7. Allow users to rotate facing direction at end of turn and rotate bot towards that.

Target Character Info :

I started by basically just making another instance of my active char info for this, put it behind the active char info and gave it a new anim in and out to just rotate upwards, scale and transition. I added info to the event data to know if it's the activechar or the target char and then added a bool to the class to handle slight differences between the two. I thought about creating a new class here that inherits from the activechar info class but I initially thought this was just bloat for something so small.... eventually I took that back and decided It was getting messy with instance specific handling for the active char vs the target char so I bit the bullet and extracted the content into subclasses.

Hover Indicator :

I then hooked in my battle manager processing for hovering. Hovering needed to be handled differently than the highlight states of the tiles as I want to be able to hover over highlight state while also using the colour it was previously. I decided to go with tinting the highlighted tile just a shade darker for now. I started with the character placement screen then on to the battle. I passed this state in through the alpha channel of a colour being passed to the tiles shader. I had previously only use the alpha for 0 or 255 to indicate whether the tile was visible or not. This was a bit wasteful so I hijacked and added a second option for it to process visible, highlighted or not visible now. I wanted to keep the red and green channel for decorating the tiles with more details in the future.

Confirm Actions & Charge Consumptions :

I wanted the user to confirm their action to move or attack before proceeding. To do this I had to modify my state system for the active character. Previously It had states for move wait and move animate, but basically I needed to shimmy in a Move Selected state and same for all the others like attack, skill use etc. They all needed a middle ground state added. This state allowed me to highlight the tile they wanted to select as a status and then if they click the tile again once highlighted it confirmed the action. If they click off on another tile it removes the current highlight and adds a highlight to the most recent selected.

For the next step, I wanted the player to be able to visualize how much charge will be consumed by their actions before they commit to it. To do this I added a second fill image to the fillbars which is a child of the current fillbar and added a mask to the parent. I then use the full width - the amount already filled and the percentage consumed which results in a nice effect of the consumed bar being darker over the current bar for the amount that will be consumed by the action.

You can see a bug with the hover highlights in this pic to the left where the outer tiles you can't move to stay highlighted (You shouldn't be able to highlight them at all in the future).

Localization :

I decided at this point to bring in some of the components from the last prototype I had made. I was actually quite happy with the architecture from the last one I was working on, just the gameplay wasn't making me happy. I had a localization system in place which was good, but I wanted to beef it up a bit more and make it a bit more user friendly. I fixed up some editor scripts to grab the existing keys from the csv files and populate them into a dropdown and added in simple editor functionality to add new Keys. I also segmented the csv's into categories like MENU, BATTLE, etc so that it's easier to detect where the strings are from in the future when translating. I brought over a few more modular components I had in the old project and as I use them or modify them I'll mention them at that point. 

The reason I started to do this was that I finally hit a higher Text area with the end of battle screen and thought before I dive too far into it I better get the localization in place. I then took a pass at all the existing texts like the actions menu and changed those to translation lookups as well. In Unity I created a wrapper component based off the TMP Text component that extends it to tap into my localization manager to add a dropdown for localization category and then a dropdown populated with all the existing keys. If they key doesn't exist, you can modify the key text and it creates a new button for ADD KEY if the key isn't in the Database already. Next it allows for the text content of the english value for that key. You can then click apply below the text if it doesn't match the existing database entry for that key. Later on once the game is near completion I can have the localization completed for the data and then test the game for translation bugs that occur where text overflows boxes once translated or looks off. This is normal from my previous experiences.

I am toying with the idea of using generative AI for the localization at that point.

End of Battle :

I decided it was a good point now where I could kill all units on a team to end the battle. The base system was already mostly in place so it wasn't too bad for changing states here and stopping action processing but it just required ensuring the action menu wasn't shown, and creating a new end of battle popup. The end of battle popup just subscribes to the state changes of the battle and shows when it goes into end game state. This is just a basic empty popup for now, but I've created enough popups now that have the same functionality of having to show and hide with an animator so I decided to make a core class that all popups in the future can inherit from to have these functionalities embedded. It just requires that the animator states names are kept consistent with AnimIn and AnimOut. 

Initial Feedback :

At this point, I am quite happy with how quickly everything has come together. The battle was playable and so with that I felt like I had already create the core of a tactical RPG. I'm hooked now. Committed. I am loving developing this game, and honestly. It's probably been my favourite development experience I've had my whole life. I'm so very excited for where this is going... so it was the moment of truth. Time to get my harshest critics to play. My son was my first to play the game outside of myself... and, well it was off to a rocky start. The placement phase wasn't clear and he didn't know to keep placing units (Note 1 taken, need UI for placement screen sooner than later). Once I helped him out with this info, he placed the expected 5 characters and we were off to the battle! he moved a unit or two and things were cooking UNTIL.... The random generation had boxed in one of his character placing him starting square cornered between a rock and a tree, literally between a rock and a hard place. His unit was stuck and couldn't move (Note 2: Ensure that randomly generated objects don't completely restrict starting squares.) I had tested the game many times and not once had I encountered this so although it's rare, its a possibility of random generation like this. I had to get him to restart as he was basically playing 4v5. He restarted and this time... he won by a hair with a dramatic miss from the opponent on it's final attack that would have killed his last unit. It was great to see and he enjoyed his experience despite critiquing my temporary basic robot models :).  

I started to address the placement confusion by changing the placement phase to show the whole island but darken out the areas you couldn't place in (see picture above).

It was on to an even harder play tester. My wife. My wife is very particular about the games she plays and fairly critical and easy to frustrate. She mostly plays casual stress free cozy games although I did get her hooked on Final Fantasy Tactics A1/A2 but she had a harder time getting into what I consider the classics of FFT and Disgaea. All that being said, it's not her first tactical rodeo. She provided some good constructive feedback with the following after playing. 

  • Misses happen too often and were frustrating.
  • Camera controls were too restrictive with the four points you could move them to. She wanted full rotation control.
  • The placement of the actions menu covered gameplay and needed to be moved off to the side.
  • The rest was mostly small bugs noted.

I took each of these feedbacks, reflected on them and implemented solutions. I started with the camera fixes and although I particularly like the 4 static camera locations and was used to this in other games I felt like she had a valid point and then started asking myself why is there 4 static cameras for some tactical RPG's. I'm guessing the practical reasoning for this limitation is because of the sprite based characters and that they maybe looked awkward at the off angles. With my game I plan to have 3D models instead of sprites, so this may be a restriction I had to leave and honestly I'm glad I did because I do feel like the full 3D camera rotation controls really helps here. I implemented it in the Q and E key controls and then through the UI.  This was a drastic change in implementation so basically had to rework the controls to have release and press inputs as before it was single press events. Release wasn't something you can tap into by default as an event for UI buttons so instead I made a Releaseable button class that extends the Base button functionality but has event handling for the release which at this moment is fired from pointerUp but this won't in the future solve controls for handling controller button presses, but I'll cross that bridge when I get to it.

I did some tweaking for the remainder of the feedback. Moved the actions menu over, and changed misses with the melee action to be instead a divider by the amount of damage in half. This is less discouraging to the player but noted in red font instead. If the half ends up being less than or equal to zero I then had it display miss instead.

I also took this point to add int a prompt text. Its a popup that quickly animates in and out using the Animated Popup I made and then just taps into all the battle events like move action or choices or what not. Each one displays a different text all accessed through the localization manager. Presently Adding in new localized text access strictly in code and not through the text component means manually adding them to the CSV files for each translation. I had initially thought of making it so that if it tried to access a Key and it didn't exist it just auto added it, but then I thought if I had a typo I'd start adding in duplicate keys which can be messy. I've added a full localization editor to my tasklist to add new key entries. 

I also found the AI was a bit too simple here. I started to think of ways to have them retreat and be a bit more strategic than move towards and attack. If they attacked and had left over movement I had them move away. If their health was lower than the nearby opponents then I had them run away and lastly if they were outnumbered by their opponents they would run away. I implemented a bunch of if statements and there was some repetitions and eventually I landed on a new algorithm instead to first determine the AI's mindset. I called this the apprehention calculation which combined each of the factors of the number of enemies, proximity, and health to determine how apprehensive this character should be and I gave it three outcomes, proceed with caution, retreat and charge!

Character Rotation Actions :

I then added in the ability to rotate the characters. This was fairly straightforward, but to begin with, I needed to know the direction the robots were facing. I decided for now just to give the robot prefab two white spheres for eyes.

I then added in new states for the rotation and had already preset up all the callbacks and hooks for the functions from the UI when I made them. I just had the buttons not interactable before. I fixed this in the editor and got to work implementing the state handling. When the rotation is selected the code was easy to highlight as I had already setup the highlight state for direction in the state enum and the handling in the shader for this. I knew at the time it was something I'd need to implement. The most challenging part of the rotations here was the actual rotation calculations needing to find the direction of the target and then getting the euler angles to it and comparing to the current eulers. I then just stepped between them by timedelta. The speed of this needed a bit of playing around with too as the translation multiplier was about 100X less than the rotations speed needed. I also added the rotation animation when the robots change direction to face the way they are moving.

Next Steps:

I'm actually compiling separate lists now for this. 

What I should/ will probably get done next. These are easy tasks that I can get done in an evening or an hour or so here and there :

  1. Add UI to the placement phase for players to cycle through characters to place.
  2. Add Post Battle UI Popups (XP Processing, Rewards)
  3. Experience calculations, levelling up units
  4. Stubbing out the main game flows screens (main menu, save slots, settings, main map, party management, inventory, tavern, scrapyard, lab .
    • no animations, sounds or art. Just the pure base layouts (UGLY PHASE)

Future Concerns. These are things that may be more challenging tasks but aren't a necessity at the moment:

  1. Grass / dirt texture locations on the island
  2. networked battles

 That's it for now... Steam Page coming July to wishlist.

If you are interested in the games development, please hop in the discord located here for the latest updates:

 

Discord Icon Join the Discord

Other socials I sometimes neglect too much...