尽管坐标设置为 0、0、0,但具有许多子项的对象不会出现在中间
Object with many children does not show up in the middle although it has coordinates set to 0, 0, 0
我正在用unity做一个魔方生成器。每个部分基本上都是一个 1x1 的立方体,它将在我的代码中以更大的立方体的形状重复作为空对象的子对象。空物恰好位于棋子的中间,所有棋子的起点都在中间。然而,当我把空的放在场景的中心时 (0, 0, 0) 它出现在不同的地方。
以下是小编的部分图片:
As you can see, the empty is in the center with coordinates set to 0, 0, 0
Now ,when it has children and the coordinates are all still 0, it shows in a different place
编辑:
@derHugo 帮助了我,但现在我创建立方体并将空对象设置到立方体中间的代码不起作用。
这是完整的代码:
public GameObject PiecePrefab;
public int CubeSize;
Vector3 avg;
Vector3 ijk;
int cubeCount = 0;
// Start is called before the first frame update
void Start()
{
//Vector3 orgpos = gameObject.transform.position;
if (CubeSize <= 0)
{
CubeSize = 1;
Debug.LogError("The cube can not be smaller than 1!");
}
else if (CubeSize > 30)
{
CubeSize = 30;
Debug.LogError("The cube should not be bigger than 30!");
}
avg = new Vector3(0, 0, 0);
for (float k = 0; k < CubeSize; k++)
{
for (float j = 0; j < CubeSize; j++)
{
for (float i = 0; i < CubeSize; i++)
{
if (i == CubeSize - 1 || i == 0)
{
CreatePiece(i, j, k);
}
else if (j == CubeSize - 1 || j == 0)
{
CreatePiece(i, j, k);
}
else if (k == CubeSize - 1 || k == 0)
{
CreatePiece(i, j, k);
}
}
}
}
avg /= cubeCount;
gameObject.transform.position = avg;
var _Go = GameObject.FindGameObjectsWithTag("KuutionPala");
foreach (GameObject KuutionPala in _Go)
{
KuutionPala.transform.SetParent(transform);
}
//gameObject.transform.localPosition = orgpos;
void CreatePiece(float x, float y, float z)
{
ijk = new Vector3(x, y, z);
avg += ijk;
cubeCount++;
Vector3 offset3D;
offset3D = new Vector3(x / CubeSize, y / CubeSize, z / CubeSize);
var Piece = Instantiate(PiecePrefab, offset3D, transform.rotation);
Piece.transform.localScale /= CubeSize;
//Debug.LogFormat("x:" + x);
//Debug.LogFormat("y:" + y);
//Debug.LogFormat("z:" + z);
}
}
}
我认为错误在这一行:
gameObject.transform.position = avg;
(抱歉,如果代码不好)
如上所述,Unity 中有两种枢轴模式(参见 Positioning GameObjects → Gizmo handle position toggles)
- Pivot: positions the Gizmo at the actual pivot point of the GameObject, as defined by the Transform component.
- Center: positions the Gizmo at a (geometrical) center position based on the selected GameObjects.
您的设置为 Center
,因此要更改该设置,请单击显示 Center
的按钮。
然后到你的代码
您目前 hoping/assuming 您的 parent 被正确放置在 0,0,0
。
然后你生成了 0
到 (CubeSize - 1)/2
范围内的所有方块,然后想要将中心向后移动。
我宁愿反其道而行之,预先计算出正确的本地偏移量,并直接将瓦片生成为具有正确偏移量的根的 children。分正反方向。
第 1 步:那个本地位置是什么?
要了解一般数学知识,请看两个例子。
假设您有 3 个索引为 0、1、2 的立方体。它们有 1/3 的延伸,所以实际上位置需要看起来像
-0.5 0 0.5
| . | . | . |
假设您有 4 个立方体,索引为 0、1、2、3 并延伸 1/4,那么位置需要看起来像
-0.5 0 0.5
| . | . | . | . |
正如您所见,最简单的方法是
- 从最小位置开始(例如
-0.5f * Vector3.one
)
- 始终为第一个偏移添加一半的扩展(例如
1/CubeSize * 0.5f * Vector3.one
)
- 添加扩展的偏移量乘以顶部的索引(例如
1/CubeSize * new Vector3(x,y,z)
)
所以在一起像
// be sure to cast to float here otherwise you get rounded ints
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
第 2 步:直接以 children 生成并具有正确的偏移量
void CreatePiece(float x, float y, float z)
{
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
var Piece = Instantiate(PiecePrefab, transform, false);
// This basically equals doing something like
//var Piece = Instantiate(PiecePrefab, transform.position, transform.rotation, transform);
Piece.transform.localPosition = offset;
Piece.transform.localScale = extends * Vector3.one;
}
然后您可以将代码缩减为
// Use a range so you directly clamp the value in the Inspector
[Range(1,30)]
public int CubeSize = 3;
// Start is called before the first frame update
void Start()
{
UpdateTiles();
}
// Using this you can already test the method without entering playmode
// via the context menu of the component
[ContextMenu(nameof(UpdateTiles)])
public void UpdateTiles()
{
// Destroy current children before spawning the new ones
foreach(var child in GetComponentsInChildren<Transform>().Where(child => child != transform)
{
if(!child) continue;
if(Application.isPlaying)
{
Destroy(child.gameObject);
}
else
{
DestroyImmediate(child.gameObject);
}
}
if (CubeSize < 1)
{
CubeSize = 1;
Debug.LogError("The cube can not be smaller than 1!");
}
else if (CubeSize > 30)
{
CubeSize = 30;
Debug.LogError("The cube should not be bigger than 30!");
}
// For making things easier to read I would use x,y,z here as well ;)
for (float x = 0; x < CubeSize; x++)
{
for (float y = 0; y < CubeSize; y++)
{
for (float z = 0; z < CubeSize; z++)
{
if (x == CubeSize - 1 || x == 0)
{
CreatePiece(x, y, z);
}
else if (y == CubeSize - 1 || y == 0)
{
CreatePiece(x, y, z);
}
else if (z == CubeSize - 1 || z == 0)
{
CreatePiece(x, y, z);
}
}
}
}
}
private void CreatePiece(float x, float y, float z)
{
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
var Piece = Instantiate(PiecePrefab, transform, false);
Piece.transform.localPosition = offset;
Piece.transform.localScale = extends * Vector3.one;
}
我正在用unity做一个魔方生成器。每个部分基本上都是一个 1x1 的立方体,它将在我的代码中以更大的立方体的形状重复作为空对象的子对象。空物恰好位于棋子的中间,所有棋子的起点都在中间。然而,当我把空的放在场景的中心时 (0, 0, 0) 它出现在不同的地方。 以下是小编的部分图片:
As you can see, the empty is in the center with coordinates set to 0, 0, 0
Now ,when it has children and the coordinates are all still 0, it shows in a different place
编辑: @derHugo 帮助了我,但现在我创建立方体并将空对象设置到立方体中间的代码不起作用。 这是完整的代码:
public GameObject PiecePrefab; public int CubeSize; Vector3 avg; Vector3 ijk; int cubeCount = 0; // Start is called before the first frame update void Start() { //Vector3 orgpos = gameObject.transform.position; if (CubeSize <= 0) { CubeSize = 1; Debug.LogError("The cube can not be smaller than 1!"); } else if (CubeSize > 30) { CubeSize = 30; Debug.LogError("The cube should not be bigger than 30!"); } avg = new Vector3(0, 0, 0); for (float k = 0; k < CubeSize; k++) { for (float j = 0; j < CubeSize; j++) { for (float i = 0; i < CubeSize; i++) { if (i == CubeSize - 1 || i == 0) { CreatePiece(i, j, k); } else if (j == CubeSize - 1 || j == 0) { CreatePiece(i, j, k); } else if (k == CubeSize - 1 || k == 0) { CreatePiece(i, j, k); } } } } avg /= cubeCount; gameObject.transform.position = avg; var _Go = GameObject.FindGameObjectsWithTag("KuutionPala"); foreach (GameObject KuutionPala in _Go) { KuutionPala.transform.SetParent(transform); } //gameObject.transform.localPosition = orgpos; void CreatePiece(float x, float y, float z) { ijk = new Vector3(x, y, z); avg += ijk; cubeCount++; Vector3 offset3D; offset3D = new Vector3(x / CubeSize, y / CubeSize, z / CubeSize); var Piece = Instantiate(PiecePrefab, offset3D, transform.rotation); Piece.transform.localScale /= CubeSize; //Debug.LogFormat("x:" + x); //Debug.LogFormat("y:" + y); //Debug.LogFormat("z:" + z); } } }
我认为错误在这一行:
gameObject.transform.position = avg;
(抱歉,如果代码不好)
如上所述,Unity 中有两种枢轴模式(参见 Positioning GameObjects → Gizmo handle position toggles)
- Pivot: positions the Gizmo at the actual pivot point of the GameObject, as defined by the Transform component.
- Center: positions the Gizmo at a (geometrical) center position based on the selected GameObjects.
您的设置为 Center
,因此要更改该设置,请单击显示 Center
的按钮。
然后到你的代码
您目前 hoping/assuming 您的 parent 被正确放置在 0,0,0
。
然后你生成了 0
到 (CubeSize - 1)/2
范围内的所有方块,然后想要将中心向后移动。
我宁愿反其道而行之,预先计算出正确的本地偏移量,并直接将瓦片生成为具有正确偏移量的根的 children。分正反方向。
第 1 步:那个本地位置是什么?
要了解一般数学知识,请看两个例子。
假设您有 3 个索引为 0、1、2 的立方体。它们有 1/3 的延伸,所以实际上位置需要看起来像
-0.5 0 0.5
| . | . | . |
假设您有 4 个立方体,索引为 0、1、2、3 并延伸 1/4,那么位置需要看起来像
-0.5 0 0.5
| . | . | . | . |
正如您所见,最简单的方法是
- 从最小位置开始(例如
-0.5f * Vector3.one
) - 始终为第一个偏移添加一半的扩展(例如
1/CubeSize * 0.5f * Vector3.one
) - 添加扩展的偏移量乘以顶部的索引(例如
1/CubeSize * new Vector3(x,y,z)
)
所以在一起像
// be sure to cast to float here otherwise you get rounded ints
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
第 2 步:直接以 children 生成并具有正确的偏移量
void CreatePiece(float x, float y, float z)
{
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
var Piece = Instantiate(PiecePrefab, transform, false);
// This basically equals doing something like
//var Piece = Instantiate(PiecePrefab, transform.position, transform.rotation, transform);
Piece.transform.localPosition = offset;
Piece.transform.localScale = extends * Vector3.one;
}
然后您可以将代码缩减为
// Use a range so you directly clamp the value in the Inspector
[Range(1,30)]
public int CubeSize = 3;
// Start is called before the first frame update
void Start()
{
UpdateTiles();
}
// Using this you can already test the method without entering playmode
// via the context menu of the component
[ContextMenu(nameof(UpdateTiles)])
public void UpdateTiles()
{
// Destroy current children before spawning the new ones
foreach(var child in GetComponentsInChildren<Transform>().Where(child => child != transform)
{
if(!child) continue;
if(Application.isPlaying)
{
Destroy(child.gameObject);
}
else
{
DestroyImmediate(child.gameObject);
}
}
if (CubeSize < 1)
{
CubeSize = 1;
Debug.LogError("The cube can not be smaller than 1!");
}
else if (CubeSize > 30)
{
CubeSize = 30;
Debug.LogError("The cube should not be bigger than 30!");
}
// For making things easier to read I would use x,y,z here as well ;)
for (float x = 0; x < CubeSize; x++)
{
for (float y = 0; y < CubeSize; y++)
{
for (float z = 0; z < CubeSize; z++)
{
if (x == CubeSize - 1 || x == 0)
{
CreatePiece(x, y, z);
}
else if (y == CubeSize - 1 || y == 0)
{
CreatePiece(x, y, z);
}
else if (z == CubeSize - 1 || z == 0)
{
CreatePiece(x, y, z);
}
}
}
}
}
private void CreatePiece(float x, float y, float z)
{
var extends = 1 / (float)CubeSize;
var offset = (-0.5f + extends * 0.5f) * Vector3.one + extends * new Vector3(x,y,z);
var Piece = Instantiate(PiecePrefab, transform, false);
Piece.transform.localPosition = offset;
Piece.transform.localScale = extends * Vector3.one;
}