Devlog 003


Devlog 003

My goal for this session was to implement some sort of combat mechanics into the game. However, before getting to that I had some essential things to add! The first of these was a way to control the camera: panning with the keyboard and mouse and being able to zoom in. This is fairly straight forward. I created a script for the Camera object which handles input in its Update() function. The arrow keys simply adjust the position of the camera in the relevant direction. To implement mouse panning when the cursor is near the edge of the screen I simply had to check if it was within a certain range of the edge of the viewport. Implement the zoom was as simple as increasing or decreasing the Size property of the camera.

The catch with the camera functionality is how much to move the camera based on these inputs - your favorite games no doubt have a sensitivity setting to control this. To support this configuration I added a variable for MousePanSpeedKeyboardPanSpeed and ZoomSpeed which I can later expose through an Options menu.

The other thing I wanted to do before worrying about combat was refactor unit selection. My first go was straightforward with a collider on the unit objects checking if a thing had been clicked and then accessing the UI manager directly to set the selected state. This worked fine as a proof of concept, but would become unsustainable as I added more functionality.

I refactored the input system so each unit wasn't checking if it was clicked. Instead, now the HexGridManager is the only thing checking for input. When a tile is clicked it fires an event: InputHexClickedEvent. This input event is handled bythe InputManager which can call the UI or whatever else is needed. In this case, it sets the data of the HexDetailWindow to the units in the hex.

The HexDetailWindow can then instantiate the necessary UnitDetailPanels to show whatever units are there and also set the information about the hex (terrain, movement cost, etc). When a unit panel is clicked that fires a new event: InputUnitPaneClickedEvent. The InputManager handles that event, as well, and it can select or deselect the unit as appropriate. What is cool about using these events is that other things can also handle these events as needed without impacting the other parts of the code. For example, when I go to implement sound effects into the game I will add a SoundManager that can handle these events and play the required sound. This architecture helps to avoid spaghetti code of one thing calling a bunch of others, which will make it easier to both enhance the game and also change isolated parts of it as needed.

With those changes in place I was ready to think about combat. As I discussed previously, when a unit is selected I add "targets" to the map for valid actions: movement and attacking. When you click on a target, the HexGridManager now fires off the releveant event: InputMoveTargetClickedEvent or InputAttackTargetClickedEvent. When either of these things happen I have UI to update and game stuff to do.

When an action target click event is received, first it is validated and then it is turned into a Command. Commands related to specific things that will change the state of the game. In this case, you guessed it, I added two commands: UnitMoveCommand and UnitAttackCommand. These commands created with all the relevant data they need to perform the required change: the target hex, which unit is acting, etc. Besides the properties for the relevant data each command also implement an Apply() method, which is where the magic happens. This architecture made it easy to start implementing the game logic.

I also added shooting attacks (with a new sort of hex "target", an input event, and a command) and added artillery to the game. While Infantry units can only shoot adjacent hexes, artillery has greater range. This clip shows both melee and shooting attacks, although there is little feedback currently to understand how things went.

Here is an example output from the log file:

----------------------------- 

 -- START MELEE -- 

 RED 3 dice: 8 

 BLUE 2 dice: 8 

 ------- Attacker Rolls [8] ------ 

 Roll result 2 

 Roll result 4 

 Roll result 4 

 Roll result 3 

 Roll result 5 

 Roll result 4 

 Roll result 1 

 Roll result 1 

 Attacker hits: 1 

 Applying 1 hits to 1 units 

 BLUE 2 takes 86 casualties from 1 hits 

 ------- Defender Rolls [8]------ 

 Roll result 5 

 Roll result 3 

 Roll result 5 

 Roll result 5 

 Roll result 4 

 Roll result 4 

 Roll result 2 

 Roll result 3 

 Defender hits: 3 

 Applying 3 hits to 1 units 

 RED 3 takes 198 casualties from 3 hits

----------------------------- Difference: 2 RED RETREATS -----------------------------

----------------------------- 

 -- START SHOOTING -- 

 ------- Firing Rolls [2] ------ 

 Roll result 1 

 Roll result 1 

No hits

-----------------------------

If you are interested, these mechanics were quickly adapted from General d' Armee 2, one of my favorite tabletop wargames, but they were just a place to start. That game is more tactical than I envision Corsican will be because I want battles to resolve reasonably quickly and simply.  With the core of these systems in place, the next thing to add is some sort of turn structure. Right now you can click on any unit and do anything at any time. To do that I have to think more about what a game turn is going to look like. 

Stay tuned!

Leave a comment

Log in with itch.io to leave a comment.