昨天有朋友问我了一个问题,它将Hierarchy视图里的某个子节点下的GameObject拷贝到另外一个对象的子节点下面,他使用的方法就是 transform.parent = parent 但是拷贝过去以后坐标就全乱了。如下图所示我们搭建一个测试环境,我的目标是把a2拷贝在b2下面。
如下图所示,a0 a1 和 b0 b1作为父节点, 为了验证测试的可行性,我把它们的坐标 旋转 缩放 完全搞乱。
一 . 不改变拷贝坐标的情况下
1.直接copy 这个是最简单的
1 2 3 4 5 6 |
private void MoveGameObject(GameObject copy,Transform parent) { copy.transform.parent = parent; } |
2.先实例化一份新的,然后在copy ,重点说说这个,因为他出问题的也是在这里。
1 2 3 4 5 6 7 8 9 10 11 12 |
private void CopyGameObject(GameObject copy,Transform parent) { GameObject go = Instantiate(copy) as GameObject; go.transform.parent = parent; go.transform.position = copy.transform.position; go.transform.rotation = copy.transform.rotation; Vector3 pLoss = copy.transform.lossyScale; Vector3 panelLoss = parent.lossyScale; go.transform.localScale = new Vector3((pLoss.x/panelLoss.x),(pLoss.y/panelLoss.y),(pLoss.z/panelLoss.z)); } |
1. GameObject go = Instantiate(copy) as GameObject;
实例化一份新的GameObject 在根目录下,此时 坐标、旋转、缩放系数取的是copy的相对坐标。那么这一步就坐标就已经乱了。。
2.go.transform.parent = parent;
仅仅是move的操作,换算到相对parent的坐标 旋转 缩放 。
3.go.transform.position = copy.transform.position;
go.transform.rotation = copy.transform.rotation;
Unity的Transform组件中看到的位置、旋转、缩放,都是相对父节点的,它并不是相对世界的。所以此时需要把 “被拷贝者” 的世界坐标系数拷贝给 “拷贝者”
4. Vector3 pLoss = copy.transform.lossyScale;
Vector3 panelLoss = parent.lossyScale;
go.transform.localScale = new Vector3((pLoss.x/panelLoss.x),(pLoss.y/panelLoss.y),
因为Unity不能直接设置世界缩放系数,只能设置相对缩放系数。所以这里我利用lossyScale来换算了一下相对坐标,lossyScale是一个只读的属性,就是只读某个对象的世界缩放系数。
二 . 改变拷贝坐标的情况下
这种情况一般都是从Resources.Load后实例化的。实例化完毕后把Prefab里面预先设置的拷贝给Instiate()后的对象。
1 2 3 4 5 6 7 8 9 10 11 |
private void LoadPrefab(string name,Transform parent) { GameObject prefab = Resources.Load<GameObject>(name); GameObject go = Instantiate(prefab) as GameObject; go.transform.parent = parent; go.transform.localPosition = prefab.transform.position; go.transform.localRotation = prefab.transform.rotation; go.transform.localScale = prefab.transform.localScale; } |
其实大多数情况下 都用 localPostion:000 localRotation:000 localScale:111。
1 2 3 4 5 6 7 8 9 10 11 |
private void LoadPrefab(string name,Transform parent) { GameObject prefab = Resources.Load<GameObject>(name); GameObject go = Instantiate(prefab) as GameObject; go.transform.parent = parent; go.transform.localPosition = Vector3.zero; go.transform.localRotation = Quaternion.Euler(Vector3.zero); go.transform.localScale = Vector3.one } |
相对坐标、旋转 localPosition localRotation (可以在Transform组件中看到)
世界坐标、旋转 position rotation(不能在编辑器中看到, 可以通过代码输出出来)
只有localScale比较特殊,它的世界缩放系数lossyScale是只读的,但是不能写。
复制过去的两个完全重合。。
- 本文固定链接: https://www.xuanyusong.com/archives/3151
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
同一个对象,先放到格子大的背包里,用代码this.transform.localScale = Vector3.one;让该对象适应背包格子的大小,再放到穿戴栏咯,用this.transform.localScale = Vector3.one;该对象的大小怎么没适应穿戴栏的格子大小,求解怎么解决,对象的子节点都是其所在的格子
transform.setparent(obj.transform,false);
tmd,写的太好了,解决了我的问题iVector3 panelLoss = parent.lossyScale;go.transform.localScale = new Vector3((pLoss.x/panelLoss.x),(pLoss.y/panelLoss.y),(pLoss.z/panelLoss.z));估计是prefab建立的原因,动态加了之后“飞到场外去了”,坐标问题,加了这几句就好了
tmd,写的太好了,解决了我的问题i Vector3 panelLoss = parent.lossyScale; go.transform.localScale = new Vector3((pLoss.x/panelLoss.x),(pLoss.y/panelLoss.y),(pLoss.z/panelLoss.z));估计是prefab建立的原因,动态加了之后“飞到场外去了”,坐标问题,加了这几句就好了
用 transform.SetParent(Transform parent, bool worldPositionStays),然后 第二个bool 设为 false,也不会乱。这个方法如何呢?
这是新方法, 可以用这个。。
看到这篇文章,感觉又理解了许多,之前美工做好的prefab,需要去替换以前的prefab,第一次我直接拖到以前prefab的子节点下,坐标就乱了。后来写了个脚本,用代码替换,第一张方法,也解决了问题。今天看到了松哥 的讲解,原来并不是最优做法法,学习了。
如果a0和 b0的缩放中x y z 三个值不一样 那还是会乱掉
雨松 页面的图片特效怪怪的,每次mouse移上去都会抖几下。
松哥,问你个问题~~我用的是3d ui,界面有点倾斜(更改了一下y轴),有个grid子物体选的是垂直排版。我往grid里面实例化元素时元素的localposition也都调成0了,但运行时grid把元素的z坐标变了(不为0了),怎么样把元素z坐标调回0啊?(是在grid的 OnDisable里面调整每个元素的z坐标吗?)
Hi,雨松~ 首先谢谢你的分享,有个问题,第二段代码中有句Vector3 panelLoss = Panel.lossyScale; “Panel”是哪个transform?
在场景中随便找个物体把transform赋给Panel好像都能成功~