Gamasutra is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

Gamasutra: The Art & Business of Making Gamesspacer
Implementing Coordinated Movement
View All     RSS
September 18, 2021
arrowPress Releases
September 18, 2021
Games Press
View All     RSS
If you enjoy reading this site, you might also want to check out these UBM Tech sites:


Implementing Coordinated Movement

January 29, 1999 Article Start Page 1 of 3 Next

Part of the fun of working in the game industry is the constant demand for technical innovations that will allow designers to create better games. In the real-time strategy (RTS) genre, most developers are focusing on improving group movement for their next round of games. I'm not talking about the relatively low-tech methods cur- rently in use. Instead, I'm referring to coordinated group movement, where units cooperate with each other to move around the map with intelligence and cohesion. Any RTS game developer that wants to be competitive needs to look beyond simple unit movement; only the games that weigh in with solid coordinated movement systems will go the distance.

In this article, the second and final part of my coordinated unit movement series, we'll take a look at how to use the systems that we considered in the first article to satisfy our coordinated group movement goal. We'll also examine how we can use our coordinated movement fundamentals to solve some classic, complex movement problems. While we will spend most of our time talking about these features through the RTS microscope, they can easily be applied to other types of games.

Catching Up

Last week (Coordinated Unit Movement), we discussed a lot of the low-level issues of coordinated unit movement. While pathfinding (the act of finding a route from point A to point B) gets all of the press, the movement code (the execution of a unit along a path) is just as important in creating a positive game experience. A game can have terrific pathfinding that never fails to find the optimum path. But, if the movement system -isn't up to par, the overall appearance to the players is going to be that the units are stupid and can't figure out where to go.

One of the key components to any good movement system is the collision determination system. The collision system really just needs to provide accurate information about when and where units will collide. A more advanced collision system will be continuous rather than discrete. Most games scale the length of the unit movement based on the length of the game update loop. As the length of that update loop increases, the gap between point A and point B can get pretty large. Discrete collision systems ignore that gap, whereas continuous systems check the gap to make sure there isn't anything in between the two points that would have created a collision with the unit being moved. Continuous collision determination systems are more accurate and more realistic. They're more difficult to write, though.

Another important element for coordinated unit movement is position prediction. We need to know where our units are trying to go so that we can make intelligent decisions about how to avoid collisions. Although building a fast position-prediction system presents us with a number of issues, for this article, we can assume that our collision determination system has been augmented to tell us about future collisions in addition to current collisions. Thus, each unit in the game will know with which units it's currently in collision with and which units it will collide with in the near future. We presented several rules for getting two units out of collision in last month's article.

All of these elements work together to create the basis for a solid, first-order (single unit to single unit) coordinated movement system. The core thing to keep in mind for this article is that we have an accurate, continuous collision determination system that tells us when and where units will collide. We'll use that collision system in conjunction with the collision resolution rules to create second order (three or more units/groups in collision) coordination.

Group Movement

Unit. A game entity that has the ability to move around the map. Players expect their units to act intelligently. Group. A general collection of units that have been grouped together by the user for convenience (usually to issue the same order to all of the units in the group). Other than a desire to keep its units together, groups don't place any other restrictions on unit movement.

Formation. A more complex group. A formation has an orientation (a front, a back, a right flank, and a left flank). Each unit in the formation tries to maintain a unique relative position within the formation. More complex models provide an individualized unit facing within the overall formation and support for wheeling during movement.

Units, Groups, and Formations

Looking at the definition of a group (see sidebar at right), we can immediately see that we need to store several pieces of data. We need a list of the units that make up our group, and we need the maximum speed at which the group can move while still keeping together. Additionally, we probably want to store the centroid of the group, which will give us a handy reference point for the group. We also want to store a commander for the group. For most games, it doesn't matter how the commander is selected; it's just important to have one.

