碰撞后正确附加到GameObject?

如何在碰撞后正确地将GameObject附加(或“粘贴”)到另一个GameObject? 问题:我希望GameObject在碰撞后附加,即使它正在改变比例。

“附上碰撞”代码:

protected Transform stuckTo = null; protected Vector3 offset = Vector3.zero; public void LateUpdate() { if (stuckTo != null) transform.position = stuckTo.position - offset; } void OnCollisionEnter(Collision col) { rb = GetComponent(); rb.isKinematic = true; if(stuckTo == null || stuckTo != col.gameObject.transform) offset = col.gameObject.transform.position - transform.position; stuckTo = col.gameObject.transform; } 

此代码使GameObject在碰撞后完美连接。 但是当GameObject改变比例(当它附着时)时,它在视觉上不再看起来与它碰撞的任何东西相关联。 基本上,这段代码使GameObject在碰撞时仅保留原始比例。 如何让GameObject始终坚持与碰撞的任何东西? 它在过程中的规模是多少? 我想避免养育子女:“虽然有点不安全,但是养育对手会造成奇怪的结果,比如随机传送或物体开始疯狂地移动和旋转等等。” – SamedTarıkÇETİN: 评论 。

缩放脚本:

 public Transform object1; //this is the object that my future-scaling GameObject collided with. public Transform object2; //another object, the same scale as object1, somewhere else //(or vice versa) void Update () { float distance = Vector3.Distance (object1.position, object2.position); float original_width = 10; if (distance <= 10) { float scale_x = distance / original_width; scale_x = Mathf.Min (scale_x, 3.0f); transform.localScale = new Vector3 (scale_x * 3.0f, 3.0f / scale_x, 3.0f); } } 

您的基本想法是正确的,您的代码可以稍微修改以支持这一点。

这是诀窍:相反,不是将对象粘贴到它碰撞的对象上,而是创建一个虚拟游戏对象,让它在碰撞点称为“胶水”,并将对象粘贴到胶水上。 胶水对象然后是我们碰撞的对象的父级。

由于胶水只是一个虚拟对象,只有组件转换和一些脚本,因此育儿没有问题。

此外,请注意,如果我们有多个接触点,我们在哪个接触点创建胶水并不重要,并且也很容易将其扩展为支持旋转,请参见下文。

所以在碰撞时,我们现在唯一要做的就是创造一种胶水。 这是代码:

 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(); // 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(); 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

PS我看到你混合了变换和刚体的语义,因为它是在Kinematic刚体上完成的,这不是什么大问题,而只是一个建议:想想你是否真的需要对已经“卡住”他人的物体有刚性体,如果不 – 也许只是删除或禁用刚体而不是使其成为运动学。

你想要做的是缩放碰撞点。 您可以通过将枢轴点设置为碰撞点来实现此目的,当您缩放对象时,它将根据轴进行缩放。 模拟这个的最好方法是在Unity中使用精灵。

缩放关于枢轴点

在上图中,左上角的板条箱在中心有一个枢轴点,所以当你沿着x缩放它时,它会围绕该点进行缩放,增加它在枢轴点两侧的宽度。 但是当枢轴点设置在侧面时,就像左下角图像一样,当你缩放它时,它只能向左延伸(除非你当然是负面缩放)。

现在的问题是你无法轻易改变网格的枢轴点,所以有很多不同的解决办法。 一种方法是将网格附加到空的新gameObject,并相对于父网格调整网格的局部变换,模拟移动网格轴点。

以下代码的作用是确定碰撞点。 由于可能存在多个碰撞点,因此我得到它们的平均碰撞点。 然后我将网格的父级移动到碰撞点并调整网格局部位置,以便立方体的侧面位于该点,这用于将网格的轴点设置为碰撞点。

