Snap GameObjects at runtime

Hi,

we want to let the player place walls. When the first Wall is sat, he shall have the option to build the next door. This 2nd door shall snap at the first wall´s corners like real Walls. Is this possible?
When it snaps, the 2nd wall should only rotate. But the one corner that snaped shall stay at the first wall.

Thank,
MysteriX

If each object has a set of “snap points” at which other objects can be snapped, then you can do a simple distance check; when the being-placed object is within 1 unit of one of the already-placed object’s hot points, it sets its position to that. Will that work for your purposes?

Hi,
thanks for the answer, but its not clear for me sorry.

how can I set the snap points? would be nice if it would be the corners of the wall. I don´t get it how to calculate them. Could you help me with a bit code or some idea to do it?

thanks!

EDIT:

And how can I set the corner of the new wall to snap the first wall? I do not want the middle of the wall to snap to the first wall´s corner. Complicated for me. More complicated to explain. I hope you can understand what I try to do

Could please anyone help me? :confused: I did not get it how to snap

A rather simple way to do this would be to add some little triggers (collider with trigger checked) as children to your wall prefab on a ‘SnapPoint’ physics layer that only collides with itself and a script on each that hooks the colliding object’s parent at the right position.

Note: don’t forget the rigidbody, and assuming you enable the script only on the moving wall:

//This is the moving wall
void OnTriggerEnter(Collider other)
{
    this.transform.parent.position = other.transform.position + (this.transform.parent.position - this.transform.position);
}

Hi,
thanks for the answer. Looks very interesting. I will test it when I´am home today. But one more question: how can i make a object just collide with itself like you said?

EDIT:

SOLVED.
I read your post again and overread the last sentence which says i have to assign the rigidbody. thanks! now it works great!

Hi, I now tested it. I could not be more confused than I am :S

Let me explain what I did. I created a Prefab of my wall. Now i added two little cubes to this prefab which have a box collider. One Cube is left and the other cube is right from the wall. I created a script which just contains your given code. But now when two walls collide, the first wall (which was already set) moves to the other. It is not what I wanted to do. Can you imagine what I made wrong? Or could you be a bit more specific for me? Thanks much!

What does the code look like at the moment? A bit hard to debug when “blind.” :slight_smile:

Hi,

I used to change the code as the following:

public bool _isMovable = true;
void OnTriggerEnter(Collider other)

{
if(!_isMovable || other.transform.tag != "snappoint")
return;
    _isMovable = false;
    this.transform.parent.position = other.transform.position + (this.transform.parent.position - this.transform.position);

}

This script I assignet to the snappoints which i created at the prefab.
You see you have to set the tag of the snap points to “snappoint”.
Iam not at home so the code is from my memory^^ I hope all is right.

It works great, but I have to implement one more things in the next days:
When the mouse pointer goes to far away from the snap point, the movable gameobject should also move away from the snappoint.
The given code makes it impossible to realize this.

If anyone have an idea, it would be great :slight_smile:

Hi, still looking for an answer ?

Nothing is impossible bro, except mabe making me write python code.

I kept my code example to the minimum so you would understand the core of it. Now if you need to add features, you have to take into account how you handle your mouse input. If you use plain Input.mousePosition you could store its value when the snaping happens, and have the update loop check the mouse distance for un-snaping and then do the snaping.

Something like:

//Enable this script at the begining of drag
//And then disable this script when drag is over

public float _unsnapMouseDistance = 25;

Vector2     _snapMousePos;
Transform   _snapTarget;

void Update()
{
    if (this._snapTarget)
    {
         this.transform.parent.position = this._snapTarget.position + (this.transform.parent.position - this.transform.position);
         if (Vector2.Distance(this._snapMousePos, Input.mousePosition) >= this._unsnapMouseDistance)
         {
              this._snapTarget = null;
              //Here you could also move the object to an appropriate distance regarding the current mouse position so the user feels he got back control of it
              //Also if you have troubles with the trigger being re-triggerer too fast, you could have a add a small timer to prevent it for about half a second...
         }
    }
}

void OnTriggerEnter(Collider other)
{
    if(this.enabled  other.transform.tag == "snappoint")
    {
        this._snapTarget =  other.transform;
        this._snapMousePos = Input.mousePosition;
    }
}

can you please explain the process to do it.

hm… one solution is to build yourself two new coordinate systems in both objects (one coordinate system in the origin object and one in the target object). Then, apply a transformation that transforms from the origin coordinate system to the destiny coordinate system.

First you build the two coordinate systems of the objects someway. You will align the coordinate system of the origin object to the coordinate system of the destiny object. When you align these coordinate systems, you will have your objects aligned too.

For both objects, the coordinate systems are composed by three orthogonal normalized vectors (x, y and z vectors) and a point in world coordinates. Like a regular coordinate system, just customized by yourself with some position/rotation for each of your objects (I recomend you to build them with cross product and normalization to ensure they are ortho-normal axis - and it will be nice if you draw them to ensure you are having the right results).

Then, you will build two Matrix4x4, that are matrices that transforms an object from the world coordinate system to the coordinate system you built for each object.

For each coordinate system you built, the Matrix4x4 that transforms from world coordinate system to your custom coordinate system will be the matrix:

M =
[ V1.x V2.x V3.x P.x ]
[ V1.y V2.y V3.y P.y ]
[ V1.z V2.z V3.z P.z ]
[ 0 0 0 1 ]

where V1, V2 and V3 are the three orthogonal normalized vectors that define your custom coordinate system and P is the origin of this custom coordinate system.

So, let’s say that you built the two matrices, M1 that transforms from the coordinate system of the world to the coordinate system of the origin object, and M2 that transforms from the coordinate system of the world to the coordinate system of the destiny object.
Then, the transformation T that transforms from the coordinate system of the origin object to the coordinate system of the target object will be a Matrix4x4 defined as:

T = M2 * M1^(-1)

That is the inverse of M1 (to transform it to the origin of the world) multiplied with M2 to transform it to the destiny coordinate system.

Not sure if that’s what you really need, but it may be helpful.