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

Unity OnControllerColliderHit检测到碰撞但角色瞬移失效问题

Unity CharacterController碰撞触发瞬移失效问题

问题表现

  • 开发需求:实现角色触碰指定立方体时触发瞬移功能
  • 异常现象:控制台可正常输出碰撞检测命中的日志,但角色位置未按代码逻辑更新,瞬移完全失效
  • 已验证情况:近似逻辑在其他场景可正常运行;将瞬移逻辑拆分到独立脚本挂载后问题仍复现
  • 对照测试结果:相近逻辑脚本中,命中trigger对象时可正常修改位置、打印日志并退出应用;命中entrance对象时仅打印瞬移日志,角色位置同样不更新

复现代码

瞬移功能测试脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class othercollision : MonoBehaviour
{
    void OnControllerColliderHit(ControllerColliderHit hit)
    {
        if (hit.gameObject.name == "teleportcube")
        {
            gameObject.transform.position = new Vector3(-3184.53f, 20.35f, -171.585f);
            Debug.Log("Collision detected");
        }
    }
}

对照参考脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public class detectcollision : MonoBehaviour
{
    public GameObject tplocation1;
    public GameObject player;
    public GameObject entranceloc;
    void OnControllerColliderHit(ControllerColliderHit hit)
    {
        // 该分支可正常修改位置、打印日志后退出
        if (hit.gameObject.name == "trigger")
        {
            Debug.Log("triggered");
            gameObject.transform.position = tplocation1.transform.position;
            Thread.Sleep(7);
            Application.Quit();
        }
        // 该分支仅打印日志,位置不更新
        if (hit.gameObject.name == "entrance")
        {
            gameObject.transform.position = new Vector3(-3184.53f, 20.35f, -171.585f);
            Debug.Log("teleporting...");
        }

    }
}

问题根因

OnControllerColliderHit是CharacterController执行Move/SimpleMove移动逻辑过程中触发的回调,在回调内直接修改transform.position后,CharacterController当帧未执行完的移动解算、碰撞贴靠修正逻辑会直接覆盖你手动设置的坐标,最终表现为瞬移失效。
参考脚本里trigger分支看似正常,本质是设置完坐标后立刻调用Application.Quit()终止了程序,CharacterController没机会执行后续的位置覆盖步骤,不是写法本身正确。

修复方案

不要在OnControllerColliderHit回调内直接修改坐标,用布尔值标记需要瞬移的状态,等到LateUpdate阶段(所有物理计算、CharacterController移动逻辑全部执行完成后)再更新位置,示例代码如下:

using UnityEngine;

public class TeleportFix : MonoBehaviour
{
    private bool _needTeleport = false;
    private Vector3 _targetPos;
    private CharacterController _controller;
    public GameObject tplocation1;

    void Start()
    {
        _controller = GetComponent<CharacterController>();
    }

    void OnControllerColliderHit(ControllerColliderHit hit)
    {
        if (hit.gameObject.name == "teleportcube" || hit.gameObject.name == "entrance")
        {
            _needTeleport = true;
            _targetPos = new Vector3(-3184.53f, 20.35f, -171.585f);
            Debug.Log("Hit teleport trigger");
        }

        if (hit.gameObject.name == "trigger")
        {
            Debug.Log("triggered");
            _needTeleport = true;
            _targetPos = tplocation1.transform.position;
            // 不要在主线程用Thread.Sleep,会卡死程序
            Invoke(nameof(QuitGame), 0.01f);
        }
    }

    void LateUpdate()
    {
        if (_needTeleport)
        {
            // 瞬移前临时关闭Controller避免位置被覆盖
            _controller.enabled = false;
            transform.position = _targetPos;
            _controller.enabled = true;
            _needTeleport = false;
        }
    }

    void QuitGame()
    {
        Application.Quit();
    }
}

额外注意:不要在Unity主线程调用Thread.Sleep(),会直接阻塞整个游戏进程导致卡顿。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 07:12:34