您的基本想法是正确的,您的代码可以稍微修改以支持这一点。
技巧如下:不是将对象粘贴到与其碰撞的对象上,而是在碰撞点创建一个虚拟游戏对象(我们称其为“胶水”),然后将对象粘贴到胶水上。然后,粘合对象将成为我们碰撞对象的父对象。
由于glue只是一个虚拟对象,只有组件变换和一些脚本,因此父子关系没有问题。
另外,请注意,如果我们有多个接触点,在哪个接触点创建粘合并不重要,并且也很容易扩展它以支持旋转,请参见下文。
因此,在碰撞时,我们现在唯一要做的就是创建胶水。这是代码:
void CreateGlue(Vector3 position, GameObject other) {
// Here we create a glue object programatically, but you can make a prefab if you want.
// Glue object is a simple transform with Glue.cs script attached.
var glue = (new GameObject("glue")).AddComponent<Glue>();
// We set glue position at the contact point
glue.transform.position = position;
// This also enables us to support object rotation. We initially set glue rotation to the same value
// as our game object rotation. If you don't want rotation - simply remove this.
glue.transform.rotation = transform.rotation;
// We make the object we collided with a parent of glue object
glue.transform.SetParent(other.transform);
// And now we call glue initialization
glue.AttachObject(gameObject);
}
void OnCollisionEnter(Collision col)
{
// On collision we simply create a glue object at any contact point.
CreateGlue(col.contacts[0].point, col.gameObject);
}
这是 Glue.cs 脚本的样子,它将处理 LateUpdate 并修改转换。
public class Glue : MonoBehaviour {
protected Transform stuckTo = null;
protected Vector3 offset = Vector3.zero;
public void AttachObject(GameObject other)
{
// Basically - same code as yours with slight modifications
// Make rigidbody Kinematic
var rb = other.GetComponent<Rigidbody>();
rb.isKinematic = true;
// Calculate offset - pay attention the direction of the offset is now reverse
// since we attach glue to object and not object to glue. It can be modified to work
// the other way, it just seems more reasonable to set all "glueing" functionality
// at Glue object
offset = transform.position - other.transform.position;
stuckTo = other.transform;
}
public void LateUpdate()
{
if (stuckTo != null) {
// If you don't want to support rotation remove this line
stuckTo.rotation = transform.rotation;
stuckTo.position = transform.position - transform.rotation * offset;
}
}
// Just visualizing the glue point, remove if not needed
void OnDrawGizmos() {
Gizmos.color = Color.cyan;
Gizmos.DrawSphere(transform.position, 0.2f);
}
}
另外,请注意,按照此处建议的方式简单地对对象进行父级设置会给您带来一些额外的麻烦,因为缩放父级也会缩放子级,因此您必须将子级重新缩放回其原始大小。问题是这些缩放操作是相对于不同的锚点的,因此您还必须对对象位置进行额外的调整。虽然可以做到。
我还创建了一个小示例项目,请参见此处(Unity v5.2.f3):https://www.dropbox.com/s/whr85cmdp1tv7tv/GlueObjects.zip?dl=0 https://www.dropbox.com/s/whr85cmdp1tv7tv/GlueObjects.zip?dl=0
附:我看到你混合了变换和刚体语义,因为它是在运动学刚体上完成的,这不是什么大问题,而只是一个建议:想想你是否真的需要在已经“粘”到其他物体上的物体上使用刚体,如果不需要的话- 也许只是删除或禁用刚体,而不是使其成为运动学。