旋转父物体时更新子物体位置: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
相关产品推荐
相关产品推荐

