(Unity C#) NPC 不在草地和其他地形上移动

Posted

技术标签:

【中文标题】(Unity C#) NPC 不在草地和其他地形上移动【英文标题】:(Unity C#) NPC not moving on Grass and other terrain 【发布时间】:2020-06-24 07:54:07 【问题描述】:

我创建了一个跟随主要玩家的 NPC。当玩家在 NPC 的一定范围内时,NPC 应该根据玩家与 NPC 的距离来行走、奔跑和攻击。 NPC 附有动画师、盒子碰撞器、导航网格代理、敌人动画师和敌人控制器脚本。设置为follows,

我的问题是,如果地形上有某种草或蕨类植物,NPC 不会追逐玩家。

NPC 设置为使用Nav Mesh Agent 运行所有类型的地形,而且bake settings 就像在图像中一样。可以看到该问题的视频here。

敌人控制器的代码(虽然我怀疑这是问题所在)如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public enum EnemyState

    PATROL,
    CHASE,
    ATTACK


public class EnemyController : MonoBehaviour


    private EnemyAnimator enemy_Anim;
    private NavMeshAgent navAgent;

    private EnemyState enemy_State;

    public float walk_Speed = 0.5f;
    public float run_Speed = 4f;

    public float chase_Distance = 7f;
    private float current_Chase_Distance;
    public float attack_Distance = 1.8f;
    public float chase_After_Attack_Distance = 2f;

    public float patrol_Radius_Min = 20f, patrol_Radius_Max = 60f;
    public float patrol_For_This_Time = 15f;
    private float patrol_Timer;

    public float wait_Before_Attack = 2f;
    private float attack_Timer;

    private Transform target;

   public GameObject attack_Point;

    //private EnemyAudio enemy_Audio;

    void Awake()
    
        enemy_Anim = GetComponent<EnemyAnimator>();
        navAgent = GetComponent<NavMeshAgent>();

        target = GameObject.FindWithTag(Tags.PLAYER_TAG).transform;

      //  enemy_Audio = GetComponentInChildren<EnemyAudio>();

    

    // Use this for initialization
    void Start()
    

        enemy_State = EnemyState.PATROL;

        patrol_Timer = patrol_For_This_Time;

        // when the enemy first gets to the player
        // attack right away
        attack_Timer = wait_Before_Attack;

        // memorize the value of chase distance
        // so that we can put it back
        current_Chase_Distance = chase_Distance;

    

    // Update is called once per frame
    void Update()
    

        if (enemy_State == EnemyState.PATROL)
        
            Patrol();
        

        if (enemy_State == EnemyState.CHASE)
        
            Chase();
        

        if (enemy_State == EnemyState.ATTACK)
        
            Attack();
        

    

    void Patrol()
    

        // tell nav agent that he can move
        navAgent.isStopped = false;
        navAgent.speed = walk_Speed;

        // add to the patrol timer
        patrol_Timer += Time.deltaTime;

        if (patrol_Timer > patrol_For_This_Time)
        

            SetNewRandomDestination();

            patrol_Timer = 0f;

        

        if (navAgent.velocity.sqrMagnitude > 0)
        

            enemy_Anim.Walk(true);

        
        else
        

            enemy_Anim.Walk(false);

        

        // test the distance between the player and the enemy
        if (Vector3.Distance(transform.position, target.position) <= chase_Distance)
        

            enemy_Anim.Walk(false);

            enemy_State = EnemyState.CHASE;

            // play spotted audio
         //   enemy_Audio.Play_ScreamSound();

        


     // patrol

    void Chase()
    

        // enable the agent to move again
        navAgent.isStopped = false;
        navAgent.speed = run_Speed;

        // set the player's position as the destination
        // because we are chasing(running towards) the player
        navAgent.SetDestination(target.position);

        if (navAgent.velocity.sqrMagnitude > 0)
        

            enemy_Anim.Run(true);

        
        else
        

            enemy_Anim.Run(false);

        

        // if the distance between enemy and player is less than attack distance
        if (Vector3.Distance(transform.position, target.position) <= attack_Distance)
        

            // stop the animations
            enemy_Anim.Run(false);
            enemy_Anim.Walk(false);
            enemy_State = EnemyState.ATTACK;

            // reset the chase distance to previous
            if (chase_Distance != current_Chase_Distance)
            
                chase_Distance = current_Chase_Distance;
            

        
        else if (Vector3.Distance(transform.position, target.position) > chase_Distance)
        
            // player run away from enemy

            // stop running
            enemy_Anim.Run(false);

            enemy_State = EnemyState.PATROL;

            // reset the patrol timer so that the function
            // can calculate the new patrol destination right away
            patrol_Timer = patrol_For_This_Time;

            // reset the chase distance to previous
            if (chase_Distance != current_Chase_Distance)
            
                chase_Distance = current_Chase_Distance;
            


         // else

     // chase

    void Attack()
    

        navAgent.velocity = Vector3.zero;
        navAgent.isStopped = true;

        attack_Timer += Time.deltaTime;

        if (attack_Timer > wait_Before_Attack)
        

            enemy_Anim.Attack();

            attack_Timer = 0f;

            // play attack sound
        //    enemy_Audio.Play_AttackSound();

        

        if (Vector3.Distance(transform.position, target.position) > attack_Distance + chase_After_Attack_Distance)
        

            enemy_State = EnemyState.CHASE;

        


     // attack

    void SetNewRandomDestination()
    

        float rand_Radius = Random.Range(patrol_Radius_Min, patrol_Radius_Max);

        Vector3 randDir = Random.insideUnitSphere * rand_Radius;
        randDir += transform.position;

        NavMeshHit navHit;

        NavMesh.SamplePosition(randDir, out navHit, rand_Radius, -1);

        navAgent.SetDestination(navHit.position);

    

    void Turn_On_AttackPoint()
    
        attack_Point.SetActive(true);
    

    void Turn_Off_AttackPoint()
    
        if (attack_Point.activeInHierarchy)
        
            attack_Point.SetActive(false);
        
    

    public EnemyState Enemy_State
    
        get; set;
    

 // class

如果有人能帮助解决这样的问题,我将不胜感激!

编辑:我忘了添加草地设置,如下。如您所见,没有对撞机。

我正在挖掘更多,显然唯一可步行的区域如下(不是整个地图),我该如何调整?

【问题讨论】:

您是否仔细检查过草地或蕨类植物上没有碰撞体,并且导航网格已覆盖它们? @BartKuijer 我已经添加了草地设置,抱歉之前没有添加。不,它们上面没有任何对撞机。关于''navmesh is bake over them?'',我该如何检查? 遗憾的是,我目前的工作场所没有安装 unity,所以我无法提供更多细节,因为我需要测试一些东西来刷新我记忆中的 navmesh 烘焙。如果直到我下班回家后这个问题仍未得到解答,我会再看一遍! 看起来您的地形高度使区域无法步行。因此大部分是灰色而不是蓝色..您需要调整陡度,以及他们可以“抬起脚”的高度,因为需要一个更好的词来使其更加覆盖。 【参考方案1】:

以下是我的做法:

    用我需要的各种草和树木绘制地形。 撤消所有画过的草和树。 将导航网格 (Navmesh) 烘焙到地形上。 重做所有画过的草和树。 轰隆隆!完成工作。 :)

为什么草不能走路?

草像树木一样被涂漆,因此在烘烤过程中被雕刻成树木。

技巧: 您必须画出所需的草和所有树木,然后您必须取消对树木特殊的所有草。之后烘烤地形,然后撤消该过程(按几次CTRL + Z),直到看到重新绘制的草。

【讨论】:

以上是关于(Unity C#) NPC 不在草地和其他地形上移动的主要内容,如果未能解决你的问题,请参考以下文章

unity3d 动态添加地面贴图 草地

关于Unity自带的Terrain编辑器

在虚幻引擎5中构建你的首款游戏 - 04 - 地形和草地

在虚幻引擎5中构建你的首款游戏 - 04 - 地形和草地

Unity3D性能优化

【Unity】tilemap层级解决方案