Refactoring

20130808_230559

With my plans on changing the combat system, a big refactoring effort on my code is needed.

I received good feedback on my article about a loosely-coupled system for code in games. So I think I should apply the principles back to my code in Tactics Ensemble.

Low-level

I should start with revisiting my unit low-level classes.

UnitAnimation:

My previous code was a thin layer behind Unity’s Animation class. Users of this class had to compute things by themselves, specifying blend time between animations, needing to check for animation playback positions themselves, etc. I need to change this so it would be a fire-and-forget scenario. Just send requests to do a certain animation, and let the UnitAnimation class figure out the little details by itself.

AnimationsUsed:

Some simple class should facilitate what default animations should be used for idle, what default hurt animation should be used when getting damaged, what animation should be played when unit is selected, and whatnot.

UnitMovement:

This is a good time to revisit the arguments between Character Controller and Rigidbody. Which one should I use now? I should also redo pathfinding, obstacle avoidance, and pushing other units, in a cleaner way now. I should also consider how this class is used by the human player input and by the AI system, how different should handling those two users be.

UnitAttack:

This is the class that was missing from my systems. A separate class should handle the little details of turning on or off melee collisions, and launching of projectiles at the right time.

UnitGui:

This is also something I need to add. A class that handles GUI for the unit, meaning what effect should happen when the unit is highlighted, when the mouse is hovered over it, when it is selected, etc.

The healthbar and any other icons floating above this unit should also be handled by this class.

Should also communicate with the GUI HUD to display this unit’s actions, portrait, name, etc. on the HUD.

UnitReplay:

Something I could add later on. It would basically take note of all incoming function calls to all low-level classes, record at what time they were called. When watching a replay, we simply review the list made, and call the appropriate functions at the proper time. This only handles the replay for one unit, so we have one UnitReplay for each unit in the battle.

Unit Facade Class

I should make the Unit class refer to the low-level classes via interfaces only. I’d need to clean this up as well to accommodate the new combat system.

20130808_230638

Actions

I think I also need to question my system on Actions and Effects.

It would be beneficial if I convert my Effects system to just use behaviour trees instead. It would make editing more consistent, and add flexibility to attacks; you could add conditional effects easily (e.g. if my health > enemy health, deal 2x damage).

Actions (i.e. attacks) would get a revamp, to accommodate the new combat system to be experimented on. I also need to consider if it can be improved to integrate with the AI system better.

Local Player Singletons

This is the set of singletons used to facilitate player input from mouse and keyboard.

They manage selecting a friendly unit on behalf of the player, relaying orders to it, facilitating when the game is asking the player for a destination/target to click on, etc. Basically it handles player input from the local machine (as opposed to input from across the network in a multiplayer game).

I think I should separate this to a low level that handles mouse and keyboard directly, and a high level that sits in problem domain. With that, I should be able to add touch-screen controls later without messing the existing code.

UnitSelector

The class that handles which unit is currently selected. In the normal flow of how a player plays the game, this is where it all starts.

Since it manages which unit is selected, this dictates which unit will be given orders by the player.

This is one of the things that probably needs decoupling, with a UnitSelectorMouseKeyboard that listens for left-clicks and keypresses, and a high-level UnitSelector that facilitates OnSelected events, tells which unit is currently selected to whoever asked it, and whatnot.

GUI HUD

Accepting input from GUI buttons should also be handled by a separate, low-level class. BattleNGUI. This would be the one directly handling NGUI.

This low-level class will listen in on unit selection events, so it can make sure the currently selected unit’s action buttons, portrait, name, etc. get displayed (in NGUI). Each action button would somehow be able to fire off requests to activate that action of that unit.

A BattleHotkey class or something would essentially do the same of allowing sending of requests to do an action of the selected unit, but now by keyboard hotkey presses instead.

Camera System

Camera movement would normally be independent from everything else, being controlled by the player only.

However, there are times when the camera would be controlled by the game.

When an enemy unit is moving on its turn, the camera should center to it (which I haven’t implemented).

And some actions or events may call for showing cinematic shots of characters.

Effects like camera shake would also be handled by this system.

Decoupling is also in order here. A CameraControlMouseKeyboard would listen for keyboard and mouse input while CameraControl provides the actual moving, rotating, zooming. There would be a CameraControlTouch for touchscreen devices.

AI Players

Fairly rudimentary right now, and I don’t think I’ll be changing this soon. When the time comes, I may experiment on giving AI players a central behaviour tree to use.

Right now, each AI unit thinks for itself. But coordination may be better if I give the AI player its own behaviour tree. It would look at the battlefield map from a tactician’s point of view, then it would tell each unit what role they should be in (go to the defensive, attack from this side, scout here, etc.).

Battle Manager Singleton

This singleton acts as umpire, deciding when the battle has ended, who won and who lost. It manages a list of all players in the game, so it can decide whose turn is next. Very simple piece of code, and I probably don’t need to do anything here.

 

If I knew how to make UML diagrams I probably would make one now.

Changing Things

20130808_230210

So, here’s the thing.

One of the experiments I did with my game was that movement also consumed Action Points. This is the same with the old XCOM and Fallout games.

However one thing I noticed is that I am poor at judging how much Action Points I should spend, i.e. “Oops, I made my unit move too far, now he doesn’t have enough AP to actually attack anymore! He’s just a sitting duck.”

This wasn’t so much of a problem with XCOM; the AP in that game is of whole numbers, that amounted to less than 100 points, normally. It’s even smaller in Fallout which would be in the 10-20 range usually. (It was feasible for them to use whole numbers because those games had grids for movement.)