现在,当您缩放时,它将围绕碰撞点进行缩放,就像在上图中一样。

 public MeshRenderer _meshRenderer; public float _moveXDirection; public Rigidbody _rigidBody; public Transform _meshTransform; public bool _sticksToObjects; public ScalingScript _scalingScript; protected Transform _stuckTo = null; protected Vector3 _offset = Vector3.zero; void LateUpdate() { if (_stuckTo != null) { transform.position = _stuckTo.position - _offset; } } void OnCollisionEnter(Collision collision) { if (!_sticksToObjects) { return; } _rigidBody.isKinematic = true; // Get the approximate collision point and normal, as there // may be multipled collision points Vector3 contactPoint = Vector3.zero; Vector3 contactNormal = Vector3.zero; for (int i = 0; i < collision.contacts.Length; i++) { contactPoint += collision.contacts[i].point; contactNormal += collision.contacts[i].normal; } // Get the final, approximate, point and normal of collision contactPoint /= collision.contacts.Length; contactNormal /= collision.contacts.Length; // Move object to the collision point // This acts as setting the pivot point of the cube mesh to the collision point transform.position = contactPoint; // Adjust the local position of the cube so it is flush with the pivot point Vector3 meshLocalPosition = Vector3.zero; // Move the child so the side is at the collision point. // A x local position of 0 means the child is centered on the parent, // a value of 0.5 means it's to the right, and a value of -0.5 means it to the left meshLocalPosition.x = (0.5f * contactNormal.x); _meshTransform.localPosition = meshLocalPosition; if (_stuckTo == null || _stuckTo != collision.gameObject.transform) { _offset = collision.gameObject.transform.position - transform.position; } _stuckTo = collision.gameObject.transform; // Enable the scaling script if (_scalingScript != null) { _scalingScript.enabled = true; } } 

这是一个带有上述代码的示例项目: https : //www.dropbox.com/s/i6pdlw8mjs2sxcf/CubesAttached.zip?dl=0

改变全球

 protected Collider stuckTo = null; 

/////使用Collider而不是变换对象。 你可能会得到更好的解决方案。告诉我,如果它工作或给出任何错误,因为我没有尝试,如果它的工作,我想知道。

 void OnCollisionEnter(Collision col) { rb = GetComponent(); rb.isKinematic = true; if(stuckTo == null || stuckTo != col.gameObject.transform) offset = col.collider.bounds.center - transform.position; stuckTo = col.collider; } public void LateUpdate() { if (stuckTo != null) { Vector3 distance=stuckTo.bounds.extents + GetComponent().bounds.extents; transform.position = stuckTo.bounds.center + distance; } } 

确保你正在缩放stuckTo变换(连接了碰撞器的变换)而不是任何变换器,或者这不起作用。

如果stuckTo的比例是统一的:

 protected Transform stuckTo = null; protected Vector3 originalPositionOffset = Vector3.zero; protected Vector3 positionOffset = Vector3.zero; protected Vector3 originalScaleOfTheTarget = Vector3.zero; public void LateUpdate() { if (stuckTo != null){ positionOffset *= stuckTo.localScale.x; transform.position = stuckTo.position - positionOffset; } } void OnCollisionEnter(Collision col) { rb = GetComponent(); rb.isKinematic = true; if(stuckTo == null || stuckTo != col.gameObject.transform){ originalScaleOfTheTarget = col.gameObject.transform.localScale; originalPositionOffset = col.gameObject.transform.position - transform.position; originalPositionOffset /= originalScaleOfTheTarget.x; } stuckTo = col.gameObject.transform; } 

但如果stuckTo的比例不均匀:

 protected Transform stuckTo = null; protected Vector3 originalPositionOffset = Vector3.zero; protected Vector3 positionOffset = Vector3.zero; protected Vector3 originalScaleOfTheTarget = Vector3.zero; public void LateUpdate() { if (stuckTo != null){ positionOffset.x = originalPositionOffset.x * stuckTo.localScale.x; positionOffset.y = originalPositionOffset.y * stuckTo.localScale.y; positionOffset.z = originalPositionOffset.z * stuckTo.localScale.z; transform.position = stuckTo.position - positionOffset; } } void OnCollisionEnter(Collision col) { rb = GetComponent(); rb.isKinematic = true; if(stuckTo == null || stuckTo != col.gameObject.transform){ originalScaleOfTheTarget = col.gameObject.transform.localScale; originalPositionOffset = col.gameObject.transform.position - transform.position; originalPositionOffset.x /= originalScaleOfTheTarget.x; originalPositionOffset.y /= originalScaleOfTheTarget.y; originalPositionOffset.z /= originalScaleOfTheTarget.z; } stuckTo = col.gameObject.transform; } 

但仍然 – 你为什么要关注ÇETİN的建议人? 只要你知道自己在做什么,对父母的对手和刚体以及几乎任何东西都是完全安全的。 只需将你的粘性变换置于目标和bam之下! 如果出现问题,只需移除刚体组件或禁用对撞机组件。