How can I properly make a GameObject attach (or "stick") to another GameObject after collision? The problem: I want the GameObject to attach after collision even if it is changing scale.
"Attach on collision" code:
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<Rigidbody>();
rb.isKinematic = true;
if(stuckTo == null
|| stuckTo != col.gameObject.transform)
offset = col.gameObject.transform.position - transform.position;
stuckTo = col.gameObject.transform;
}
This code makes a GameObject attach perfectly after collision. But when that GameObject changes scale (while it's attached), it visually no longer looks attached to whatever it collided with. Basically, this code makes the GameObject stick with only the original scale at the moment of the collision. How can I make the GameObject always stick to whatever it collided with? And with whatever scale it has during the process? I would like to avoid parenting: "It's a bit unsafe though, parenting colliders can cause weird results, like random teleporting or object starting to move and rotate insanely, etc." - Samed Tarık ÇETİN : comment.
Scaling script:
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);
}
}
change global
///// use Collider instead of transform object. You might get better solution.Inform me if it works or gives any error since i haven't tried if it works i would like to know.
What you want to do is scale about the collision point. You can achieve this by setting the pivot point to the collision point, that way when you scale the object it will be scaled based on the pivot. The best way to simulate this is using sprites in Unity.
In the above image, the top-left crate has a pivot point in the center, so when you scale it along x, it scales about that point, increasing it's width both sides of the pivot point. But when the pivot point is set to the side, like in the bottom left image, when you scale it, it can only extend it out to the left (unless you scale negatively of course).
Now the problem is you can't easily change the pivot point of mesh, so there are a number of different work-arounds for this. One such approach is to attach the mesh to an empty new gameObject and adjust the mesh's local transform in relation to the parent, simulating moving the meshes pivot point.
What the below code does is determine the collision point. Since there can be multiple collision points, I get the average collision point of them all. I then move the mesh's parent to the collision point and adjust the meshes local position so that the side of the cube is positioned at that point, this acts as setting the mesh's pivot point to the collision point.
Now when you scale, it will scale about the collision point, just like in the above image.
Here is an example project with the above code: https://www.dropbox.com/s/i6pdlw8mjs2sxcf/CubesAttached.zip?dl=0
Make sure that you are scaling the stuckTo transform (the one that has the collider attached to) and not any of it's parents or this will not work.
if the stuckTo's scale is uniform:
but if the stuckTo's scale is non-uniform:
But still though - why are you following ÇETİN's advice man? It's totally safe to parent colliders and rigidbodies and literally anything as long as you know what you are doing. Just parent your sticky transform under the target and bam! if something goes wrong just remove your rigidbody component or disable your collider component.
Your basic idea is right, your code can be modified slightly to support this.
Here is the trick: instead instead of sticking your object to the object it collided with, you create a dummy game object, lets call it "glue", at the collision point, and stick your object to the glue. The glue object is then parented to the object we collided with.
Since glue is just a dummy object with only components transform and some script, there is no problem with parenting.
Also, pay attention that it does not really matter at which contact point we create the glue, in case we have multiple contact points, and it is also easy to extend this to support rotations, see below.
So on collision, the only thing we do now is creating a glue. Here is the code:
And here is how Glue.cs script looks, it will handle LateUpdate and modify transform.
Also, pay attention that simply parenting the objects as it was suggested here will get you in some additional trouble, because scaling parent also scales children, so you will have to re-scale the child back to its original size. The problem is that these scaling operations are relative to different anchor points, so you will also have to make additional adjustments in objects position. Can be done though.
I also created a small sample project, see here (Unity v5.2.f3): https://www.dropbox.com/s/whr85cmdp1tv7tv/GlueObjects.zip?dl=0
P.S. I see that you mix transform and rigidbody semantics, since it is done on Kinematic rigidbodies it is not a big deal, but just a suggestion: think whether you really need to have rigidbodies on objects that are already "stuck" to others, if not - maybe just remove or disable the rigidbody instead of making it Kinematic.