Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / role / PathSign.cs
@小李xl 小李xl on 17 Nov 2022 3 KB 记录玩家走过的位置

using Godot;

/// <summary>
/// 寻路标记, 记录下Role移动过的位置, 用于Ai寻路
/// </summary>
public class PathSign : Node2D, IDestroy
{
    public bool IsDestroyed { get; private set; }
    
    /// <summary>
    /// 当前标记在整个链上的索引
    /// </summary>
    public int Index { get; }

    /// <summary>
    /// 监视的对象
    /// </summary>
    public Role Target { get; }
    
    /// <summary>
    /// 视野半径
    /// </summary>
    public float ViewRadius { get; }

    /// <summary>
    /// 射线对象
    /// </summary>
    public RayCast2D RayCast { get; }

    /// <summary>
    /// 连接的上一个 PathSign
    /// </summary>
    public PathSign Prev { get; set; }

    /// <summary>
    /// 连接的下一个 PathSign
    /// </summary>
    public PathSign Next { get; set; }

    private Vector2 _prevTargetPos;
    
    /// <summary>
    /// 创建标记
    /// </summary>
    /// <param name="pos">坐标</param>
    /// <param name="viewRadius">视野半径</param>
    /// <param name="target">监视对象</param>
    public PathSign(Vector2 pos, float viewRadius, Role target) : this(pos, viewRadius, target, 0, null)
    {
    }

    private PathSign(Vector2 pos, float viewRadius, Role target, int index, PathSign prev)
    {
        Index = index;
        Prev = prev;
        Target = target;
        ViewRadius = viewRadius;
        GameApplication.Instance.Room.GetRoot(false).AddChild(this);
        GlobalPosition = pos;

        //目前只检测墙壁碰撞
        RayCast = new RayCast2D();
        RayCast.CollisionMask = PhysicsLayer.Wall;
        AddChild(RayCast);

        //绘制箭头
        if (GameApplication.Instance.Debug)
        {
            var sprite = new Sprite();
            sprite.Texture = ResourceManager.Load<Texture>(ResourcePath.resource_effects_debug_arrows_png);
            sprite.Position = new Vector2(0, -sprite.Texture.GetHeight() * 0.5f);
            AddChild(sprite);
        }
    }

    public override void _Process(float delta)
    {
        base._Process(delta);
        if (GameApplication.Instance.Debug)
        {
            Update();
        }
    }

    public override void _PhysicsProcess(float delta)
    {
        if (Next == null)
        {
            //监视目标
            var targetPos = Target.GlobalPosition;
            if (GlobalPosition.DistanceSquaredTo(targetPos) <= ViewRadius * ViewRadius) //在视野范围内
            {
                RayCast.Enabled = true;
                RayCast.CastTo = RayCast.ToLocal(targetPos);
                RayCast.ForceRaycastUpdate();

                if (RayCast.IsColliding())
                {
                    Next = new PathSign(_prevTargetPos, ViewRadius, Target, Index + 1, this);
                }
                RayCast.Enabled = false;
                _prevTargetPos = targetPos;
            }
        }
    }

    public void Destroy()
    {
        if (IsDestroyed)
        {
            return;
        }

        IsDestroyed = true;

        if (Next != null)
        {
            Next.Destroy();
        }

        QueueFree();
    }

    public override void _Draw()
    {
        if (GameApplication.Instance.Debug)
        {
            if (Next != null)
            {
                DrawLine(Vector2.Zero,ToLocal(Next.GlobalPosition), Colors.Red);
            }
        }
    }
}