我正在制作一个FPS生存游戏。我编写了一个GameManager脚本来处理游戏中的敌人生成部分。我的EnemyAttack脚本负责敌人的攻击。问题是,当第一个敌人生成时,我只受到1点伤害(如AttackDamage中设置的),但当第二个敌人生成时,即使我只进入了一个敌人的攻击范围,我也会受到2点伤害(AttackDamage * 2)。以下是我所有的敌人脚本:
EnemyAttack.cs:
using UnityEngine; using UnityEngine.UI; using System.Collections; public class EnemyAttack : MonoBehaviour {public float AttackDamage = 1.0f;public float AttackSpeed = 1.0f;void Start() { StartCoroutine(Attack());}IEnumerator Attack() { while (true) { while (PlayerMovement.isEnemyAttacking == true) { EnemyAttacking(); yield return new WaitForSeconds(AttackSpeed); } yield return 0; }}public void EnemyAttacking() { Debug.Log("Enemy Attacking!"); PlayerHealth.Health -= AttackDamage; GameObject.FindGameObjectWithTag("HealthPoints").GetComponent<Text>().text = "HEALTH: " + PlayerHealth.Health;} }
EnemyAI.cs:
using UnityEngine; using System.Collections; public class EnemyAI : MonoBehaviour {public Transform TriggerBox;// Use this for initializationvoid Start () {}// Update is called once per framevoid Update(){ if (EnemySight.inSight == true) { NavMeshAgent agent = GetComponent<NavMeshAgent>(); agent.destination = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>().position; } } }
EnemySight.cs:
using UnityEngine; using System.Collections; public class EnemySight : MonoBehaviour {public static bool inSight = false;// Use this for initializationvoid Start(){}// Update is called once per framevoid Update(){}void OnTriggerEnter(Collider other){ if (other.gameObject.tag == "Player") { inSight = true; }}void OnTriggerExit(Collider other) { if (other.gameObject.tag == "Player") { inSight = false; } } }
以及PlayerHealth.cs:
using UnityEngine; using UnityEngine.UI; using System.Collections; public class PlayerHealth : MonoBehaviour {public Transform Player;public static float Health = 100;public static float maxHealth = 100;// Use this for initializationvoid Start () { GameObject.FindGameObjectWithTag("HealthPoints").GetComponent<Text>().text = "HEALTH: " + Health;}// Update is called once per framevoid Update () { if (Health <= 0) { Dead(); }}public static void Dead() {} }
回答:
你的脚本存在一些问题…
我认为你对静态变量的理解可能有误。
静态变量在类的所有实例之间共享其值
public static bool inSight;
不应该使用静态变量。
PlayerMovement.isEnemyAttacking
这也不应该使用静态变量。
目前,一旦有一个敌人满足“攻击”条件,你就会设置和读取一个单一的静态变量,导致所有敌人开始攻击。你应该让你的变量属于每个敌人的实例,而不是将你的变量设为静态。
基本上,你只需要理解什么是静态变量。一旦你明白了,你就会明白为什么你的逻辑不工作。
编辑:解决方案
PlayerHealth脚本。将此脚本附加到场景中的玩家GameObject上。
using UnityEngine;using UnityEngine.UI;public class PlayerHealth : MonoBehaviour{ public static float Health; public static float maxHealth = 100; private Text healthText; void Start() { healthText = GameObject.FindGameObjectWithTag("HealthPoints").GetComponent<Text>(); //在开始时使其满100%的健康值 Health = maxHealth; RefreshHealthBar(); } public void TakeDamage(float damage) { Health -= damage; RefreshHealthBar(); if (Health <= 0) Die(); } public void Die() { Health = 0; RefreshHealthBar(); //TODO: 你的代码 } void RefreshHealthBar() { healthText.text = "HEALTH: " + Health; }}
EnnemyAI脚本。将此脚本附加到你的敌人预制件上。
using System.Collections;using UnityEngine;public class EnnemyAI : MonoBehaviour{ public float AttackDamage = 1.0f; public float AttackSpeed = 1.0f; public float AttackRange = 1.0f; private bool isPlayerInSight; private GameObject target; private NavMeshAgent agent; // Use this for initialization void Start () { target = GameObject.FindGameObjectWithTag("Player"); agent = GetComponent<NavMeshAgent>(); StartCoroutine(AttackLoop()); } // Update is called once per frame void Update () { if (isPlayerInSight) { agent.destination = target.transform.position; } } IEnumerator AttackLoop() { while (true) { //我不知道你的攻击逻辑,所以假设他们可以在1单位范围内攻击 while (Vector3.Distance(target.transform.position, this.transform.position) <= AttackRange) { Attack(); yield return new WaitForSeconds(AttackSpeed); } yield return 0; } } void Attack() { target.GetComponent<PlayerHealth>().TakeDamage(AttackDamage); } void OnTriggerEnter(Collider other) { if (other.gameObject.tag == "Player") { isPlayerInSight = true; } } void OnTriggerExit(Collider other) { if (other.gameObject.tag == "Player") { isPlayerInSight = false; } }}
- 为了性能原因,我将FindGameObjectWithTag从Update()循环中移出。
- 玩家不再监听攻击。相反,敌人会向玩家发送伤害。
这样我们就去掉了静态变量。