(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 不在草地和其他地形上移动的主要内容,如果未能解决你的问题,请参考以下文章