Unity 网格导航围绕目标做圆周运动

 描述当AI发现玩家时,不会立马发动攻击,则会在玩家周围进行圆周运动(漫步),等待足够长时间后发动攻击,

效果图

其中用LineRederer来绘制轨迹

话不多说直接上代码

using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UI;

public class AiCM : MonoBehaviour
{
    [Header("时间尺")]
    [Range(0, 4)]
    public float scale;
    public int framRate=30;

    [Header("显示")]
    public Text txt_velocity;
    public Text txt_Distance;

    public Vector3 direction;
    public Vector3 rotaionDirection;
    /// <summary>
    /// 基础速度
    /// </summary>
    [Header("漫步")]
    public float speed = 3f;
    /// <summary>
    /// 徘徊半径
    /// </summary>
    public float wanderRadius = 2f;
    /// <summary>
    /// 徘徊最大距离
    /// </summary>
    public float wanderDistance = 4f;

    /// <summary>
    /// 徘徊的目标
    /// </summary>
    public Transform Target;
    /// <summary>
    /// 周期 =  2PI v /v
    /// </summary>
    public float CycleT;
    /// <summary>
    /// 角速度 = 2pi / T
    /// </summary>
    public float angleSpeed;
    /// <summary>
    /// 反转方向
    /// <para>真 逆时针 假 顺时针</para>
    /// </summary>
    public bool inverse;
    public float angle; 
    public float intervalTime = 3f;
    public Vector3 oldDirection;
    public Vector3 currentDirection;


    private float runIntervalTime;
    private float currentTime;
    private bool _wanderFlag;
    private Transform currentTarget;
     
    NavMeshAgent Agent;
    CharacterController cc;

    void Start()
    {
        cc = GetComponent<CharacterController>();
        Agent = GetComponent<NavMeshAgent>();

        Application.targetFrameRate = framRate;
    }

    // Update is called once per frame
    void Update()
    {
        if (scale != Time.timeScale)
        {
            Time.timeScale = scale;
        }
        if(wanderRadius >= wanderDistance)
        {
            wanderRadius = wanderDistance - 0.5f;
        }


        MoveToTarget();
   


        #region 朝向旋转部分

        if (!_wanderFlag)
        {
            rotaionDirection = Agent.desiredVelocity;
        }
        else
        {
            rotaionDirection = (currentTarget.position - transform.position);
        }
        var dir = Vector3.ProjectOnPlane(rotaionDirection, transform.up).normalized;
        var roa = Quaternion.LookRotation(dir, transform.up);
        transform.rotation = Quaternion.Slerp(transform.rotation, roa, 1 - Mathf.Exp(-10 * Time.deltaTime));

        #endregion

      
  

        cc.Move(new Vector3(direction.x, 0, direction.z) * 2 * speed * Time.deltaTime);


        if (txt_velocity) txt_velocity.text = cc.velocity.magnitude.ToString("#0.00");
        if (txt_Distance) txt_Distance.text = Vector3.Distance(transform.position, currentTarget.position).ToString("#0.00");
    }

   

    void MoveToTarget()
    {
        currentTarget = Target;
        if (Agent.pathPending)
        {
            Debug.Log($"计算路程中 丢弃这帧{Time.frameCount}");
            return;
        }



        if ((Target.position - transform.position).sqrMagnitude > (wanderDistance + 1) * (wanderDistance + 1))
        {
            Agent.isStopped = false;
            Agent.SetDestination(currentTarget.position);
            direction = Agent.desiredVelocity;
            _wanderFlag = false;
            
        }

        else if (Agent.remainingDistance <= wanderDistance &&!_wanderFlag)
        {
            Agent.ResetPath();
            Agent.isStopped = true;
            direction = Vector3.zero;
            _wanderFlag = true;

            angle = 0;
        }
        if (_wanderFlag)
        {
            if (Time.time - currentTime > runIntervalTime)
            { 
                inverse ^= true;
                runIntervalTime = Random.Range(intervalTime, intervalTime + 3f);
                currentTime = Time.time;
            }
            float runRadius = wanderRadius;

            //计算周期
            CycleT = (2 * Mathf.PI * runRadius) / (speed);// Random.Range(wanderRadius, wanderRadius + 1f);

            if (CycleT == 0) return;

            //计算角速度
            angleSpeed = (2 * Mathf.PI / CycleT)*2  ;
          
            angle += (angleSpeed * (inverse ? 1 : -1)) * Time.deltaTime;//累加已经转过的角度

            float posX = (runRadius * Mathf.Sin(angle   )) + Target.position.x;//计算x位置
            float posZ = (runRadius * Mathf.Cos(angle  )) + Target.position.z;//计算y位置 

            Vector3 dir = new Vector3(posX, 0, posZ);
             
            Agent.isStopped = false;
            Agent.SetDestination(dir);
            direction = Agent.desiredVelocity; 
        }
        direction.Normalize();
    }



}

面板信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值