Unity游戏中玩家Collider无法检测敌人碰撞的问题求助
玩家与敌人碰撞检测未触发问题排查
我和朋友开发Unity游戏时,遇到玩家攻击逻辑的碰撞检测问题:敌人进入玩家Collider后,enemyIN布尔值未被设为true,导致无法触发攻击。已调大玩家Collider,项目使用FPmovement(玩家控制)和EnemyDamage(敌人伤害)两个脚本,且已在FPmovement中调用EnemyDamage.takeDMG()方法。尝试过添加/移除Rigidbody、调整Collider、重写脚本,均无效果,日志无任何碰撞相关输出。
FPmovement脚本代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; public class FPmovement : MonoBehaviour { public AudioSource source; public AudioClip walking; public float speed = 5f; public float jumpSpeed = 5f; public float gravity = -9.81f; public float crouchHeight = 1f; public float lookSensitivity = 2f; public float superDashCost = 35.0f; private float _originalHeight; public bool j = true; public GameManager gameManager; public bool enemyIN = false; public EnemyDamage enemyD; private CharacterController _controller; public Transform _camera; void Start() { _controller = GetComponent<CharacterController>(); _originalHeight = _controller.height; Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } private void Awake() { Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } void Update() { if (Input.GetKeyDown(KeyCode.Mouse0) && enemyIN == true) { // Attack Animation enemyD.takeDMG(Random.Range(12, 28)); } if (Input.GetKeyDown(KeyCode.V)) { gameManager.AddTree(25); } if (Input.GetKeyDown(KeyCode.B)) { if (gameManager.tree >= superDashCost) { Debug.Log("Money well Spent"); gameManager.RemoveTree(35); } else { Debug.Log("Not enough Tree"); } } float x = Input.GetAxis("Horizontal"); float z = Input.GetAxis("Vertical"); Vector3 move = transform.right * x + transform.forward * z; _controller.Move(move * speed * Time.deltaTime); if (_controller.isGrounded && Input.GetButtonDown("Jump")) { _controller.Move(Vector3.up * jumpSpeed * Time.deltaTime); } _controller.Move(Vector3.up * gravity * Time.deltaTime); if (Input.GetKey(KeyCode.LeftControl)) { _controller.height = crouchHeight; speed = 2.5f; } else { _controller.height = _originalHeight; speed = 5; } if (Input.GetKey(KeyCode.LeftShift)) { speed = 7.5f; } else { source.clip = walking; source.loop = true; source.Play(); speed = 5; } // first-person look float mouseX = Input.GetAxis("Mouse X") * lookSensitivity; mouseX = Mathf.Clamp(mouseX, -20f, 70f); float mouseY = Input.GetAxis("Mouse Y") * lookSensitivity; transform.Rotate(0f, mouseX, 0f); float newXRotation = _camera.localEulerAngles.x - mouseY; if (newXRotation > 180f) { newXRotation -= 360f; } newXRotation = Mathf.Clamp(newXRotation, -20f, 80f); _camera.localEulerAngles = new Vector3( newXRotation, 0f, 0f ); } public void OnCollisionEnter(Collision collision) { Debug.Log("Collison2"); if (collision.gameObject.CompareTag("Enemy")) { Debug.Log("Collison with Enemy"); enemyIN = true; } } private void OnCollisionExit(Collision collision) { if (collision.gameObject.CompareTag("Enemy")) { Debug.Log("Collison with Enemy Leave"); enemyIN = false; } } }
EnemyDamage脚本代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class EnemyDamage : MonoBehaviour { public int EnemyHealth = 100; private Health PlayerHealth; private GameObject damVFX; private Image damVFXimg; private GameObject player; private Animator playerAnim; private bool attack; private GameObject AttackHand; // Start is called before the first frame update void Start() { damVFX = GameObject.FindWithTag("damage"); damVFXimg = damVFX.GetComponent<Image>(); player = GameObject.FindWithTag("Player"); PlayerHealth = player.GetComponent<Health>(); playerAnim = player.GetComponent<Animator>(); attack = playerAnim.GetBool("isWeakAttack"); AttackHand = GameObject.FindWithTag("AttackHand"); } // Update is called once per frame void Update() { if (EnemyHealth <= 0) { Destroy(gameObject); } } private void OnTriggerEnter(Collider other) { if (other.CompareTag("AttackHand")) { takeDMG(10); Debug.Log("uh"); } } private void OnTriggerStay(Collider other) { if (other.CompareTag("Player")) { Damage(1); effectOn(); } } private void OnTriggerExit(Collider other) { Invoke("effectOff", 2f); } public void Damage(int damage) { PlayerHealth.health -= damage; } public void takeDMG(int Edamage) { EnemyHealth -= Edamage; } public void effectOn() { damVFXimg.enabled = true; } public void effectOff() { damVFXimg.enabled = false; } }
排查方向
- CharacterController的特殊性:玩家使用
CharacterController组件时,OnCollisionEnter/Exit不会被触发——因为CharacterController通过Move()方法驱动,不属于Unity的物理碰撞系统。需要将玩家的Collider设置为Is Trigger,然后把OnCollisionEnter/Exit替换为OnTriggerEnter/Exit。 - 标签与组件校验:确认敌人对象的
Tag确实是Enemy,且敌人身上带有非触发器状态的Collider;如果玩家用触发器,敌人或玩家其中一方必须带有Rigidbody(且不能勾选Is Kinematic,否则触发器事件不会触发)。 - Rigidbody配置:建议给敌人添加Rigidbody组件,关闭
Is Kinematic选项,确保物理引擎能检测到碰撞/触发事件。 - 脚本挂载位置:确认
FPmovement挂载在带有CharacterController和Collider的玩家根对象上,EnemyDamage挂载在敌人对象上。 - 方法权限修正:将
FPmovement中的OnCollisionEnter从public改为private(虽然这不是核心问题,但符合代码规范),核心还是替换为触发器事件。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