Being in small whole numbers, it was easy to think ahead how much AP you’d need i.e. “Oh, swinging this big hammer costs 3 AP so I better use only up to 7 AP (being that my character has 10 AP)”.

In this regard, I’m deciding to experiment with a different system. It’ll closely resemble Skulls of the Shogun or the Arc the Lad games in PS2, where movement has no cost. Instead, you can move as much as you’d like within your movement range (i.e. a circle perimeter).

There will still be AP, but it is only needed for attacks or other actions instead now.

It also feels like something that may resemble Valkyria Chronicles, in the end, in that it feels like an action-game, only that you control many people, one at a time.

Results of 1 Year Game Challenge

20130729_010139

So, by the way, I forgot to mention that the 1 Year Game Challenge sort of fell by the wayside. Long story short, the organizers were disheartened by the amount of participants giving up. Ergo, they stopped asking for updates from us remaining participants. So I kind-of lost motivation too, amidst busy schedules.

However! The new IGDA Manila board initiated a revival of the competition, which they simply called 1 Year Game Challenge++.

With new people manning the competition, hopefully this will work out better.

This time they’re trying to coax motivation by making participants give up PHP 1,000.00 (approx. USD 20.00) to IGDA Manila. If they back out of the competition, IGDA keeps the 1,000 bucks. If they finish their game and release, and some threshold of download numbers are reached (which is admittedly very low), they give back the money.

It’s a well meant gesture (and a cheap tactic to get funds) but I’m a believer that carrot-and-stick motivators don’t work with creative endeavors (however, I believe they work if your livelihood is on the line). This is from Dan Pink’s TED talk on motivation.

I instead suggested the participants do periodic game jams, as I always see a sky-rocket jump in motivation when you’re in a room filled with other people doing the same thing.

In the end, I joined again. Development on Tactics Ensemble has been halted long enough!

Finally Modularized My BT Library

TEV-w-INTLord

My behaviour tree library now exists as a git subtree in my game’s repo!

This means any updates I make to the library from other endeavors can easily be incorporated to this project. Likewise, any updates to the BT library from this game can be applied to the BT library’s own repo.

One such update is the Parallel Composite. I realize they’re really needed for real-time games, so I added them in. For example, when you need your A.I.’s moving, to act independently from shooting, allowing a run-and-gun behaviour (shooting while evading, shooting while charging in, etc.).

It’s not multi-threaded though (with this being in Unity), and I haven’t added completion policy or failure policy to it yet.

The way I made my Parallel, I think is different from the one explained in AIGameDev.com. It’s far more rudimentary since I’m still not finished with it.

  • The Parallel executes all its children once in sequence, but does no early-out aborts.
  • It waits for all of them to finish executing, then deliberate what its return value should be, based on the return value of its children.
  • Even if a child returns “Running” (a request to suspend tree traversal), we still wait for all children to complete.

There would be two types of deliberation policies:

  1. At least one failure from any child will make the parallel return failure. The parallel will return success only if all children returned success.
  2. At least one success from any child will make the parallel return success. The parallel will return failure only if all children returned failure.

Essentially, one is strict, and the other isn’t.

What if two children of a Parallel return “Running”? I haven’t taken this into account but I imagine it would be like this:

  1. Traversal should continue at the very first one that signaled “Running”.
  2. Even if one of them finished successfully, if the other one is still in “Running”, the whole tree should still return “Running”.
  3. This means the traversal should keep track of all “Running” actions.
  4. Essentially what we want to prevent here is resetting execution of a “Running” action, when what it should really do is attempt to continue where it left off instead.

Thankfully I already made code where the traversal stack is saved when we suspend traversal. However, the idea of keeping track of two or more “Running” actions complicate things. Could be I need to store more than one traversal stack.

Real parallel nodes I believe, will keep on running its children. If one child finishes too early while the others haven’t finished yet, it gets run again.

Since my BT library runs on Unity which is hampered by restrictions on multi-threading, I’d have to do some sort of job scheduling like operating systems do.

This was one thing I thought of before: an interleaved parallel.

  • This will disrupt the normal flow of traversal. The interleave will look at its first child, let it execute one of its children, then suspend that traversal. The interleave will then move on to its next child, also only allowing it to execute one of its children only. And so on.
  • It’s a constant cycle of suspension and continuation of the children’s own traversals.
  • When should the interleave stop? When all children have completed their traversal at least once (remember, they repeat traversal if possible). Then the return value of the interleave will be chosen from the deliberation policies mentioned earlier.

For my scenario though, I’ve yet to need this. My behaviour tree actions and conditions are very lightweight, in that they don’t actually do the actions themselves. They just send requests to the other sub-systems in the game to do the work for them. The behaviour tree only handles the deciding part, not the doing part. As such, traversal is relatively fast, that I (so far) don’t need a job scheduler for a parallel. I just traverse them linearly.

Assertion checks, on the other hand, makes sense to be checked only after resuming traversal of the whole tree (back from a “Running” state).

Why? Because most, if not all, actions always return a “Running” signal. As mentioned, actions only fire off requests to the other sub-systems in the game to do the actual work. Once that request has been sent, the tree has no choice but to wait for that to finish. For example, an attack action sends a request to play the attack animation (among other things). And only once the animation is finished do we resume traversal of the tree.

So I made a special composite just for that. It’ll automatically traverse its “assertion” child when the resuming of traversal continues from its “main” child. I called it Auditor.

The BT library by the way, is now tentatively named “INTLord”. I’m not sure if that should be INTLord, or INT Lord, or Int Lord.