(61d00a474) v0.9.7.1
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
using FarseerPhysics;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
class SwarmBehavior
|
||||
{
|
||||
private readonly float minDistFromClosest;
|
||||
private readonly float maxDistFromCenter;
|
||||
private readonly float cohesion;
|
||||
|
||||
public List<AICharacter> Members { get; private set; } = new List<AICharacter>();
|
||||
public HashSet<AICharacter> ActiveMembers { get; private set; } = new HashSet<AICharacter>();
|
||||
|
||||
private EnemyAIController ai;
|
||||
|
||||
public bool IsActive { get; set; }
|
||||
public bool IsEnoughMembers => ActiveMembers.Count > 1;
|
||||
|
||||
|
||||
public SwarmBehavior(XElement element, EnemyAIController ai)
|
||||
{
|
||||
this.ai = ai;
|
||||
minDistFromClosest = ConvertUnits.ToSimUnits(element.GetAttributeFloat("mindistfromclosest", 10.0f));
|
||||
maxDistFromCenter = ConvertUnits.ToSimUnits(element.GetAttributeFloat("maxdistfromcenter", 1000.0f));
|
||||
cohesion = element.GetAttributeFloat("cohesion", 1) / 10;
|
||||
}
|
||||
|
||||
public static void CreateSwarm(IEnumerable<AICharacter> swarm)
|
||||
{
|
||||
var aiControllers = new List<EnemyAIController>();
|
||||
foreach (AICharacter character in swarm)
|
||||
{
|
||||
if (character.AIController is EnemyAIController enemyAI && enemyAI.SwarmBehavior != null)
|
||||
{
|
||||
aiControllers.Add(enemyAI);
|
||||
}
|
||||
}
|
||||
var filteredMembers = aiControllers.Select(m => m.Character as AICharacter).Where(m => m != null);
|
||||
foreach (EnemyAIController ai in aiControllers)
|
||||
{
|
||||
ai.SwarmBehavior.Members = filteredMembers.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
Members.RemoveAll(m => m.IsDead || m.Removed || m.AIController is EnemyAIController ai && ai.State == AIState.Flee);
|
||||
foreach (var member in Members)
|
||||
{
|
||||
if (!member.AIController.Enabled && member.IsRemotePlayer || Character.Controlled == member || !((EnemyAIController)member.AIController).SwarmBehavior.IsActive)
|
||||
{
|
||||
ActiveMembers.Remove(member);
|
||||
}
|
||||
else
|
||||
{
|
||||
ActiveMembers.Add(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSteering(float deltaTime)
|
||||
{
|
||||
if (!IsActive) { return; }
|
||||
if (!IsEnoughMembers) { return; }
|
||||
//calculate the "center of mass" of the swarm and the distance to the closest character in the swarm
|
||||
float closestDistSqr = float.MaxValue;
|
||||
Vector2 center = Vector2.Zero;
|
||||
AICharacter closest = null;
|
||||
foreach (AICharacter member in Members)
|
||||
{
|
||||
center += member.SimPosition;
|
||||
if (member == ai.Character) { continue; }
|
||||
float distSqr = Vector2.DistanceSquared(member.SimPosition, ai.Character.SimPosition);
|
||||
if (distSqr < closestDistSqr)
|
||||
{
|
||||
closestDistSqr = distSqr;
|
||||
closest = member;
|
||||
}
|
||||
}
|
||||
center /= Members.Count;
|
||||
|
||||
if (closest == null) { return; }
|
||||
|
||||
//steer away from the closest if too close
|
||||
float closestDist = (float)Math.Sqrt(closestDistSqr);
|
||||
if (closestDist < minDistFromClosest)
|
||||
{
|
||||
Vector2 diff = closest.SimPosition - ai.SimPosition;
|
||||
if (diff.LengthSquared() < 0.0001f)
|
||||
{
|
||||
diff = Vector2.UnitX;
|
||||
}
|
||||
ai.SteeringManager.SteeringManual(deltaTime, -diff);
|
||||
}
|
||||
//steer closer to the center of mass if too far
|
||||
else if (Vector2.DistanceSquared(center, ai.SimPosition) > maxDistFromCenter * maxDistFromCenter)
|
||||
{
|
||||
float distFromCenter = Vector2.Distance(center, ai.SimPosition);
|
||||
ai.SteeringManager.SteeringSeek(center, (distFromCenter - maxDistFromCenter) / 10.0f);
|
||||
}
|
||||
|
||||
//keep the characters moving in roughly the same direction
|
||||
if (cohesion > 0.0f)
|
||||
{
|
||||
Vector2 avgVel = Vector2.Zero;
|
||||
foreach (AICharacter member in Members)
|
||||
{
|
||||
avgVel += member.AnimController.TargetMovement;
|
||||
}
|
||||
avgVel /= Members.Count;
|
||||
ai.SteeringManager.SteeringManual(deltaTime, avgVel * cohesion);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user