You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity飞行AI追逐正常,触发避障时出现抖动问题求助

Unity飞行AI避障时抖动问题修复方案

开发Unity飞行AI时,单纯追逐目标功能正常,但添加避障系统后,触发避障时AI出现明显抖动。通过调试确认,抖动根源是AI在追逐状态和避障状态之间频繁切换。

原代码问题分析

  1. 无状态切换缓冲:每帧通过Physics.SphereCast检测障碍,某帧未检测到就立即切回追逐,导致状态在两帧间反复跳转。
  2. 避障方向计算不合理:Vector3.Cross(hit.point, hit.normal)生成的避让方向未结合原追逐路径,且未做归一化,导致移动方向突变。
  3. 移动方式生硬:直接使用Vector3.MoveTowards设置位置,两种状态的移动方向没有平滑过渡,加剧抖动。

修复方案及修改后代码

通过添加状态缓冲、优化避障方向计算、实现平滑移动过渡来解决问题:

using Cinemachine;
using UnityEngine;

public class EnemyNew : MonoBehaviour
{
    [Header("Settings")]
    public int HP;
    public float speed;
    public float detectionRadius;
    public int gunsCount;
    public Vector3 stoppingDistance;
    public LayerMask obstacleLayer;
    [Tooltip("连续检测到障碍的帧数阈值,达到后才触发避障")]
    public int obstacleDetectThreshold = 2;
    [Tooltip("连续未检测到障碍的帧数阈值,达到后才切回追逐")]
    public int obstacleClearThreshold = 3;
    [Tooltip("避障方向与原追逐方向的混合权重,0=完全追逐,1=完全避障")]
    public float avoidanceWeight = 0.7f;
    
    [HideInInspector] public bool alive;
    [HideInInspector] public float distance;
    
    [Header("Components")]
    public Rocket target;
    private AudioSource audioSource;
    
    // 状态缓冲相关变量
    private int obstacleDetectCount = 0;
    private bool isAvoiding = false;

    void Start()
    {
        alive = true;
        audioSource = GetComponent<AudioSource>();
    }

    void FixedUpdate()
    {
        if (!alive || !target?.isAlive ?? false) return;
        
        distance = Vector3.Distance(transform.position, target.transform.position);
        if (distance > 100) return;

        Vector3 chaseDirection = (target.transform.position + stoppingDistance - transform.position).normalized;
        bool obstacleDetected = Physics.SphereCast(transform.position, transform.localScale.magnitude, chaseDirection, out RaycastHit hit, detectionRadius, obstacleLayer);

        // 状态缓冲逻辑,避免单帧误判导致状态跳变
        if (obstacleDetected)
        {
            obstacleDetectCount++;
            if (obstacleDetectCount >= obstacleDetectThreshold)
            {
                isAvoiding = true;
            }
        }
        else
        {
            obstacleDetectCount--;
            if (obstacleDetectCount <= 0)
            {
                isAvoiding = false;
                obstacleDetectCount = 0;
            }
        }

        Vector3 moveDirection = chaseDirection;
        if (isAvoiding)
        {
            // 计算优化后的避障方向:垂直于障碍法线,且尽量贴合原追逐路径
            Vector3 obstacleNormal = hit.normal.normalized;
            Vector3 avoidanceDirection = Vector3.Cross(chaseDirection, obstacleNormal).normalized;
            // 混合追逐与避障方向,实现平滑过渡
            moveDirection = Vector3.Lerp(chaseDirection, avoidanceDirection, avoidanceWeight).normalized;
            
            Debug.Log("Avoiding");
        }
        else
        {
            Debug.Log("Chasing");
        }

        // 平滑移动,避免生硬跳转
        transform.position += moveDirection * speed * Time.deltaTime;
        // 可选:让AI朝向移动方向,增强飞行自然感
        transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(moveDirection), Time.deltaTime * 5f);
    }
}

关键修改点说明

  • 状态缓冲机制:通过obstacleDetectCount计数,只有连续检测到障碍达到阈值才进入避障状态,连续未检测到达到阈值才切回追逐,彻底解决状态频繁切换问题。
  • 优化避障方向:基于原追逐方向和障碍法线计算避让路径,确保AI避障时尽量保持原有飞行轨迹,同时通过权重混合实现方向平滑过渡。
  • 平滑移动逻辑:直接通过方向向量累加位置,配合旋转平滑,替代原有的Vector3.MoveTowards生硬移动方式,消除抖动感。

内容的提问来源于stack exchange,提问作者kotan4ik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 04:46:26