🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Handling crowd collision detection

Started by
3 comments, last by Neoptolemus 3 years, 7 months ago

Hi everyone,

I'm working with Unreal Engine 4, and I am trying to get a large-scale battle system in place, similar to Total War. Armies will comprise several dozen companies, each containing 200 individual soldiers.

So far, I have managed to get 10k animated soldiers on screen at once with good fps (100fps on a GTX 1080 at 1440p), and I have ditched the use of movement components, instead projecting each soldier onto the navigation mesh to make sure they align with the floor and limiting their movement to it so can't move through solid objects (thereby negating the need to check for environment collisions). Finally, I am using asynchronous hierarchical pathfinding, which allows me to have each individual soldier do their own pathfinding if necessary without causing hitching.

Where I am now stuck a little bit is on how to stop them phasing through each other. I was looking at a flocking algorithm of some sort, but I am not getting the results I need. The game is set during the Napoleonic era, so it is anticipated that soldiers will march in columns and ranks for the most part, and therefore I think I can ditch the cohesion and alignment parts of the algorithm because each soldier will have a specific space in the formation they should stand in, and unless their path is blocked they should just move to that position each time.

The flocking algorithms I've been looking at suggest that for each soldier in the company, I should do something like this:

FVector MySoldierClass::CalculateVelocity()
{
	FVector Velocity = FVector(0,0,0);
	FVector DesiredMoveDir = (PlaceInFormation - this->Location).GetSafeNormal();
	
	FVector SeparationDir = CalcSeparation();
	
	Velocity = DesiredMoveDir += SeparationDir;
	Velocity = Velocity.GetSafeNormal() * MovementSpeed;
	
	return Velocity;

}

FVector MySoldierClass::CalcSeparation()
{
	FVector SepDir = FVector(0,0,0);
	int32 CollisionCount = 0;
	for (MySoldierClass* CheckSoldier : OtherSoldiers)
	{
		if (CheckSoldier != this)
		{
			float Dist = FVector::Distance(this->Location, CheckSoldier->Location);
			
			if (Dist < MinimumSpacing)
			{
				CollisionCount = 0;
				FVector ThisSepDir = (this->Location - CheckSoldier->Location).GetSafeNormal();
				SepDir += ThisSepDir;
			}
		}
	}
	
	if (CollisionCount > 0)
	{
		SepDir /= CollisionCount;
		SepDir.Normalize();
	}
	
	return SepDir;
}

However, this causes all my soldiers to start marching off at an angle. Not sure what I'm doing wrong here, or if the flocking algorithm isn't right for what I want to achieve. All I really want is for soldiers to avoid each other and not clip inside each other when moving around. Maybe there is something really obvious I'm missing?

Thanks!

Advertisement

You don't seem to increment CollisionCount, which implies never normalizing SepDir.

EDIT: SepDir /= CollisionCount; is completely redundant if you then normalize SepDir.

How do you determine OtherSoldiers? Could it be empty or otherwise incorrect?

Omae Wa Mou Shindeiru

You don't have to normalize SepDir and DesiredMoveDir: the lengths of the two vectors represent the variable importance of the two behaviours (more separation with more non-conflicting close neighbours, more arrival if the destination is unusually far).
The only thing that has to be normalized is the physically constrained walking speed.

Omae Wa Mou Shindeiru

@LorenzoGatti Hi Lorenzo!

I was incrementing CollisionCount correctly in my actual code, but I must have accidentally omitted it when I was typing up the abridged version in my original post. The critical mistake however was in my actual code though, where I was ADDING MovementSpeed rather than multiplying by it, which is why they all marched off at an angle. Oops :(

It all seems to be working now. I normalise DesiredMoveDir still though because I want the soldiers to be able to potentially stray quite a distance from their desired position in the formation, either due to poor discipline in less well-trained units, or due to enemy action such as a cavalry charge. However, I no longer normalise ThisSepDir so that deeper overlaps with nearby soldiers weight the movement more heavily.

Thank you for the reply ? I will continue to tweak this until it's exactly how I want it.

This topic is closed to new replies.

Advertisement