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

Unity中Transform.position无法将物体移至指定Vector3位置的问题

问题描述

我编写的物体位置更新代码原本运行正常,但添加移动另一批同类物体的代码段后出现异常:物体无法移动到指定的Vector3位置。已确认传入的目标向量为正确值,但当前位置与目标位置的距离始终无法归零。

已排查的情况:这些物体未挂载Rigidbody,也不是其他物体的子物体,排除被卡住的可能;但即使在Inspector中手动修正位置,物体仍会自动回到错误位置。

相关代码段
public void UpdateCardPosition(int offsetDirection)
{
    TimeBehaviour centralTime = FindObjectOfType<TimeBehaviour>();
    float AnchorDistance = centralTime.GetBoardSize() * 4.5f;
    float ManifestRepulsion = 0f;
    int playerIndex = centralTime.PlayerList.IndexOf(this);
    
    if (FocalEntity != null) ManifestRepulsion = AnchorDistance * 5;
    
    foreach (EntityBehaviour entity in FindObjectsOfType<EntityBehaviour>())
    {
        float em_count = entity.entityManifests.Count;
        for(int i=0; i<em_count; i++)
        {
            CardBehaviour curCard = entity.entityManifests[i];
            if (curCard != centralTime.FocalEvent)
            {
                float theta = Mathf.PI / 2 * (((float)i + 1) / (em_count + 1) - .5f);
                Vector3 newLoc = new Vector3(AnchorDistance * (.5f - playerIndex) / .5f * Mathf.Cos(theta), AnchorDistance*5, AnchorDistance * (.5f - playerIndex) / .5f * Mathf.Sin(theta));
                if (entity == FocalEntity) newLoc = new Vector3(AnchorDistance * (.5f - playerIndex) / .5f * Mathf.Cos(theta), 0f, AnchorDistance * (.5f - playerIndex) / .5f * Mathf.Sin(theta));
                curCard.transform.position = Vector3.Lerp(curCard.transform.position, newLoc, 0.1f);
                // Debug.Log((curCard.transform.position-newLoc).magnitude);
                curCard.transform.rotation = Quaternion.Euler(new Vector3(0, (90f * (.5f - playerIndex) / .5f - theta * 180 / Mathf.PI), 0));
            }
            else
            {
                curCard.transform.position = Vector3.Lerp(curCard.transform.position, centralTime.transform.position, 0.1f);
                curCard.transform.rotation = Quaternion.Slerp(curCard.transform.rotation, centralTime.transform.rotation, 0.1f);
            }
        }
    }
    
    // 以下代码段原本运行正常,写法与上面一致
    float pre_count = playerPresent.Count;
    for (int i=0; i<pre_count; i++)
    {
        float AnchorDistance_Pre = AnchorDistance + 1.5f* AnchorDistance * 0.5f * Mathf.Max(0, Mathf.Abs(offsetDirection));
        CardBehaviour curCard = playerPresent[i];
        if(curCard != centralTime.FocalEvent)
        {
            float theta = Mathf.PI / 2 * (((float)i + 1) / (pre_count + 1) - .5f) + offsetDirection * Mathf.PI / 2;
            Vector3 newLoc = new Vector3(AnchorDistance_Pre * (.5f - playerIndex) / .5f * Mathf.Cos(theta), ManifestRepulsion, AnchorDistance_Pre * (.5f - playerIndex) / .5f * Mathf.Sin(theta));
            curCard.transform.position = Vector3.Lerp(curCard.transform.position, newLoc, 0.1f);
            curCard.transform.rotation = Quaternion.Euler(new Vector3(0, (90f * (.5f - playerIndex) / .5f - theta * 180 / Mathf.PI), 0));
        }
        else
        {
            curCard.transform.position = Vector3.Lerp(curCard.transform.position, centralTime.transform.position, 0.1f);
            curCard.transform.rotation = Quaternion.Slerp(curCard.transform.rotation, centralTime.transform.rotation, 0.1f);
        }
    }
    
    float fut_count = playerFuture.Count;
    for (int i = 0; i < fut_count; i++)
    {
        float AnchorDistance_Fut = AnchorDistance + 1.5f* AnchorDistance * (Mathf.Min(-0.5f, offsetDirection) + 1f);
        CardBehaviour curCard = playerFuture[i];
        float theta = Mathf.PI / 2 * (((float)i + 1) / (fut_count + 1) - .5f) + Mathf.PI/2 + offsetDirection * Mathf.PI/2;
        Vector3 newLoc = new Vector3(AnchorDistance_Fut * (.5f - playerIndex) / .5f * Mathf.Cos(theta), ManifestRepulsion, AnchorDistance_Fut * (.5f - playerIndex) / .5f * Mathf.Sin(theta));
        curCard.transform.position = Vector3.Lerp(curCard.transform.position, newLoc, 0.1f);
        curCard.transform.rotation = Quaternion.Euler(new Vector3(0, (90f * (.5f - playerIndex) / .5f - theta * 180 / Mathf.PI), 0));
    }
    
    float pas_count = playerPast.Count;
    for (int i = 0; i < pas_count; i++)
    {
        float AnchorDistance_Pas = AnchorDistance + 1.5f* AnchorDistance * Mathf.Abs(Mathf.Max(0.5f, offsetDirection)-1f);
        CardBehaviour curCard = playerPast[i];
        float theta = Mathf.PI / 2 * (((float)i + 1) / (pas_count + 1) - .5f) - Mathf.PI / 2 + offsetDirection * Mathf.PI/2;
        Vector3 newLoc = new Vector3(AnchorDistance_Pas * (.5f - playerIndex) / .5f * Mathf.Cos(theta), ManifestRepulsion, AnchorDistance_Pas * (.5f - playerIndex) / .5f * Mathf.Sin(theta));
        curCard.transform.position = Vector3.Lerp(curCard.transform.position, newLoc, 0.1f);
        curCard.transform.rotation = Quaternion.Euler(new Vector3(0, (90f * (.5f - playerIndex) / .5f - theta * 180 / Mathf.PI), 0));
    }   
}
问题分析与解决方案

