Showing off my take on the course

So I made a couple of minor changes to @CodeMonkey’s excellent game design, as there are plenty of choices to be had along the way.

My ideal tactics style game has each unit taking a turn in order based on speed, so I created a TurnBroker class to manage this. The concept of a Player turn then Enemy turn is out the window for me (though these sorts of games can be quite fun, and a strategy session in themselves!).

Great examples of individual speed/turn based strategy games include most of the Final Fantasy games including my all time favorites, the Tactics versions.
A great example of an Each side takes a turn game is the Android Elder Scrolls game.

I also chose to allow units to only move in the 4 cardinal directions, and to prevent them from walking through each other. These two constraints lend themselves to some excellent strategies for blocking and planning ahead so you don’t get caught in a corner with no hope of escape.

Here’s the rough draft, before I go to tackle the camera/wall problems.

3 Likes

Helps if I include the link: https://youtu.be/Nwp08BiD_EM

3 Likes

Looks good! Also added the course to wishlist for after i finish the RPG course, didnt see it yet.

1 Like

Looks amazing really enjoying the course.

1 Like

I’m glad you liked the course!
Modifying the turn logic to be based on Speed is a great alternative.
I really like how it looks! Love the action camera while moving the units, and the bonus glow on the valid Attack positions looks awesome.
Great job!

1 Like

Thanks. Since this video I fixed the issue with the walls blocking the camera view with a combination of Cinemachine Collider and starting the follow Y position a bit higer.

I’ve also made it so you can’t shoot through an occupied space as well as not being able to move through occupied spaces (and of course you can’t shoot through walls).

All of the combat actions are now children of a BaseAttackAction class which takes care of most of the logic for determining the valid positions, possible positions and the BestAI. The child classes just need to override the range, the name of the animation triggers, and the projectile to use if any.

Upcoming, I’m going to implement flying logic. Fliers will be able to go over some walls, and not go over certain others. Most importantly, fliers can never land on an obstacle, they can only fly over the obstacle.

The final challenge I want to tackle is height. One of my all time favorite games (I’ll be showing my age here) is the original Final Fantasy Tactics. They use height to great advantage!

1 Like

Flying is an interesting one, I hadn’t considered that in my design, should be fun to implement!

1 Like

In it’s simplest, it’s just considering every possible spot within range, and eliminating unwalkable tiles as end points, then passing a bool to the pathfinder to ignore unwalkable tiles. So when the turn is over, the unit will always be on a walkable tile.
More complexity would be to maintain a state of walkable, flyable, and impassable for each location. Fences, for example, would be flyable, while building walls (presumably there is an unseen roof overhead) would be impassable. One could go a step further and have perchable tiles, which would allow the flyer to fly over, or land on.

1 Like

How to find this course? How is it called?

1 Like

I believe this is the course to which they are referring.

On sale now for $23.40 Earth monies! Get it, get it!

3 Likes

Nice! I’m looking to do something similar. It would be cool to be able to effect a units speed with a spell or knock down.
How did your get the path to disappear on movement? I have tried HideAllGridPosition() from MoveAction_OnStartMoving(object sender, EventArgs e) but it nothing happens. My next thought was to make the texture fully transparent.

You want the Grid visuals to disappear when moving? You can indeed just hide them when you start a move action although you need to also handle the logic to keep them hidden when the unit moves, otherwise it will hide the grid, then the unit moves and it shows the grid again. By default the visual is set to always updating when a unit changes grid position.

This looks very good. I would perhaps consider showing a list of the units in the order they will be taking their turns in the UI, and highlighting the current, active unit. Could add to the decision making if the player knows who will be taking the next turn. Unless you don’t want that level of foresight.

The TurnBroker sounds useful if a unit’s speed can be changed during the course of the game and the turn order will be affected. A few years ago I made a dungeon crawler for a game jam where the combat is turn based (and I have been trying to redo it and make it a full game ever since). At the start of combat, I order all combatants in the order they’ll take their turns - taking speed, surprise etc. into consideration - and put them all in a queue. Then I just dequeue, take turn, enqueue and all goes well.

Got it by making singleton GridSystemVisual and calling HideAllGridPositions() from MoveAction Update() twice. Once right after !isActive and also in the else{ of the distance check but before the path reach zero. Then call UpdateGridVisual() when zero.
Is hiding ALL grid positions bad? Should I hide only the move positions?

Unless your grid is 1000x1000 (don’t make a grid of 1000x1000!), you should be fine disabling all of the locations.

Even if the speed is constant, at a certain point the turn order will naturally change. For example, if unit A has a speed of 30 and unit B has a speed of 60, then unit B will get two moves for every move that unit A gets. It also sets up a situation where you can conserve turn counters… In Final Fantasy Tactics, if you skip your turn, then your turn counter is reset to roughly 1/3rd of what it would be. If you move, but don’t act, it’s 2/3rds, same with acting but not moving. This means a ranged character that doesn’t move will get more turns than a character with the same speed that acts AND moves.

The whole scheme is simple… each unit gets a float NextMove;. At the end of the unit’s turn, that NextMove is incremented by 60/speed (that 60 is arbitrary, as we’re not doing “real time” in the simulation, but I use a similar scheme for time between actions in my real time rpg). So if the unit’s speed is 60, then NextTurn will start at 1, if it’s 30, it will start at 2, etc.

Here’s the entire TurnBroker class:

TurnBroker.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Attributes;
using Object = UnityEngine.Object;

namespace TurnManagement
{
    public class TurnBroker
    {
        public static event Action<Unit> OnNextCharacterTurn;
        
        public static IEnumerable<Unit> GetUnits()
        {
            return Object.FindObjectsOfType<Unit>().Where(h => !h.GetComponent<Health>().IsDead)
                         .OrderBy(u => u.nextTurn);
        }

        public static void NextTurn()
        {
            OnNextCharacterTurn?.Invoke(GetUnits().FirstOrDefault());
        }
        
    }
}

GetUnits is public to set up a visualization (yep, I definitely plan on showing the list of turns, and I plan on having the AI factor that list into it’s decision making process!).
When a unit finishes it’s turn, it simply calculates it’s next turn score and calls TurnBroker.NextMove(); The entire class is static, so no Singletons, no worries about finding the turn broker, no race conditions, as the TurnBroker gets it’s data as it needs it.

1 Like

Very nice! In this case I didn’t consider moving twice before another unit gets a turn. It is something I want to do in my dungeon crawler. Had loads of ‘bounces’ off my ‘idea wall’ around this.

PS: Your video inspired me a little. I have icons and assets lying around that I buy but never use.

Privacy & Terms