unity3d - 尽管坐标设置为 0、0、0,但具有许多子对象的对象不会显示在中间
问题描述
我正在做一个统一的魔方生成器。每个部分基本上都是一个 1x1 的立方体,在我的代码中,它会以一个更大的立方体的形状重复,作为一个空对象的子对象。空物在棋子的正中间,所有棋子的起源都在正中间。但是,当我将空白放置在场景的中心 (0, 0, 0) 时,它会出现在不同的位置。以下是编辑提供的一些图片:
编辑:@derHugo 帮助了我,但现在我创建立方体并将空对象设置到它们中间的代码不起作用。这是完整的代码:
公共 GameObject PiecePrefab; 公共 int CubeSize; Vector3 平均; 矢量3 ijk; 整数立方体计数 = 0; // 在第一帧更新之前调用 start 无效开始() { //Vector3 orgpos = gameObject.transform.position; 如果(立方体尺寸 <= 0) { 立方体尺寸 = 1; Debug.LogError("立方体不能小于1!"); } else if (CubeSize > 30) { 立方体尺寸 = 30; Debug.LogError("立方体不应大于 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); } 否则 if (k == CubeSize - 1 || k == 0) { CreatePiece(i, j, k); } } } } 平均/=立方体计数; gameObject.transform.position = avg; var _Go = GameObject.FindGameObjectsWithTag("KuutionPala"); foreach(_Go 中的游戏对象 KuutionPala) { KuutionPala.transform.SetParent(transform); } //gameObject.transform.localPosition = orgpos; 无效 CreatePiece(浮动 x,浮动 y,浮动 z) { ijk = new Vector3(x, y, z); 平均 += ijk; 立方体计数++; 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:将 Gizmo 定位在 GameObject 的实际轴心点,由 Transform 组件定义。
- Center:根据选定的游戏对象将 Gizmo 定位在(几何)中心位置。
您的设置为Center
so 以更改单击按钮上的Center
.
然后到你的代码
您目前只是希望/假设您的父母正确放置在0,0,0
.
然后你生成从0
到范围内的所有图块(CubeSize - 1)/2
,然后想要将中心移回。
我宁愿反过来,预先计算正确的局部偏移量,并直接将瓦片作为具有正确偏移量的根的子节点生成。分为正反两个方向。
第 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 步:直接生成为具有正确偏移的子代
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;
}
推荐阅读
- c# - 正则表达式将字符串中的日期与 where 子句匹配
- javascript - 会话超时时如何处理jsp应用程序中的多个登录页面显示?
- laravel - 定义模型关系时如何在表间而不是关系表上添加条件
- java - 如何更改浮点转换的精度?
- java - java - 如何在Java中使用OpenPDF创建一个使用动态行跨度/列跨度并放入单元格的表格?
- c# - 在字符串中查找单词并替换它
- azure - 无法在服务结构集群中下载 docker 映像
- android - webview 应用程序:选择文件不起作用
- google-apps-script - 如何从插件加载 Google Apps 脚本 UDF 以在 Google 表格中使用?
- javascript - 如何使用 Node.js 在 Google Cloud Storage 中更改文件的元数据