You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Collider失效问题:需修改玩家扣血逻辑为僵尸碰撞FPS玩家时扣血

解决Unity中僵尸碰撞扣血无效的问题

我明白你想把原本那种“僵尸一进入攻击动画就自动扣玩家血”的逻辑,改成只有僵尸和FPS玩家实际碰撞时才扣除生命值,但现在你的OnTriggerEnter碰撞检测完全没起作用。咱们一步步排查问题,把这个逻辑给修好:

一、先把碰撞检测的基础条件捋顺(这些坑最容易踩)

  • 双方都得有Collider组件:玩家和僵尸都要加上合适的Collider(比如CapsuleCollider),而且至少得有一方的Collider勾选了Is Trigger——毕竟你用的是OnTriggerEnter触发事件,如果是想做物理碰撞的话就用OnCollisionEnter,那时候就不能勾Is Trigger了。
  • 必须有Rigidbody:Unity的触发检测要求至少一方带有Rigidbody组件,你可以给僵尸或者玩家加,要是不想影响移动的话,把Rigidbody的Is Kinematic勾上就行,不影响触发事件的触发。
  • 标签别写错:确认僵尸的GameObject标签真的是Enemy,标签是区分大小写的,别写成enemy或者Enemy1之类的。

二、修正你的碰撞扣血代码

你现在的脚本逻辑可能搞反了:如果是僵尸撞玩家,要么把检测脚本挂在僵尸身上,要么挂在玩家身上时正确判断触发对象。另外,得加个冷却机制,不然僵尸一蹭到玩家就疯狂扣血,太不合理了。

方案1:把脚本挂在玩家身上的正确写法

public class PlayerHealth : MonoBehaviour
{
    public float currentHealth = 100f;
    public PlayerHealthBar healthBar; // 把你的血条UI拖进来
    private bool canTakeDamage = true;
    public float damageCooldown = 1f; // 1秒内只能扣一次血

    void OnTriggerEnter(Collider other)
    {
        // 检查进来的是僵尸,而且当前可以扣血
        if (other.CompareTag("Enemy") && canTakeDamage)
        {
            currentHealth -= 20f;
            healthBar.value = currentHealth; // 更新血条显示
            Debug.Log("被僵尸打中了!当前血量:" + currentHealth);
            StartCoroutine(StartDamageCooldown());
        }
    }

    // 冷却逻辑,防止重复扣血
    IEnumerator StartDamageCooldown()
    {
        canTakeDamage = false;
        yield return new WaitForSeconds(damageCooldown);
        canTakeDamage = true;
    }
}

方案2:把脚本挂在僵尸身上(更合理,毕竟是僵尸发起攻击)

public class ZombieAttack : MonoBehaviour
{
    private bool canAttack = true;
    public float attackCooldown = 1.5f; // 僵尸攻击间隔
    public int attackDamage = 20;

    void OnTriggerEnter(Collider other)
    {
        // 碰到的是玩家,而且可以发起攻击
        if (other.CompareTag("Player") && canAttack)
        {
            // 获取玩家的血量组件
            PlayerHealth playerHealth = other.GetComponent<PlayerHealth>();
            if (playerHealth != null)
            {
                playerHealth.TakeDamage(attackDamage);
                Debug.Log("僵尸攻击了玩家!");
                StartCoroutine(StartAttackCooldown());
            }
        }
    }

    IEnumerator StartAttackCooldown()
    {
        canAttack = false;
        yield return new WaitForSeconds(attackCooldown);
        canAttack = true;
    }
}

// 同时在玩家的脚本里加一个专门的扣血方法
public class PlayerHealth : MonoBehaviour
{
    public float currentHealth = 100f;
    public PlayerHealthBar healthBar;

    public void TakeDamage(int damage)
    {
        currentHealth -= damage;
        healthBar.value = currentHealth;
        
        // 可以加个死亡判断
        if (currentHealth <= 0)
        {
            Debug.Log("玩家阵亡了!");
            // 这里写死亡后的逻辑,比如播放动画、加载场景
        }
    }
}

三、别忘了删掉旧的扣血逻辑

一定要把你原来那段基于动画状态的扣血代码删掉,不然两种逻辑同时运行,血量会乱掉:

// 把这段旧代码彻底移除
// if (anim.GetBool("isAttacking") && !anim.GetBool("isWalking")) { 
//     PlayerHealthBar.value -= 2; 
//     Debug.Log("Hit"); 
//     //anim.SetBool("isAttacking", false); 
// }

四、额外的小提示

  • 如果不想用触发事件,想用真实的物理碰撞,就把OnTriggerEnter换成OnCollisionEnter,同时双方的Collider都不能勾Is Trigger,Rigidbody还是得有。
  • 测试的时候可以在Scene视图里打开Collider的可视化,看看僵尸和玩家的Collider是不是真的会碰到一起,有时候Collider范围太小或者位置不对也会导致检测失败。

内容的提问来源于stack exchange,提问作者Fazil Mahesania

火山引擎 最新活动