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到另一个目标,导致位置在两个目标间拉扯,永远无法到达最终点。
具体修复方案
避免重复处理同一对象
在第一段遍历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; // 原有的位置更新逻辑... } }优化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; }检查方法调用时机
确认UpdateCardPosition没有被多个对象重复调用,避免同一帧内多次修改同一卡片的位置。
内容的提问来源于stack exchange,提问作者Aaron Lee
相关产品推荐
相关产品推荐

