How to Make Marching Formation for RTS Units

RTS game army formation

In previous tutorial, we created a warrior unit (a soldier). But if we select multiple such units, they do not follow ordered movement. So in this post, I will talk about many approaches to formations.

In real world, contingents of army stay ordered because each soldier steers himself to adjust his position among other soldiers. The overall effect, when all the soldiers do this, is that a formation system is created. Also, there could be many types of formations such as line, square, winged and so on.

In computer, this kind of self-adjustment is called steering behaviors. But it is complex. We use simpler approaches in games that are often math-based.

Breakdown of Unit Formation

There are some possible approaches:

  1. Approach 1: When multiple units are selected, calculate their average position by adding the position of all the units divided by the number of units. Let assume that there exists a group leader at the average position. Now calculate path from average position to the destination. This path is for the hypothetical group leader. For each (real) selected unit, set its position to be an offset from the group leader’s position. This offset is calculated based on the type of formation (square, line, etc).
  2. Approach 2: Set one of the units to be the group leader. All other units will have their path same as the group leader, but with an offset. This offset again is calculated based on the type of formation.

Implementing Unit Formations

The cleaner way, in my opinion is that we make marching as a separate state, or that we extend the Warrior class to make MarchingWarrior, that adds this additional state & manage it accordingly. The condition for this state will be when multiple units are selected.

But, in my own implementation, I used a hacky way, that is, I overwritten the path of individual units to be the path of 1st unit, but with offset. This is not recommended. But the main thing I will focus on is the idea of offset around some central position.

# implement marching function
func calculate_formation_path_as_if_marching(selected_units: Array):
	# if leader, return
	if selected_units[0] == self:
		return
	
	# else calculate path as offset from leader, such that the formation is maintained as square
	var leader = selected_units[0]
	var leader_pos = leader.global_position
	
	# Calculate offset from leader so it makes a square formation
	var n = int(sqrt(selected_units.size()))
	var current_unit_index = selected_units.find(self)
	var offset = calculate_offset_for_index(current_unit_index, n, 8.0)
	
	# Assign our path as the path of agent, but all points offsetted to given offset
	current_agent_path.clear()
	for i in range(leader.current_agent_path.size()):
		var point = leader.current_agent_path[i]
		var new_point = point + offset
		current_agent_path.append(new_point)


# a function to loop n times, and calculate the offset for given index in square formation
func calculate_offset_for_index(index: int, n: int, separation: float):
	var offset = Vector3(0, 0, 0)
	var row = int(index / n)
	var col = index % n
	var row_offset = row * separation
	var col_offset = col * separation
	offset.x = col_offset
	offset.z = row_offset
	return offset

In above code, I set the 1st unit among the selected_units to be the leader, and it calculates its path normally. Rest of the units use calculate_offset_for_index function to calculate their offset from the group leader. This function takes the index of the current unit whose offset is being calculated from the group leader.

Another approach that I think is used in Age of Empires is that they assume a hypothetical group leader, whose position is calculated to be the average position of all the selected_units. Then path will be calculated from his position to the destination, and all real units will just have an offset from that group leader.

Other Useful Sources

I found a very descent discussion on github & on unity forums as well. These discussions talk about the approaches in detail & are worth looking.

Leave a Reply

Your email address will not be published. Required fields are marked *