One basic question needs to be answered before we proceed, though. Do we need to keep the units together as they move across the board? If not, then the group is just a user interface convenience. Each unit will path and move as if the player had issued individual commands to each group member. As we look at how to improve on the organization of our groups, we can see that there are varying degrees of group movement cohesion.

Units in a group just move at the same speed. Usually, this sort of organization moves the group at the maximum speed of its slowest unit, but sometimes it's better to let a slow unit move a little faster when it's in a group (see Figure 1 below). Designers generally give units a slow movement speed for a reason, though; altering that speed can often create unbalanced game play by allowing a powerful unit to move around the map too quickly.

Figure 1

Units in a group move at the same speed and take the same path. This sort of organization prevents half of the group's units from walking one way around the forest while the other half takes a completely different route (see Figure 2 below). Later, we'll look at an easy way to implement this sort of organization.

Figure 2

Units in a group move at the same speed, take the same path, and arrive at the same time. This organization exhibits the most complex behavior that we'll apply to our group definition. In addition to combining the previous two options, it also requires that units farther ahead wait for other units to catch up and possibly allows slower units to get a temporary speed boost in order to catch up.

So, how can we achieve the last option? By implementing a hierarchical movement system, we can manage individual unit movement in a way that allows us to consider a group of units together. If we group units together to create a group object, we can store all of the necessary data, calculate the maximum speed for the group as a whole, and provide the basic decision making regarding when units will wait for other units (Listing 1).

Listing 1. BUnitGroup.

// BUnitGroup
class BUnitGroup
BUnitGroup( void );
~BUnitGroup( void );

//Returns the ID for this group instance.
int getID( void ) const { return(mID); }

//Various get and set functions. Type designates the type of the group
//(and is thus game specific). Centroid, maxSpeed, and commander are
//obvious. FormationID is the id lookup for any formation attached to
//the group (will be some sentinel value if not set).
int getType( void ) const { return(mType); }
void setType( int v ) { mType=v; }
BVector& getCentroid( void ) const { return(mCentroid); }
float getMaxSpeed( void ) const { return(mMaxSpeed); }
int getCommanderID( void ) const { return(mCommanderID); }
BOOL getFormationID( void ) const { return(mFormationID); }
BOOL setFormationID( int fID );

//Standard update and render functions. Update generates all of the
//decision making within the group. Render is here for graphical
BOOL update( void );
BOOL render( BMatrix& viewMatrix );

//Basic unit addition and removal functions.
BOOL addUnit( int unitID );
BOOL removeUnit( int unitID );
int getNumberUnits( void ) const { return(mNumberUnits); }
int getUnit( int index );

int mID;
int mType;
BVector mCentroid;
float mMaxSpeed;
int mCommanderID;
int mFormationID;
int mNumberUnits;
BVector* mUnitPositions;
BVector* mDesiredPositions;

The BGroup class manages the unit interactions within itself. At any point in time, it should be able to develop a schedule for resolving collisions between its units. It needs to be able to control or modify the unit movement through the use of parameter settings and priority manipulation. If your unit system only has support for one movement priority, you'll want to track a secondary movement priority within the group for each unit in the group. Thus, to the outside world, the group can behave as a single entity with a single movement priority, but still have an internal prioritization. Essentially, the BGroup class is another complete, closed movement system.

The commander of the group is the unit that will be doing the pathfinding for the group. The commander will decide which route the group as a whole will take. For basic group movement, this may not mean much more than the commander being the object that generates the pathfinding call. As we'll see in the next section, though, there's a lot more that the commander can do.

Article Start Page 1 of 3 Next

Related Jobs

Sucker Punch Productions
Sucker Punch Productions — Bellevue, Washington, United States

Senior Camera Programmer
Sucker Punch Productions
Sucker Punch Productions — Bellevue, Washington, United States

Senior Gameplay Programmer
Sucker Punch Productions
Sucker Punch Productions — Bellevue, Washington, United States

Combat Designer
Sucker Punch Productions
Sucker Punch Productions — Bellevue, Washington, United States

Audio Programmer

Loading Comments

loader image