You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 21:24:56