Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / role / ai / state / AiFollowUpState.cs

using System;
using Godot;

namespace AiState;

/// <summary>
/// 目标在视野内, 跟进目标, 如果距离在子弹有效射程内, 则开火
/// </summary>
public class AiFollowUpState : StateBase<AiRole, AIStateEnum>
{
    //导航目标点刷新计时器
    private float _navigationUpdateTimer = 0;
    private float _navigationInterval = 0.3f;

    public AiFollowUpState() : base(AIStateEnum.AiFollowUp)
    {
    }

    public override void Enter(AIStateEnum prev, params object[] args)
    {
        if (Master.LookTarget == null)
        {
            ChangeState(AIStateEnum.AiNormal);
            return;
            //throw new Exception("进入 AIAdvancedStateEnum.AiFollowUp 状态时角色没有攻击目标!");
        }
        
        _navigationUpdateTimer = 0;
    }

    public override void Process(float delta)
    {
        //先检查弹药是否打光
        if ((Master.WeaponPack.Capacity > 0 && !Master.NoWeaponAttack) && Master.IsAllWeaponTotalAmmoEmpty())
        {
            //再寻找是否有可用的武器
            var targetWeapon = Master.FindTargetWeapon();
            if (targetWeapon != null)
            {
                ChangeState(AIStateEnum.AiFindAmmo, targetWeapon);
                return;
            }
            else
            {
                //切换到随机移动状态
                ChangeState(AIStateEnum.AiSurround);
            }
        }

        var playerPos = Master.LookTarget.GetCenterPosition();

        //更新玩家位置
        if (_navigationUpdateTimer <= 0)
        {
            //每隔一段时间秒更改目标位置
            _navigationUpdateTimer = _navigationInterval;
            Master.NavigationAgent2D.TargetPosition = playerPos;
        }
        else
        {
            _navigationUpdateTimer -= delta;
        }

        //是否在攻击范围内
        var inAttackRange = false;

        var weapon = Master.WeaponPack.ActiveItem;
        var distanceSquared = Master.Position.DistanceSquaredTo(playerPos);
        if (weapon != null)
        {
            inAttackRange = distanceSquared <= Mathf.Pow(Master.GetWeaponRange(0.7f), 2);
        }
        else
        {
            inAttackRange = distanceSquared <= Mathf.Pow(Master.ViewRange * 0.7f, 2);
        }
        
        if (!Master.NavigationAgent2D.IsNavigationFinished())
        {
            //移动
            Master.DoMove();
        }
        else
        {
            //站立
            Master.DoIdle();
        }

        //在视野中
        if (Master.TargetInView)
        {
            //更新标记位置
            Master.UpdateMarkTargetPosition();
            if (inAttackRange) //在攻击范围内
            {
                if (weapon != null)
                {
                    //距离够近, 可以切换到环绕模式
                    if (distanceSquared <= Mathf.Pow(Utils.GetConfigRangeStart(weapon.Attribute.Bullet.DistanceRange) * 0.7f, 2))
                    {
                        ChangeState(AIStateEnum.AiSurround);
                    }
                    else if (!Master.IsAttack && weapon.TriggerIsReady()) //可以攻击
                    {
                        //攻击状态
                        ChangeState(AIStateEnum.AiAttack);
                    }
                }
                else
                {
                    //距离够近, 可以切换到环绕模式
                    if (distanceSquared <= Mathf.Pow(Master.ViewRange * 0.7f, 2))
                    {
                        ChangeState(AIStateEnum.AiSurround);
                    }
                    else if (!Master.IsAttack && Master.NoWeaponAttack) //可以在没有武器时发起攻击
                    {
                        //攻击状态
                        ChangeState(AIStateEnum.AiAttack);
                    }
                }
            }
        }
        else //不在视野中
        {
            ChangeState(AIStateEnum.AiTailAfter);
        }
    }

    public override void DebugDraw()
    {
        var playerPos = Master.LookTarget.GetCenterPosition();
        Master.DrawLine(new Vector2(0, -8), Master.ToLocal(playerPos), Colors.Red);
    }
}