You need to enable JavaScript to run this app. Unity按空格键实现玩家与虚拟人偶位置交换偶现执行异常问题
优惠活动
大模型
产品
解决方案
定价
更多

Unity按空格键实现玩家与虚拟人偶位置交换偶现执行异常问题

玩家与人偶位置交换功能异常修复方案

异常根本原因

  • 执行顺序逻辑错位:原代码在Update中按键检测前就每帧执行SwapTransforms(),完全偏离了「记录交换前位置快照」的设计目的。本该在触发交换的瞬间、交换动作执行前记录两个对象的原始位置,实际实现却每帧用实时位置覆盖快照值,一旦物理引擎因重叠产生推挤位移,错误的推挤后位置会被写入快照,直接导致后续交换目标错乱。
  • 赋值时序触发物理冲突:交换时逐对象设置位置的间隙,物理引擎会检测到刚体重叠,立刻施加推力将两个对象分离,直接复现了「人偶先瞬移到玩家位置、玩家再移动到目标点、最终位置重叠互相推挤」的异常表现。
  • 快照逻辑无隔离:原实现每帧根据实时位置刷新记录值,没有和「交换触发动作」做绑定,只要两个对象位置因任何原因发生变动,就会被写入记录位,无法保证交换时获取的是无推挤污染的原始位置,因此会出现偶发异常。

修复后可运行代码

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

public class PlayerSwap : MonoBehaviour
{
    public GameObject player;
    public GameObject dummy;
    public GameObject cameraAnchor;

    public bool canSwap;
    public float swapRadius;
    public LayerMask dummyInRadius;

    void Update()
    {
        canSwap = Physics.CheckSphere(player.transform.position, swapRadius, dummyInRadius);
        if (canSwap && Input.GetKeyDown(KeyCode.Space))
        {
            SwapPosition();
        }
        else if (!canSwap)
        {
            Debug.Log("Can't Swap");
        }
        cameraAnchor.transform.position = player.transform.position;
    }

    private void SwapPosition()
    {
        // 触发交换瞬间存储两个对象的原始位置快照,完全隔离后续物理推挤的影响
        Vector3 playerOriginalPos = player.transform.position;
        Vector3 dummyOriginalPos = dummy.transform.position;

        // 临时禁用碰撞体,避免赋值过程触发重叠推挤
        Collider playerCol = player.GetComponent<Collider>();
        Collider dummyCol = dummy.GetComponent<Collider>();
        if (playerCol) playerCol.enabled = false;
        if (dummyCol) dummyCol.enabled = false;

        // 基于快照直接赋值,不再依赖外部挂载的记录位Transform
        player.transform.position = dummyOriginalPos;
        dummy.transform.position = playerOriginalPos;

        // 赋值完成后恢复碰撞
        if (playerCol) playerCol.enabled = true;
        if (dummyCol) dummyCol.enabled = true;
    }

    public void OnDrawGizmos()
    {
        Gizmos.color = Color.white;
        Gizmos.DrawWireSphere(player.transform.position, swapRadius);
    }
}

修复后效果

  • 每次按下空格键时,会一次性读取两个对象的当前真实位置生成快照,后续所有赋值操作都基于这个快照完成,不会被中途的物理推挤干扰,从根源上避免偶发的位置错乱。
  • 赋值过程中临时关闭碰撞体,完全杜绝逐对象赋值时物理引擎检测重叠推挤的问题,不会出现位置重叠、互相推动的异常表现。
  • 移除了原代码中冗余的haveSwapped状态标记、每帧无效调用的SwapTransforms()、需要手动拖拽绑定的记录位Transform,逻辑链路更短,状态同步无延迟,每次按键都能稳定实现两者位置来回切换的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.01 19:54:00