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
相关产品推荐
相关产品推荐