核心问题:重复赋值冲突

FindObjectsOfType<EntityBehaviour>()遍历的卡片,大概率和playerPresent/playerFuture/playerPast中的卡片是同一批对象。同一张卡片被两段代码先后修改位置,先被第一段Lerp到一个目标,接着又被后面的代码Lerp到另一个目标,导致位置在两个目标间拉扯,永远无法到达最终点。

具体修复方案

  1. 避免重复处理同一对象
    在第一段遍历EntityBehaviour的循环中,跳过已在playerPresent/playerFuture/playerPast中的卡片:

    foreach (EntityBehaviour entity in FindObjectsOfType<EntityBehaviour>())
    {
        float em_count = entity.entityManifests.Count;
        for(int i=0; i<em_count; i++)
        {
            CardBehaviour curCard = entity.entityManifests[i];
            // 跳过已被后续代码处理的卡片
            if (playerPresent.Contains(curCard) || playerFuture.Contains(curCard) || playerPast.Contains(curCard))
                continue;
            
            // 原有的位置更新逻辑...
        }
    }
    
  2. 优化Lerp的趋近逻辑
    固定0.1的Lerp系数会导致物体无限接近目标但永远无法到达,可替换为基于时间的平滑移动,同时设置距离阈值直接归位:

    float moveSpeed = 8f; // 可根据需求调整速度
    float distanceThreshold = 0.02f;
    if (Vector3.Distance(curCard.transform.position, newLoc) > distanceThreshold)
    {
        curCard.transform.position = Vector3.MoveTowards(curCard.transform.position, newLoc, moveSpeed * Time.deltaTime);
    }
    else
    {
        curCard.transform.position = newLoc;
    }
    
  3. 检查方法调用时机
    确认UpdateCardPosition没有被多个对象重复调用,避免同一帧内多次修改同一卡片的位置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 02:45:20