群体寻路研究

 int originOffset = this.tiles.OriginOffset;
    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; }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yxriyin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值