start.x += originOffset;
start.y += originOffset;
goal.x += originOffset;
goal.y += originOffset;
List<Vector2> list = base.FindPath(TileWorldUtils.Floor(start), TileWorldUtils.Floor(goal), parameters);
for (int i = list.Count - 1; i >= 0; i--)
{
Vector2 vector = list[i];
vector.x += 0.5f - originOffset;
vector.y += 0.5f - originOffset;
list[i] = vector;
}
return list;
暂时还是不很理解其中的含义,看具体用起来是怎么个效果吧。
仔细看了之后,发现其实它并不是通过寻路分开单位,而是去计算碰撞,通过碰撞分离所有单位。
public class EntityPosition : EntityComponent
{
// Fields
protected Vector3 center;
private Vector3 centerOffset;
private int collidableRetainCount = 1;
private Vector2 collisionForce;
private const float DECOLLISION_SEPARATION = 0.0625f;
private const float MIN_PENETRATION = 0.2f;
private float tileRadius;
public float Weight;
// Events
public event Action GivenUpTiles;
public event Action<EntityPosition> Moved;
public event Action PreUpdateTiles;
// Methods
public EntityPosition()
{
this.UpdateTiles = true;
this.Facing = Vector3.get_down();
}
private void AnnouceMoved()
{
if (this.Moved != null)
{
this.Moved(this);
}
}
public void ApplyCollisionForces(float deltaTime)
{
if ((this.collisionForce.x != 0f) || (this.collisionForce.y != 0f))
{
this.Translate(new Vector3(this.collisionForce.x * 0.0625f, this.collisionForce.y * 0.0625f));
}
}
public void CalCollisionForces()
{
this.collisionForce.Set(0f, 0f);
if (this.Collidable)
{
bool flying = this.Flying;
Vector2 vector = new Vector2(this.Center.x, this.Center.y);
int x = Mathf.FloorToInt(vector.x);
TileContainer container = base.Tiles.Get(x, Mathf.FloorToInt(vector.y));
if (container != null)
{
int collidableGroup = container.GetCollidableGroup(base.Template.physicalRadius + 0.7071068f);
List<TileEntity> list = container.CollidableEntityDistanceGroups[collidableGroup];
int num2 = 0;
int count = list.Count;
while (num2 < count)
{
TileEntity entity = list[num2];
if (entity != base.entity)
{
EntityPosition position = entity.Position;
if (position.Collidable && (position.Flying == flying))
{
Vector2 vector2 = new Vector2(position.Center.x, position.Center.y);
float num4 = this.PhysicalRadius + position.PhysicalRadius;
float num5 = num4 * num4;
Vector2 vector3 = vector2 - vector;
float num6 = vector3.SqrMagnitude();
if (num6 <= 0f)
{
float @float = base.World.Random.GetFloat();
this.collisionForce.x += Mathf.Sign(@float * 10000f) * 0.0625f;
this.collisionForce.y += ((@float * 2f) - 1f) * 0.0625f;
}
else if (num6 < num5)
{
float num8 = Mathf.Sqrt(num6);
float num9 = num4 - num8;
if (num9 < 0.2f)
{
num9 = 0.2f;
}
float num10 = num9 / num8;
if (position.Weight <= 0f)
{
num10 *= 5f;
}
else
{
num10 *= position.Weight;
}
vector3 = (Vector2) (vector3 * num10);
this.collisionForce -= vector3;
}
}
}
num2++;
}
if (this.Weight != 0f)
{
this.collisionForce = (Vector2) (this.collisionForce / this.Weight);
}
}
}
}
public void FacePosition(Vector3 targetPos)
{
this.FaceVector(targetPos - base.CenterPosition, false);
}
public void FaceToTarget()
{
if (this.TargetEntity != null)
{
this.FacePosition(this.TargetEntity.CenterPosition);
}
}
public void FaceVector(Vector3 targetVector, bool includeZ = false)
{
if (includeZ)
{
if (targetVector != Vector3.get_zero())
{
this.Facing = targetVector.get_normalized();
}
}
else if ((targetVector.x != 0f) || (targetVector.y != 0f))
{
targetVector.z = 0f;
this.Facing = targetVector.get_normalized();
}
}
public void ForEachTileAroundCenterPosition(Vector3 centerPosition, Action<TileContainer> callback)
{
int num = Mathf.FloorToInt(centerPosition.x - this.tileRadius);
int num2 = Mathf.FloorToInt(centerPosition.y - this.tileRadius);
float num3 = this.tileRadius * 2f;
float num4 = num + num3;
float num5 = num2 + num3;
for (int i = num; i < num4; i++)
{
for (int j = num2; j < num5; j++)
{
TileContainer container = base.Tiles.Get(i, j);
if (container != null)
{
callback(container);
}
}
}
}
public float GetDistance(TileEntity entity)
{
return Vector3.Distance(this.Center, entity.CenterPosition);
}
public float GetDistance(Vector3 pos)
{
return Vector3.Distance(this.Center, pos);
}
public float GetDistanceFromOuter(Vector3 pos)
{
return (this.GetDistance(pos) - this.PhysicalRadius);
}
public float GetDistanceSquared(TileEntity entity)
{
return Vector3.SqrMagnitude(this.Center - entity.CenterPosition);
}
public float GetDistanceToOuter(TileEntity entity)
{
return (this.GetDistance(entity) - entity.Position.PhysicalRadius);
}
public Vector3 GetTopLeftFrom(Vector3 centerParm)
{
return (centerParm - this.centerOffset);
}
public void GiveUpTiles()
{
if (this.UpdateTiles)
{
this.UnregisterFromTileContainers();
this.UpdateTiles = false;
if (this.GivenUpTiles != null)
{
this.GivenUpTiles();
}
}
}
public bool IsCenterPositionWithinTileBounds(Vector3 centerPosition)
{
int x = Mathf.FloorToInt(centerPosition.x - this.tileRadius);
int y = Mathf.FloorToInt(centerPosition.y - this.tileRadius);
int num3 = Mathf.CeilToInt(this.tileRadius * 2f) - 1;
return (base.Tiles.InRange(x, y) && base.Tiles.InRange(x + num3, y + num3));
}
public bool IsInRange(TileEntity entity, float distance)
{
return (Vector3.SqrMagnitude(this.Center - entity.CenterPosition) <= (distance * distance));
}
public bool IsInRange(Vector3 pos, float distance)
{
return (Vector3.SqrMagnitude(this.Center - pos) <= (distance * distance));
}
public bool IsInRangeFromOuter(Vector3 pos, float distance)
{
distance -= this.PhysicalRadius;
return (Vector3.SqrMagnitude(this.Center - pos) <= (distance * distance));
}
public bool IsTileWithinBounds(int tileX, int tileY)
{
int num = Mathf.FloorToInt(this.center.x - this.tileRadius);
int num2 = Mathf.FloorToInt(this.center.y - this.tileRadius);
float num3 = this.tileRadius * 2f;
return ((((tileX >= num) && (tileX < (num + num3))) && (tileY >= num2)) && (tileY < (num2 + num3)));
}
public override void OnRemoved()
{
base.OnRemoved();
this.UnregisterFromTileContainers();
if (this.Weight > 0f)
{
base.World.Decollider.Remove(this);
}
}
public override void PopulateToLayoutTO(LayoutEntity to)
{
Vector3 topLeft = this.TopLeft;
to.x = topLeft.x;
to.y = topLeft.y;
}
public void ReleaseCollider()
{
this.collidableRetainCount--;
}
public void RetainCollider()
{
this.collidableRetainCount++;
}
private void SafePosition()
{
this.center.x = SAMath.Round(this.center.x, 2);
this.center.y = SAMath.Round(this.center.y, 2);
this.center.z = SAMath.Round(this.center.z, 2);
}
public void SetCenterPosition(Vector3 p)
{
this.center = p;
this.SafePosition();
if (base.entity != null)
{
this.UpdateTileContainers(null, false);
this.AnnouceMoved();
}
}
public void SetCenterPosition(float x, float y, float z = 0)
{
this.center.x = x;
this.center.y = y;
this.center.z = z;
this.SafePosition();
if (base.entity != null)
{
this.UpdateTileContainers(null, false);
this.AnnouceMoved();
}
}
public override void SetParent(TileEntity parent)
{
base.SetParent(parent);
this.PhysicalRadius = base.Template.physicalRadius;
this.tileRadius = 0.1f;
BuildingTemplate templateAsBuilding = base.TemplateAsBuilding;
if (templateAsBuilding != null)
{
this.TileWidth = templateAsBuilding.width;
this.TileHeight = templateAsBuilding.height;
int num = Mathf.Max(1, this.TileWidth);
int num2 = Mathf.Max(1, this.TileHeight);
this.centerOffset = new Vector3(num * 0.5f, num2 * 0.5f, 0f);
this.center += this.centerOffset;
if ((this.TileWidth > 0) && (this.TileHeight > 0))
{
this.tileRadius = Mathf.Sqrt((float) (this.TileWidth * this.TileHeight)) / 2f;
}
else
{
this.tileRadius = Mathf.Max(this.tileRadius, this.PhysicalRadius);
}
}
else
{
if (base.Template is TroopTemplate)
{
this.FlightHeight = base.TemplateAsTroop.flightHeight;
this.center.z += this.FlightHeight;
if (this.PhysicalRadius > 0f)
{
this.Weight = 1f;
}
}
else if (base.Template is ProjectileTemplate)
{
this.UpdateTiles = false;
}
this.tileRadius = Mathf.Max(this.tileRadius, this.PhysicalRadius);
}
if (this.Weight > 0f)
{
base.World.Decollider.Add(this);
}
this.SafePosition();
if (this.PhysicalRadius == 0f)
{
this.ReleaseCollider();
}
this.AllTileContainers = new List<TileContainer>(Mathf.CeilToInt(Mathf.Pow(this.tileRadius * 2f, 2f)));
this.UpdateTileContainers(null, true);
}
public void SetTopLeftPosition(float x, float y, float z = 0)
{
this.center.x = x + this.centerOffset.x;
this.center.y = y + this.centerOffset.y;
this.center.z = z + this.centerOffset.z;
this.SafePosition();
if (base.entity != null)
{
this.UpdateTileContainers(null, false);
this.AnnouceMoved();
}
}
public void TakeUpTiles()
{
if (!this.UpdateTiles)
{
this.UpdateTiles = true;
this.UpdateTileContainers(null, false);
}
}
public void Translate(Vector3 v)
{
Vector3? previousPosition = null;
if (v.get_sqrMagnitude() < 2f)
{
previousPosition = new Vector3?(this.center);
}
this.center += v;
this.SafePosition();
this.UpdateTileContainers(previousPosition, false);
this.AnnouceMoved();
}
public void TranslateWithCollisions(Vector3 v)
{
Vector3? previousPosition = null;
if (v.get_sqrMagnitude() < 2f)
{
previousPosition = new Vector3?(this.center);
}
this.center += v;
this.SafePosition();
this.UpdateTileContainers(previousPosition, false);
this.CalCollisionForces();
this.ApplyCollisionForces(0f);
}
private void UnregisterFromTileContainers()
{
for (int i = this.AllTileContainers.Count - 1; i >= 0; i--)
{
this.AllTileContainers[i].RemoveEntity(base.entity);
}
this.AllTileContainers.Clear();
}
private void UpdateTileContainers(Vector3? previousPosition = new Vector3?(), bool addOnly = false)
{
if (this.UpdateTiles)
{
int num2;
int num3;
int num4;
int num5;
if (this.PreUpdateTiles != null)
{
this.PreUpdateTiles();
}
float num = this.tileRadius + base.World.Tiles.BiggestPathfinderRadius;
if (previousPosition.HasValue)
{
Vector3 vector = previousPosition.Value;
num2 = Mathf.FloorToInt(Mathf.Min(this.center.x, vector.x) - num);
num3 = Mathf.FloorToInt(Mathf.Min(this.center.y, vector.y) - num);
num4 = Mathf.FloorToInt(Mathf.Max(this.center.x, vector.x) + num);
num5 = Mathf.FloorToInt(Mathf.Max(this.center.y, vector.y) + num);
}
else
{
this.UnregisterFromTileContainers();
num2 = Mathf.FloorToInt(this.center.x - num);
num3 = Mathf.FloorToInt(this.center.y - num);
num4 = Mathf.FloorToInt(this.center.x + num);
num5 = Mathf.FloorToInt(this.center.y + num);
}
float num6 = (num3 + 0.5f) - this.center.y;
float num7 = num6 * num6;
float num8 = (2f * num6) + 1f;
int y = num3;
while (y <= num5)
{
float num10 = (num2 + 0.5f) - this.center.x;
float num11 = num10 * num10;
float num12 = (2f * num10) + 1f;
int x = num2;
while (x <= num4)
{
TileContainer item = base.Tiles.Get(x, y);
if (item != null)
{
switch (item.UpdateCollidableEntity(base.entity, num11 + num7, addOnly))
{
case TileContainer.UpdateCollidableResult.Added:
this.AllTileContainers.Add(item);
break;
case TileContainer.UpdateCollidableResult.Removed:
goto Label_01E6;
}
}
goto Label_01F9;
Label_01E6:
this.AllTileContainers.Remove(item);
Label_01F9:
x++;
num10++;
num11 += num12;
num12 += 2f;
}
y++;
num6++;
num7 += num8;
num8 += 2f;
}
}
}
// Properties
public List<TileContainer> AllTileContainers { get; protected set; }
public Vector3 Center
{
get
{
return this.center;
}
}
public bool Collidable
{
get
{
return (this.collidableRetainCount > 0);
}
}
public Vector3 Facing { get; private set; }
public float FlightHeight { get; private set; }
public bool Flying
{
get
{
return (this.FlightHeight > 0f);
}
}
public float PhysicalRadius { get; private set; }
public TilePosition Tile
{
get
{
Vector3 topLeft = this.TopLeft;
return new TilePosition((int) topLeft.x, (int) topLeft.y);
}
}
public int TileHeight { get; private set; }
public int TileWidth { get; private set; }
public Vector3 TopLeft
{
get
{
return this.GetTopLeftFrom(this.center);
}
}
public bool UpdateTiles { get; private set; }
}