You need to enable JavaScript to run this app. Unity C#开发中如何实现玩家与雪人敌人碰撞时扣血更新血条?
优惠活动
大模型
产品
解决方案
定价
更多

Unity C#开发中如何实现玩家与雪人敌人碰撞时扣血更新血条?

碰撞扣血逻辑修复方案

你的现有代码存在4个核心问题,直接按照下面的方案修正即可实现功能:

  • 语法结构错误:将碰撞回调OnCollisionEnter、扣血方法TakeDamage嵌套写在了Update()方法内部,C#不支持在方法内定义其他方法,所有碰撞事件永远无法触发
  • 组件适配错误:玩家挂载的是CharacterController组件,该组件不会触发OnCollisionEnter碰撞回调,对应的触发接口为OnControllerColliderHit
  • 逻辑校验缺失:未判断碰撞对象是否为敌人snowman,会出现碰到任何物体都扣血的问题
  • 联网逻辑错误:使用Mirror框架时,本地客户端没有权限直接修改血量数值,需要加服务器权限判断,否则多端血量显示不同步

修正后的完整玩家脚本

using UnityEngine;
using Mirror;

public class Player : NetworkBehaviour {
    CharacterController characterController;

    [Header("基础移动参数")]
    public float speed = 6.0f;
    public float jumpSpeed = 8.0f;
    public float gravity = 20.0f;
    [Header("生命值参数")]
    public int maxHealth = 30;
    public int currentHealth;
    [Header("碰撞伤害参数")]
    public int collisionDamage = 10;
    
    private Vector3 moveDirection = Vector3.zero;

    // 仅服务器端执行扣血逻辑
    [Server]
    void TakeDamage(int damage) {
        currentHealth -= damage;
        // 将当前血量同步给对应玩家的客户端
        TargetUpdateHealth(connectionToClient, currentHealth);
    }

    // 客户端接收血量同步值,更新血条UI
    [TargetRpc]
    void TargetUpdateHealth(NetworkConnection target, int health) {
        FindObjectOfType<HealthBar>().SetHealth(health);
    }

    void Start() {
        characterController = GetComponent<CharacterController>();
        currentHealth = maxHealth;
        // 仅本地玩家初始化血条最大刻度
        if (isLocalPlayer) {
            FindObjectOfType<HealthBar>().SetMaxHealth(maxHealth);
        }
    }

    // CharacterController专属碰撞回调
    void OnControllerColliderHit(ControllerColliderHit hit) {
        // 所有伤害判定仅在服务器端运行
        if (!isServer) return;
        // 判断碰撞对象是否为雪人敌人,通过标签判断比名字判断更稳定
        if (hit.gameObject.CompareTag("Enemy")) {
            TakeDamage(collisionDamage);
        }
    }

    void Update() {
        if (!isLocalPlayer) return;
        
        if (characterController.isGrounded) {
            moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
            moveDirection *= speed;

            if (Input.GetButton("Jump")) {
                moveDirection.y = jumpSpeed;
            }
        }

        moveDirection.y -= gravity * Time.deltaTime;
        characterController.Move(moveDirection * Time.deltaTime);
        transform.rotation = Quaternion.LookRotation(moveDirection);
    }

    public override void OnStartLocalPlayer() {
        Camera.main.GetComponent<CameraFollow>().setTarget(transform);
    }
}

落地操作注意事项

  • 将snowman预制体的Tag设置为Enemy(可在Unity Inspector顶部的Tag下拉栏新建),不要直接通过物体名字判断碰撞对象,后续改名不会导致逻辑失效
  • 不需要给CharacterController额外挂载Rigidbody组件,OnControllerColliderHit回调可以正常触发
  • Mirror框架下所有属性修改逻辑统一放在服务器端执行,同步给对应客户端更新UI显示,避免多端数值不一致

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.09 12:54:10