你好,我试图让敌人在玩家面前停止,使用 if(Vector2.Distance(transform.position, player.position) > minDistance)
但这并没有按我预期的那样工作。敌人应该在一定范围内开始跟随玩家,然后在他面前停止。这在使用 if(Vector2.Distance(transform.position, player.position) <= range)
时运行良好
using System.Collections;using System.Collections.Generic;using UnityEngine;public class Enemy : MonoBehaviour{ public int Health; public Transform player; public float range; public float speed; public Animator anim; public Transform goblinRange; public float attackRangeGoblin; public LayerMask whatIsPlayer; public int damage; private float timeBtwAttack; public float startTimeBtwAttack; // Update is called once per frame void Update() { if (Vector2.Distance(transform.position, player.position) <= range) { anim.SetBool("GWalking", true); transform.position = Vector2.MoveTowards(transform.position, player.position, speed * Time.deltaTime); Collider2D[] playerToDamage = Physics2D.OverlapCircleAll(goblinRange.position, attackRangeGoblin, whatIsPlayer); for (int i = 0; i < playerToDamage.Length; i++) { playerToDamage[i].GetComponent<PlayerMovement>().TakeDamage(damage); } } else { Idle(); } } private void FixedUpdate() { if (Health <= 0) { Destroy(gameObject); } } private void Idle() { anim.SetBool("GWalking", false); } public void TakeDamage(int Damage) { Health -= Damage; Debug.Log("Damage Taken"); } private void OnDrawGizmosSelected() { Gizmos.color = Color.red; Gizmos.DrawWireSphere(goblinRange.position, attackRangeGoblin); } private void Attack() { anim.SetTrigger("goblinAttack"); } }
所以我需要敌人在玩家面前停止并开始攻击动画,但我不知道如何在不删除 “<= range” 的情况下将 if(Vector2.Distance(transform.position, player.position) > minDistance)
实现到我的代码中。任何帮助都将不胜感激。
回答:
range
和 minDistance
的检查并不是互斥的(“一个或另一个”)。它们可以同时存在并共存:
//避免冗余,少写一些代码,并使其更易读var distance = Vector2.Distance(transform.position, player.position);//如果在范围内..if (distance <= range) { //如果不在最小距离内.. if(!(distance <= minDistance)) { //移动 } //如果在最小距离内(包括移动后,上面).. if (distance <= minDistance) { //攻击 }}//如果不在范围内..else { //空闲}
代码中还有其他几个问题:
-
你应该遵循命名约定:
- 如果你的变量和参数将使用驼峰命名法,那么
Health
应该改为health
,GWalking
应该改为gWalking
,Damage
应该改为damage
。
- 如果你的变量和参数将使用驼峰命名法,那么
-
名称应该具有描述性:
为了节省几个字符的输入而牺牲你或其他人(例如我们)解读代码的难度是不值得的。
- 避免歧义。
anim
可以指的是 animator 或 animation。使用animator
更合适。 - 避免使用缩写。在
GWalking
中,G
代表什么?— Goblin。我知道。问题是:我通过推断其他代码得知的;不是通过名称本身。使用goblinWalking
更合适。 - 避免使用类似缩写的简写,如
Btw
代替Between
。它们不好,原因与 ‘G’ 相同。
- 避免歧义。
-
保持一致性:
- 对相似的东西使用相同的命名结构。决定一个方案,并遵循它。不要在一个地方使用
GWalking
,在另一个地方使用goblinAttack
。如果 “subjectAction
” 是结构,使用goblinWalking
、goblinAttack
等。 - 在名称中使用相同的结构顺序。如果你的主题将放在开头,如
goblinRange
,那么不要在其他地方放在末尾,如attackRangeGoblin
。使用goblinAttackRange
更合适。 - 如果类是 “Enemy”,那么 “Goblin” 相关的东西不应该出现在这里。所有哥布林 可能 是敌人,但并非所有敌人都是哥布林。你的类可能是所有敌人的通用类,或者是哥布林的特定类;不能两者兼有。将其命名为
Goblin
;或者从其元素中移除 “goblin” 相关的东西。
- 对相似的东西使用相同的命名结构。决定一个方案,并遵循它。不要在一个地方使用
-
为变量命名它们是什么,而不是它们做什么:
whatIsPlayer
改为playerLayerMask
。
-
在命名时要有资源性(即:“描述性并不意味着冗长!”):
timeBtwAttacks
改为attackInterval
。
-
尝试将相关的东西分组。
修复后,它应该看起来像这样:
//外部(?)依赖public Transform player;public LayerMask playerLayerMask; //来自:whatIsPlayer//内部依赖public Animator animator; //来自:anim//设置public int health; //来自:Healthpublic float range;public float speed;public int damage;public float attackInterval; //来自:timeBtwAttack//哥布林相关的东西(可能多余/不必要)public Transform goblin; //来自:goblinRangepublic float goblinAttackRange; //来自:attackRangeGoblin//在答案中使用,从问题中推断public float minDistance; //可能是 'goblinAttackRange' 的意思。
其他修复:
FixedUpdate
用于物理相关的东西。if (health <= 0) { Destroy(gameObject); }
应该在Update
中(加上return
),如果要遵循当前结构。如果不是,那么它应该对健康变化做出反应,因此应该在TakeDamage
中。- 在代码中保持一致性。不要在一个地方使用
anim.SetBool("GWalking", true)
,然后在另一个地方使用Idle()
。两者都应该是方法(Idle()
和Walk()
),或者两者都应该是SetBool
调用。 Transform goblin
是一个单独的变换吗?如果不是,只需像在Vector2.Distance
中那样使用transform
即可。