旋转立方体并追踪它的边
Rotate Cube and track its sides
我一直在尝试解决旋转体素(3d 立方体)并在旋转后跟踪边的问题。
以这张图片为例。
旋转后,我需要知道后面的边在哪里。例如,如果我将此立方体沿其 Z 轴旋转 90 度,则 Y 和 X 将交换。
这适用于用 Unity 编写的 3d 体素游戏的服务器端 mod。所以 Unity methods/utils 也可用。但这又是服务器端和 mod,所以我无法访问网格或对象本身,我只能告诉它旋转 x、y 或 z,并且需要根据最终旋转执行逻辑。如果有人能指出我的大致方向或告诉我可以实现此目的的方法,我将不胜感激。谢谢!
编辑:旋转存储在 x、y、z 旋转中
也许有点 "stupid" 解决方案,但我会简单地将相应的边名称存储在一个数组中,并针对特定轴的每 90° 步长执行相应的值偏移。
所以让我们说例如在默认状态下你有
0 : X_l
1 : Z_u
2 : Y_l
3 : Z_l
4 : Y_u
5 : X_u
那么实际你需要知道的是每个轴和每个方向(+
或-
)一个90°步长的变化矩阵:
X轴
positive step negative step
original index 0 | 1 | 2 | 3 | 4 | 5 0 | 1 | 2 | 3 | 4 | 5
new index 0 | 2 | 3 | 4 | 1 | 5 0 | 4 | 1 | 2 | 1 | 0
Y轴
positive step negative step
original index 0 | 1 | 2 | 3 | 4 | 5 0 | 1 | 2 | 3 | 4 | 5
new index 3 | 0 | 2 | 5 | 4 | 1 1 | 5 | 2 | 0 | 4 | 3
Z轴
positive step negative step
original index 0 | 1 | 2 | 3 | 4 | 5 0 | 1 | 2 | 3 | 4 | 5
new index 4 | 1 | 0 | 3 | 5 | 2 2 | 1 | 5 | 3 | 0 | 4
我在 class Cube
中实现了这个
// The possible names of your cube sides
public enum CubeSideName
{
X_l,
X_u,
Y_l,
Y_u,
Z_l,
Z_u
}
// This stores the relationship between one certain
// position (Front,Back,Top,Bottom,Right,Left)
// and a cube side (x_l, x_u, y_l, y_u, z_l, z_u)
[Serializable]
public struct CubeSidePair
{
// For the example I used GameObjects with according names
// instead of GameObjects you could also simply have a string ID or another enum
// for the name of the according position
public GameObject GameObject;
public CubeSideName Name;
}
[Serializable]
public class Cube
{
// This stores which position (Front,Back,Top,Bottom,Right,Left)
// is currently taken by which cube side (x_l, x_u, y_l, y_u, z_l, z_u)
public CubeSidePair[] CubeSidesPair = new CubeSidePair[6];
public Vector3Int Rotation
{
get { return _rotation; }
set
{
UpdateRotation(value);
}
}
// This is actually just for making it visual
private readonly Dictionary<CubeSideName, Color> colors = new Dictionary<CubeSideName, Color>(6)
{
{CubeSideName.X_u, Color.blue },
{CubeSideName.X_l, Color.cyan },
{CubeSideName.Y_u, Color.red },
{CubeSideName.Y_l, Color.magenta },
{CubeSideName.Z_u,Color.green },
{CubeSideName.Z_l,Color.yellow }
};
[Header("Debug only")]
[SerializeField] private Vector3Int _rotation;
public void Reset()
{
_rotation = Vector3Int.zero;
CubeSidesPair[0].Name = CubeSideName.X_l;
CubeSidesPair[1].Name = CubeSideName.Z_u;
CubeSidesPair[2].Name = CubeSideName.Y_l;
CubeSidesPair[3].Name = CubeSideName.Z_l;
CubeSidesPair[4].Name = CubeSideName.Y_u;
CubeSidesPair[5].Name = CubeSideName.X_u;
UpdateColors();
}
// Here all the magic happens
private void UpdateRotation(Vector3Int newRotaion)
{
// get difference to current rotation
var newRotationInput = newRotaion - _rotation;
// Go in 90° steps around the according axis
// untilt he rotation is done
while (newRotationInput != Vector3Int.zero)
{
// For each rotation step just take the index matrices from before
// and use them to perform an array shift
if (newRotationInput.x < 0)
{
// do negative X rotation
var temp = CubeSidesPair[1].Name;
CubeSidesPair[1].Name = CubeSidesPair[2].Name;
CubeSidesPair[2].Name = CubeSidesPair[3].Name;
CubeSidesPair[3].Name = CubeSidesPair[4].Name;
CubeSidesPair[4].Name = temp;
newRotationInput.x += 90;
}
else if (newRotationInput.x > 0)
{
// do positive X rotation
var temp = CubeSidesPair[4].Name;
CubeSidesPair[4].Name = CubeSidesPair[3].Name;
CubeSidesPair[3].Name = CubeSidesPair[2].Name;
CubeSidesPair[2].Name = CubeSidesPair[1].Name;
CubeSidesPair[1].Name = temp;
newRotationInput.x -= 90;
}
else if (newRotationInput.y < 0)
{
// do negative Y rotation
var temp = CubeSidesPair[1].Name;
CubeSidesPair[1].Name = CubeSidesPair[0].Name;
CubeSidesPair[0].Name = CubeSidesPair[3].Name;
CubeSidesPair[3].Name = CubeSidesPair[5].Name;
CubeSidesPair[5].Name = temp;
newRotationInput.y += 90;
}
else if (newRotationInput.y > 0)
{
// do positive Y rotation
var temp = CubeSidesPair[3].Name;
CubeSidesPair[3].Name = CubeSidesPair[0].Name;
CubeSidesPair[0].Name = CubeSidesPair[1].Name;
CubeSidesPair[1].Name = CubeSidesPair[5].Name;
CubeSidesPair[5].Name = temp;
newRotationInput.y -= 90;
}
else if (newRotationInput.z < 0)
{
// do negative Z rotation
var temp = CubeSidesPair[2].Name;
CubeSidesPair[2].Name = CubeSidesPair[0].Name;
CubeSidesPair[0].Name = CubeSidesPair[4].Name;
CubeSidesPair[4].Name = CubeSidesPair[5].Name;
CubeSidesPair[5].Name = temp;
newRotationInput.z += 90;
}
else if (newRotationInput.z > 0)
{
// do positive Z rotation
var temp = CubeSidesPair[4].Name;
CubeSidesPair[4].Name = CubeSidesPair[0].Name;
CubeSidesPair[0].Name = CubeSidesPair[2].Name;
CubeSidesPair[2].Name = CubeSidesPair[5].Name;
CubeSidesPair[5].Name = temp;
newRotationInput.z -= 90;
}
}
_rotation = newRotaion;
UpdateColors();
}
// Just for the visual
private void UpdateColors()
{
foreach (var cubeSide in CubeSidesPair)
{
var renderer = cubeSide.GameObject.GetComponent<Renderer>();
renderer.material.color = colors[cubeSide.Name];
}
}
}
这是我在演示中使用它的方式(见底部):
public class CubeController : MonoBehaviour
{
public Cube Cube;
private void Awake()
{
// Initial setup
Cube.Reset();
}
private void Update()
{
var multiplier = 90;
if (Input.GetKey(KeyCode.LeftShift))
{
multiplier = -90;
}
if (Input.GetKeyDown(KeyCode.X))
{
Cube.Rotation += Vector3Int.right * multiplier;
}
else if (Input.GetKeyDown(KeyCode.Y))
{
Cube.Rotation += Vector3Int.up * multiplier;
}
else if (Input.GetKeyDown(KeyCode.Z))
{
Cube.Rotation += new Vector3Int(0, 0, 1) * multiplier;
}
}
}
我希望我能把这个想法形象化一点;)
我当然只是逐步旋转,但如果进入像
这样的固定旋转,它应该以相同的方式工作
Cube.Rotation = new Vector3(-90, 180, 270);
但是,您可能想要更改旋转的顺序。
我一直在尝试解决旋转体素(3d 立方体)并在旋转后跟踪边的问题。
以这张图片为例。
旋转后,我需要知道后面的边在哪里。例如,如果我将此立方体沿其 Z 轴旋转 90 度,则 Y 和 X 将交换。
这适用于用 Unity 编写的 3d 体素游戏的服务器端 mod。所以 Unity methods/utils 也可用。但这又是服务器端和 mod,所以我无法访问网格或对象本身,我只能告诉它旋转 x、y 或 z,并且需要根据最终旋转执行逻辑。如果有人能指出我的大致方向或告诉我可以实现此目的的方法,我将不胜感激。谢谢!
编辑:旋转存储在 x、y、z 旋转中
也许有点 "stupid" 解决方案,但我会简单地将相应的边名称存储在一个数组中,并针对特定轴的每 90° 步长执行相应的值偏移。
所以让我们说例如在默认状态下你有
0 : X_l
1 : Z_u
2 : Y_l
3 : Z_l
4 : Y_u
5 : X_u
那么实际你需要知道的是每个轴和每个方向(+
或-
)一个90°步长的变化矩阵:
X轴
positive step negative step
original index 0 | 1 | 2 | 3 | 4 | 5 0 | 1 | 2 | 3 | 4 | 5
new index 0 | 2 | 3 | 4 | 1 | 5 0 | 4 | 1 | 2 | 1 | 0
Y轴
positive step negative step
original index 0 | 1 | 2 | 3 | 4 | 5 0 | 1 | 2 | 3 | 4 | 5
new index 3 | 0 | 2 | 5 | 4 | 1 1 | 5 | 2 | 0 | 4 | 3
Z轴
positive step negative step
original index 0 | 1 | 2 | 3 | 4 | 5 0 | 1 | 2 | 3 | 4 | 5
new index 4 | 1 | 0 | 3 | 5 | 2 2 | 1 | 5 | 3 | 0 | 4
我在 class Cube
中实现了这个
// The possible names of your cube sides
public enum CubeSideName
{
X_l,
X_u,
Y_l,
Y_u,
Z_l,
Z_u
}
// This stores the relationship between one certain
// position (Front,Back,Top,Bottom,Right,Left)
// and a cube side (x_l, x_u, y_l, y_u, z_l, z_u)
[Serializable]
public struct CubeSidePair
{
// For the example I used GameObjects with according names
// instead of GameObjects you could also simply have a string ID or another enum
// for the name of the according position
public GameObject GameObject;
public CubeSideName Name;
}
[Serializable]
public class Cube
{
// This stores which position (Front,Back,Top,Bottom,Right,Left)
// is currently taken by which cube side (x_l, x_u, y_l, y_u, z_l, z_u)
public CubeSidePair[] CubeSidesPair = new CubeSidePair[6];
public Vector3Int Rotation
{
get { return _rotation; }
set
{
UpdateRotation(value);
}
}
// This is actually just for making it visual
private readonly Dictionary<CubeSideName, Color> colors = new Dictionary<CubeSideName, Color>(6)
{
{CubeSideName.X_u, Color.blue },
{CubeSideName.X_l, Color.cyan },
{CubeSideName.Y_u, Color.red },
{CubeSideName.Y_l, Color.magenta },
{CubeSideName.Z_u,Color.green },
{CubeSideName.Z_l,Color.yellow }
};
[Header("Debug only")]
[SerializeField] private Vector3Int _rotation;
public void Reset()
{
_rotation = Vector3Int.zero;
CubeSidesPair[0].Name = CubeSideName.X_l;
CubeSidesPair[1].Name = CubeSideName.Z_u;
CubeSidesPair[2].Name = CubeSideName.Y_l;
CubeSidesPair[3].Name = CubeSideName.Z_l;
CubeSidesPair[4].Name = CubeSideName.Y_u;
CubeSidesPair[5].Name = CubeSideName.X_u;
UpdateColors();
}
// Here all the magic happens
private void UpdateRotation(Vector3Int newRotaion)
{
// get difference to current rotation
var newRotationInput = newRotaion - _rotation;
// Go in 90° steps around the according axis
// untilt he rotation is done
while (newRotationInput != Vector3Int.zero)
{
// For each rotation step just take the index matrices from before
// and use them to perform an array shift
if (newRotationInput.x < 0)
{
// do negative X rotation
var temp = CubeSidesPair[1].Name;
CubeSidesPair[1].Name = CubeSidesPair[2].Name;
CubeSidesPair[2].Name = CubeSidesPair[3].Name;
CubeSidesPair[3].Name = CubeSidesPair[4].Name;
CubeSidesPair[4].Name = temp;
newRotationInput.x += 90;
}
else if (newRotationInput.x > 0)
{
// do positive X rotation
var temp = CubeSidesPair[4].Name;
CubeSidesPair[4].Name = CubeSidesPair[3].Name;
CubeSidesPair[3].Name = CubeSidesPair[2].Name;
CubeSidesPair[2].Name = CubeSidesPair[1].Name;
CubeSidesPair[1].Name = temp;
newRotationInput.x -= 90;
}
else if (newRotationInput.y < 0)
{
// do negative Y rotation
var temp = CubeSidesPair[1].Name;
CubeSidesPair[1].Name = CubeSidesPair[0].Name;
CubeSidesPair[0].Name = CubeSidesPair[3].Name;
CubeSidesPair[3].Name = CubeSidesPair[5].Name;
CubeSidesPair[5].Name = temp;
newRotationInput.y += 90;
}
else if (newRotationInput.y > 0)
{
// do positive Y rotation
var temp = CubeSidesPair[3].Name;
CubeSidesPair[3].Name = CubeSidesPair[0].Name;
CubeSidesPair[0].Name = CubeSidesPair[1].Name;
CubeSidesPair[1].Name = CubeSidesPair[5].Name;
CubeSidesPair[5].Name = temp;
newRotationInput.y -= 90;
}
else if (newRotationInput.z < 0)
{
// do negative Z rotation
var temp = CubeSidesPair[2].Name;
CubeSidesPair[2].Name = CubeSidesPair[0].Name;
CubeSidesPair[0].Name = CubeSidesPair[4].Name;
CubeSidesPair[4].Name = CubeSidesPair[5].Name;
CubeSidesPair[5].Name = temp;
newRotationInput.z += 90;
}
else if (newRotationInput.z > 0)
{
// do positive Z rotation
var temp = CubeSidesPair[4].Name;
CubeSidesPair[4].Name = CubeSidesPair[0].Name;
CubeSidesPair[0].Name = CubeSidesPair[2].Name;
CubeSidesPair[2].Name = CubeSidesPair[5].Name;
CubeSidesPair[5].Name = temp;
newRotationInput.z -= 90;
}
}
_rotation = newRotaion;
UpdateColors();
}
// Just for the visual
private void UpdateColors()
{
foreach (var cubeSide in CubeSidesPair)
{
var renderer = cubeSide.GameObject.GetComponent<Renderer>();
renderer.material.color = colors[cubeSide.Name];
}
}
}
这是我在演示中使用它的方式(见底部):
public class CubeController : MonoBehaviour
{
public Cube Cube;
private void Awake()
{
// Initial setup
Cube.Reset();
}
private void Update()
{
var multiplier = 90;
if (Input.GetKey(KeyCode.LeftShift))
{
multiplier = -90;
}
if (Input.GetKeyDown(KeyCode.X))
{
Cube.Rotation += Vector3Int.right * multiplier;
}
else if (Input.GetKeyDown(KeyCode.Y))
{
Cube.Rotation += Vector3Int.up * multiplier;
}
else if (Input.GetKeyDown(KeyCode.Z))
{
Cube.Rotation += new Vector3Int(0, 0, 1) * multiplier;
}
}
}
我希望我能把这个想法形象化一点;)
我当然只是逐步旋转,但如果进入像
这样的固定旋转,它应该以相同的方式工作Cube.Rotation = new Vector3(-90, 180, 270);
但是,您可能想要更改旋转的顺序。