Unity C#问题:战士攻击Boss血量不更新,如何跨脚本修改数值?
我尝试通过Warrior(战士)脚本修改Boss的血量,但数值完全没有更新。目前战士碰撞Boss时能触发检测且无报错,但Boss的血量数值未发生变化。另外,Warrior可以生成多个实例,相关代码如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class WarriorHealthSystem : MonoBehaviour { // private int warriorHealth = 100; - dont need it atm private int warriorAttack = 20; // public int warriorDefense = 10; - dont need it atm private int warriorCooldown = 5; private int timeSinceLastAttack; public GameObject bossHealth; // Start is called before the first frame update void Start() { bossHealth = GameObject.FindGameObjectWithTag("Boss"); } // Update is called once per frame void Update() { } private void OnCollisionStay2D(Collision2D collision) { HealthSystemScript healthSystemScript = bossHealth.GetComponent<HealthSystemScript>(); //Check if warrior is touching Boss object if (collision.gameObject.tag == "Boss" && Time.time > warriorCooldown) { // Abort if we already attacked recently. if (Time.time - timeSinceLastAttack < warriorCooldown) return; { //if collided object has "Boss" Tag then: if (collision.gameObject.CompareTag("Boss")) { WarriorAttack(warriorAttack, healthSystemScript.currentHealth); Debug.Log("took 20dmg!"); // Remember that we recently attacked. timeSinceLastAttack = (int)Time.time; } } } } private void WarriorAttack(int damage, int bossHealth) { bossHealth -= damage; } }
核心原因及修复方案:
值传递导致无效修改
C#里int是值类型,把healthSystemScript.currentHealth传给WarriorAttack的bossHealth参数时,传的是一份数值副本,方法里修改副本根本不会影响原组件里的currentHealth。
错误写法:WarriorAttack(warriorAttack, healthSystemScript.currentHealth); private void WarriorAttack(int damage, int bossHealth) { bossHealth -= damage; // 改的是副本,原血量没变化 }直接修改原变量或者传递组件实例:
// 方案1:直接在碰撞逻辑里修改 healthSystemScript.currentHealth -= warriorAttack; // 方案2:修改WarriorAttack方法接收组件实例 private void WarriorAttack(int damage, HealthSystemScript bossHealthSystem) { bossHealthSystem.currentHealth -= damage; } // 调用时传组件实例 WarriorAttack(warriorAttack, healthSystemScript);冷却判断逻辑错误
最外层条件里加了Time.time > warriorCooldown,游戏刚开始Time.time从0开始,小于5,直接导致攻击逻辑根本进不去。这个条件完全多余,后面已经有Time.time - timeSinceLastAttack < warriorCooldown的冷却判断,直接删掉即可。
修正后的条件:if (collision.gameObject.CompareTag("Boss"))冗余的标签判断
最外层已经判断了碰撞对象是Boss,里面又重复写了collision.gameObject.CompareTag("Boss"),完全没必要,直接删掉这段冗余代码。多战士实例的潜在注意点
每个战士都通过GameObject.FindGameObjectWithTag("Boss")查找Boss,这个逻辑本身没问题,但如果Boss被销毁重建,可能会出现找不到的情况。可以考虑把Boss的HealthSystemScript做成单例,或者在场景里提前赋值引用,避免重复查找。
内容的提问来源于stack exchange,提问作者Aru Alonless

