Instantiated Enemy 对每个在他之后生成的敌人输出双倍伤害
Instantiated Enemy outputs double damage for every enemy spawning after him
所以我正在制作一款 FPS 生存游戏。我制作了一个 GameManager 脚本来处理游戏的 Enemy Spawning 部分。我的 EnemyAttack 脚本处理敌人的攻击。问题是,当第一个敌人生成时,我只受到 1 点伤害(在 AttackDamage 中设置),但是当第二个敌人生成时,即使我只进入 1 个敌人的攻击范围,我也会受到 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 initialization
void Start () {
}
// Update is called once per frame
void 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 initialization
void Start()
{
}
// Update is called once per frame
void 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 initialization
void Start () {
GameObject.FindGameObjectWithTag("HealthPoints").GetComponent<Text>().text = "HEALTH: " + Health;
}
// Update is called once per frame
void Update () {
if (Health <= 0) {
Dead();
}
}
public static void Dead() {
}
}
你的脚本有一些问题...
我觉得你不明白什么是静态变量。
A static variable shares the value of it among all instances of the class
Source
public static bool inSight;
不应该是静态的。
PlayerMovement.isEnemyAttacking
这也不应该是静态的。
现在,一旦你有 1 个敌人满足 "Attack" 条件,你就会设置和读取一个静态变量,导致所有敌人攻击。你应该让你的变量属于每个敌人实例,而不是让你的变量成为静态的。
基本上,你只需要了解什么是静态变量就可以了。一旦你知道了,你就会明白为什么你的逻辑不起作用。
编辑:解决方案
玩家健康脚本。将此脚本附加到场景中的玩家游戏对象。
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>();
//Make it full 100% health on start
Health = maxHealth;
RefreshHealthBar();
}
public void TakeDamage(float damage)
{
Health -= damage;
RefreshHealthBar();
if (Health <= 0)
Die();
}
public void Die()
{
Health = 0;
RefreshHealthBar();
//TODO: Your code
}
void RefreshHealthBar()
{
healthText.text = "HEALTH: " + Health;
}
}
EnnemyAI 脚本。将其附加到您的 Ennemy 预制件上。
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)
{
//I don't know your attacking logic, so lets say they can attack in a 1 unit range
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() 循环中移除。
- 玩家不再监听攻击。相反,敌人正在向玩家发送伤害。
这样我们就摆脱了静态变量。
所以我正在制作一款 FPS 生存游戏。我制作了一个 GameManager 脚本来处理游戏的 Enemy Spawning 部分。我的 EnemyAttack 脚本处理敌人的攻击。问题是,当第一个敌人生成时,我只受到 1 点伤害(在 AttackDamage 中设置),但是当第二个敌人生成时,即使我只进入 1 个敌人的攻击范围,我也会受到 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 initialization
void Start () {
}
// Update is called once per frame
void 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 initialization
void Start()
{
}
// Update is called once per frame
void 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 initialization
void Start () {
GameObject.FindGameObjectWithTag("HealthPoints").GetComponent<Text>().text = "HEALTH: " + Health;
}
// Update is called once per frame
void Update () {
if (Health <= 0) {
Dead();
}
}
public static void Dead() {
}
}
你的脚本有一些问题...
我觉得你不明白什么是静态变量。
A static variable shares the value of it among all instances of the class
Source
public static bool inSight;
不应该是静态的。
PlayerMovement.isEnemyAttacking
这也不应该是静态的。
现在,一旦你有 1 个敌人满足 "Attack" 条件,你就会设置和读取一个静态变量,导致所有敌人攻击。你应该让你的变量属于每个敌人实例,而不是让你的变量成为静态的。
基本上,你只需要了解什么是静态变量就可以了。一旦你知道了,你就会明白为什么你的逻辑不起作用。
编辑:解决方案
玩家健康脚本。将此脚本附加到场景中的玩家游戏对象。
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>();
//Make it full 100% health on start
Health = maxHealth;
RefreshHealthBar();
}
public void TakeDamage(float damage)
{
Health -= damage;
RefreshHealthBar();
if (Health <= 0)
Die();
}
public void Die()
{
Health = 0;
RefreshHealthBar();
//TODO: Your code
}
void RefreshHealthBar()
{
healthText.text = "HEALTH: " + Health;
}
}
EnnemyAI 脚本。将其附加到您的 Ennemy 预制件上。
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)
{
//I don't know your attacking logic, so lets say they can attack in a 1 unit range
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() 循环中移除。
- 玩家不再监听攻击。相反,敌人正在向玩家发送伤害。
这样我们就摆脱了静态变量。