RTS - Detecting when a command finishes

Started by
5 comments, last by DerekL 9 years, 7 months ago

I'm working on a game that is controlled like an RTS, ie left-click and drag a box to select units, right click to issue a move command, or press a hotkey and left-click to issue some ability command. You can also hold shift to queue commands after the current one (move here, then attack this building).

My question is how I can detect when a command finishes so I can start executing the next one. My current implementation is as follows:

I have Command structs that just hold data (MoveCommand holds a world position, AttackCommand holds the id of the unit to attack, etc).

I have a CommandRunner that has a method for each type of command. These methods return a boolean that is true if the command finished, or false otherwise.

I have a CommandManager that has a map that maps IDs to linked lists of commands.

My algorithm is to loop through CommandManager's map. For each element, execute the first command in the list using the CommandRunner. If it returns true, pop it off the front of the list.

This works great, except that my conditions for a command being done aren't good enough. For example, my naive first attempt for MoveCommands was just if( myPosition == goal ). This works for a single unit, but obviously adding any more creates problems since most of the units can't get to their goal. They end up just sitting around the point jostling to get closer, but never actually reaching it.

Obviously the conditions are easy for some commands ( AttackCommand would be if( target.dead() ) ), but I'm not sure of the best way for a Movement Command. I'm thinking I'll have to implement some flocking behaviors, since it seems it would be more reliable to check if the flock as a whole has reached the destination.

Advertisement
When a command is done is going to depend on the command (is target dead? is the building built?), but for movement you probably want to have a radius - basically, don't check for "am I sitting on my goal", but "am I closer then X units to my goal" which can be done with a simple vector length check.

If you want to get fancier you could look into multi-unit moves as a single large "unit" with the goal checks coming from the center of the mass.

Hi.

What could happen is the unit walking to its target could ask idel units in there way to move. This looks good with vehicles.

The problem with checking for a radius is it only really works for a certain amount of units. A single unit would stop short of the destination, and repeated clicks wouldn't get him any closer which would be very frustrating and unintuitive to use. Plus it would still run into the same issues with groups too large to fit into the chosen radius.

I already have handling for idle units. Basically whenever units collide, I push them each equally away from each other's center just enough to no longer collide, so idle units end up being pushed away. My problem is occuring when multiple units want to move to the same spot, so neither can push the other away.

I'm thinking I'll have to use a mix of approaches, like checking for a radius that's based on how many units were selected, abandoning a move after a certain number of collisions, using flocking to set a different goal than what was clicked, etc.

That’s the right idea. Basically the way I deal with this problem in my game is for each unit to keep a list of ids of other units in the flock; whenever two units collide, they offset their destinations so that they’re moving in parallel to areas around the ultimate destination (if they’re moving in the same general direction) and add their own id to the lists in all these connected units so they can keep track of each other. Flocking and keeping a list also means you can eliminate a lot of unnecessary collision detection every update loop, since you know that units that have already been adjusted to move as a group won’t collide with each other again unless some outside unit interferes.

There are a lot of special cases to check for, but having some kind of list of nearby units means you can adjust the acceptable distance to the target depending on how many units are around. If you’ve just got one unit, it has to move exactly to the target, but if there are a lot of units moving to the same place, you can have a larger radius based on the number of units and their individual sizes for defining whether each one is close enough for the move order to be satisfied. (They should still keep moving to their destination at least until they collide with another unit, but once they do, they’ll check if they’re already within the group-defined radius of the destination and then either stop or tell the units blocking the way to move.)

Would something like the following work?

1) Set location as "target"

2) move unit toward the target

3) if the unit collides with an ally unit, check to see if the target is occupied by an ally unit

if not) continue as normal

4) if it is, check for the closest point in a ring around the target that isn't occupied by an ally. Set as new target.

5) If no spot is available, increase the ring size and try again.

Okay so what could work is you could add event listeners to the units following the main unit and when the main unit reaches his destination he dispatches an event letting all the other units know to stop. When this event is recieved just have the units move towards the main unit and if theres no more room to stop, then do this again until no units have any room left in between them.

This topic is closed to new replies.

Advertisement