Unity 2D 2020:如何让攻击代码检测两种不同组件?
问题描述
现有攻击脚本仅检测带有Enemy组件的对象,代码如下:
// Damage them foreach (Collider2D enemy in hitEnemies) { // Debug log showing the attack connected Debug.Log("We hit " + enemy.name); // the enemy takes damage from the player, could be rewritten enemy.GetComponent<Enemy>().TakeDamage(attackDamage); }
需求是让脚本同时兼容Boss专属的EnemyLoadArea组件(仅Boss拥有该组件,包含场景加载方法),但直接修改GetComponent为EnemyLoadArea会导致普通敌人无法受击死亡。尝试过以下写法均报错:
enemy.GetComponent<Enemy || EnemyLoadArea>().TakeDamage(attackDamage);:报错“||无法使用”- 连续调用两个
GetComponent:触发NullReferenceException空引用错误 - 重复foreach循环修改组件类型:无效
同时希望了解能否通过检测Enemy标签实现受击逻辑,替代组件检测。
解决方案
方案1:通过接口统一受击逻辑(推荐)
定义一个包含TakeDamage方法的接口,让Enemy和EnemyLoadArea都实现这个接口,就能统一处理两种对象的受击逻辑,避免空引用问题。
步骤1:定义接口
public interface IDamageable { void TakeDamage(int damage); }
步骤2:让组件实现接口
修改Enemy类:
public class Enemy : MonoBehaviour, IDamageable { // 原有Enemy逻辑代码 public void TakeDamage(int damage) { // 原有的受击死亡处理逻辑 } }
修改EnemyLoadArea类:
public class EnemyLoadArea : MonoBehaviour, IDamageable { // 原有场景加载逻辑代码 public void TakeDamage(int damage) { // Boss的受击处理逻辑,比如扣血后触发场景加载等 } }
步骤3:修改攻击脚本
foreach (Collider2D enemy in hitEnemies) { Debug.Log("We hit " + enemy.name); IDamageable damageable = enemy.GetComponent<IDamageable>(); if (damageable != null) { damageable.TakeDamage(attackDamage); } }
方案2:分别判断组件是否存在
如果不想使用接口,可以分别检查两个组件是否存在,仅在组件不为空时调用TakeDamage,避免空引用:
foreach (Collider2D enemy in hitEnemies) { Debug.Log("We hit " + enemy.name); Enemy normalEnemy = enemy.GetComponent<Enemy>(); if (normalEnemy != null) { normalEnemy.TakeDamage(attackDamage); } EnemyLoadArea bossEnemy = enemy.GetComponent<EnemyLoadArea>(); if (bossEnemy != null) { bossEnemy.TakeDamage(attackDamage); } }
方案3:使用标签检测替代组件检测
给所有受击对象(普通敌人+Boss)添加统一的Enemy标签,通过标签筛选后再获取对应组件:
步骤1:设置对象标签
在Inspector面板的Tag下拉框中,给普通敌人和Boss对象都添加Enemy标签(若无该标签可自行创建)。
步骤2:修改攻击脚本
foreach (Collider2D enemy in hitEnemies) { Debug.Log("We hit " + enemy.name); if (enemy.CompareTag("Enemy")) { Enemy normalEnemy = enemy.GetComponent<Enemy>(); if (normalEnemy != null) { normalEnemy.TakeDamage(attackDamage); } EnemyLoadArea bossEnemy = enemy.GetComponent<EnemyLoadArea>(); if (bossEnemy != null) { bossEnemy.TakeDamage(attackDamage); } } }
也可以结合接口方式简化代码:
foreach (Collider2D enemy in hitEnemies) { Debug.Log("We hit " + enemy.name); if (enemy.CompareTag("Enemy")) { IDamageable damageable = enemy.GetComponent<IDamageable>(); if (damageable != null) { damageable.TakeDamage(attackDamage); } } }
内容的提问来源于stack exchange,提问作者Moonlit Buns
相关产品推荐
相关产品推荐

