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

旋转父物体时更新子物体位置:3D俄罗斯方块旋转问题求助

解决3D俄罗斯方块Tetromino旋转后子物体位置不同步的问题

嘿,我太懂你这种卡壳的感觉了——刚学Unity做3D俄罗斯方块,旋转方块这块折腾好几天都不对,简直头大!咱们先把问题根源捋清楚,再给你实打实的解决办法:

为什么直接旋转父物体会出问题?

你现在是直接对空父物体用transform.Rotate(0, 0, -90),这种方式本质是让父物体带着子物体做旋转变换,但子物体的localPosition(相对于父物体的局部坐标)是不会变的——你看到中间方块视觉上移动,其实是父物体旋转带动它的世界坐标变了,但它的局部坐标还是原来的值,这就导致你看transform.position(世界坐标)的时候,可能因为父旋转的影响产生误解,而且这种方式会让方块的位置脱离网格(出现小数坐标),后续碰撞检测、移动都会乱套。

俄罗斯方块的旋转逻辑,核心不是“旋转父物体”,而是计算每个子方块旋转后的目标网格位置,然后直接更新它们的坐标,同时保持父物体无旋转状态。

正确的实现步骤

1. 确定旋转中心

对于T型方块,旋转中心就是中间那个立方体的位置(不管是世界坐标还是父物体的局部坐标都可以,统一就行)。

2. 计算每个方块旋转后的位置

遍历所有子方块,以旋转中心为原点,计算它们旋转后的新坐标:

  • 先算出当前方块相对于旋转中心的偏移量
  • 用四元数(Quaternion)对偏移量进行旋转变换
  • 把旋转后的偏移量加回旋转中心,得到新位置
  • 别忘了把坐标对齐到网格(四舍五入到整数,因为俄方块每个格子都是整数坐标)

3. 重置父物体旋转

所有子方块位置更新完后,把父物体的旋转重置为初始状态(无旋转),避免后续移动、旋转受父物体旋转状态干扰。

代码示例(C#)

假设你的父物体是tetrominoParent,中间方块打了"CenterBlock"标签,直接把这段代码挂在父物体上就行:

using UnityEngine;

public class TetrominoRotation : MonoBehaviour
{
    public void RotateZMinus90()
    {
        // 找到旋转中心(中间的方块)
        Transform centerBlock = transform.Find("CenterBlock");
        if (centerBlock == null)
        {
            Debug.LogError("找不到中心方块!请给中间的Cube添加CenterBlock标签");
            return;
        }

        Vector3 rotationCenter = centerBlock.position;
        // 定义要旋转的角度(这里是绕Z轴转-90度)
        Quaternion rotateQuaternion = Quaternion.Euler(0, 0, -90);

        // 遍历所有子方块,更新位置
        foreach (Transform block in transform)
        {
            // 跳过中心方块(旋转后位置不变)
            if (block == centerBlock) continue;

            // 计算当前方块到旋转中心的偏移
            Vector3 offset = block.position - rotationCenter;
            // 旋转偏移量
            Vector3 rotatedOffset = rotateQuaternion * offset;
            // 计算新位置并对齐到网格
            Vector3 newPosition = rotationCenter + rotatedOffset;
            newPosition = new Vector3(
                Mathf.Round(newPosition.x),
                Mathf.Round(newPosition.y),
                Mathf.Round(newPosition.z)
            );
            // 设置新位置
            block.position = newPosition;
        }

        // 重置父物体的旋转,避免后续操作受影响
        transform.rotation = Quaternion.identity;
    }
}

额外注意点

  • 如果你的方块是用局部坐标管理的,把代码里的position换成localPosition,rotationCenter也用centerBlock.localPosition就行,逻辑是一样的。
  • 旋转前最好先检测新位置是否会超出边界或者和其他方块碰撞,避免旋转后方块穿墙。

这样操作后,每个子方块的transform.position都会正确更新到旋转后的网格位置,再也不会出现“视觉移动但坐标没变”的问题啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:53:16