- Home /
Problem is not reproducible or outdated
How to change the position of an object without overlapping?
I have a question.
I have 2d simple tutorial game.
The game has several objects.
I would like the objects to change their position each time PLAY is pressed.
The objects must be in the BOX:
x = Random.Range (-4, 4); y = Random.Range (-4, 4);
The idea is that each time you start the game, they are in a different place- but without each other collision.
The problem is that sometimes their position overlaps.
I added to each object Rigidbody 2d , where I marked freeze rotation with.
Every object has a box collider added.
My code now:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RandomRange : MonoBehaviour {
float x;
float y;
Vector2 pos;
void Start()
{
x = Random.Range(-4, 4);
y = Random.Range(-4, 4);
pos = new Vector2(x, y);
gameObject.transform.position = pos;
}
public bool IsHitting(Collider other) {
Collider col = GetComponent<Collider>(); // this object's collider
Collider[] hits = Physics.OverlapBox(col.bounds.center, col.bounds.extents,
transform.rotation);
foreach(Collider hit in hits) {
if(hit == other) {
return true;
}
}
return false;
}
}
This script caused that each time objects overlap, they move so that they do not touch each other.
However, there were two problems:
1) When objects overlap each other near the edge of the BOX, they fall on it when changed position.
2) The transfer of objects is very visible.
Objects should only be loaded at a distance not less than the minimum distance.
In this case, you can see when the object overlaps the other and how it is changed position.
Could anyone help fix it, or create a simpler script?
You can see my problem on video:
https://gfycat.com/pl/gifs/detail/InferiorRashBlackmamba
Answer by IamAnewUser · May 25, 2018 at 10:02 AM
Randomize them as Maxence_Marchand said and check for the distance with the other GameObjects with Vector2.Distance() . If they're too close too each other then randomize the position again. This has to be a loop, for example something like that might do
float minDistance = 5f;
bool goodPosition = false;
GameObject[] allGO = FindObjectsOfType<theObjects>();
while(!goodPosition){
goodPosition = true;
theRandomItem.trasform.position = new Vector2(Random.Range(0, 50), Random.Range(0,50));
for(int i = 0; i < allGO.Length; i++){
if(Vector2.Distance(theRandomItem.trasform.position, allGO[i].transform.position) <
minDistance){
goodPosition = false;
}
}
}
just change minDistance to the distance you want and theObjects to a script that is assigned only to those objects or search them by a tag etc
The comments are all gone '-' What just happened?
I'm so confused right now ... @polan31 did you saw my last comment before it disappeared (got deleted)?
Oh, I'm sorry, I tried to edit, because in one place you wrote "trasform" and not "transform" what caused the error in the code, unfortunately I deleted the post by accident :(
However, I have copy your answer, so if it is not a problem, I will paste it now :)
@IamAnewUser answer :
set theRandomItem to gameObject -theRandomItem is the object that we want to generate random position for and check if it's close to another-
set allGO to FindObjectsOfType() -allGO is an array of all the objects we want to generate random positions for and check if they're close to eachother and we find them by searching for a specific component/script that is only added to those type of objects. Which in your case, according to your previous code, is the collisionObject script-
you might want to customize the Random.Range's and the $$anonymous$$Distance too to match them to your preference. Here are the links to the docs, Random.Range https://docs.unity3d.com/ScriptReference/Random.Range.html Vector2.Distance https://docs.unity3d.com/ScriptReference/Vector2.Distance.html
$$anonymous$$y code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collisionObject : $$anonymous$$onoBehaviour {
public int myIndexNumber;
public bool isHighestNumber;
float $$anonymous$$Distance = 5f;
bool goodPosition = false;
collisionObject[] allGO = FindObjectsOfType<collisionObject>();
public void Start()
{
isHighestNumber = true;
//find all other objects:
foreach (collisionObject cObj in GameObject.FindObjectsOfType<collisionObject>()) {
//check if any of the other objects has a larger number than $$anonymous$$e, if yes, note to self that i am not the highest number.
if (cObj.myIndexNumber > myIndexNumber) {
isHighestNumber = false;
break;
}
}
Debug.Log ("Object number " + myIndexNumber + " is here // is highest Number: " + isHighestNumber);
}
void Awake ()
{
while(!goodPosition){
goodPosition = true;
gameObject.transform.position = new Vector2(Random.Range(0, 50), Random.Range(0,50));
for(int i = 0; i < allGO.Length; i++){
if(Vector2.Distance(gameObject.transform.position, allGO[i].transform.position) <
$$anonymous$$Distance){
goodPosition = false;
}
}
}
}
}
Generally, the code causes a small error that I am trying to solve now:
UnityException: FindObjectsOfType is not allowed to be called from a $$anonymous$$onoBehaviour constructor (or instance field initializer), call it in Awake or Start ins$$anonymous$$d. Called from $$anonymous$$onoBehaviour 'collisionObject' on game object 'xx'.
PS: "xx" is the name of the object.
Answer by Maxence_Marchand · May 25, 2018 at 08:51 AM
Why not giving them random positions in the Start()
method? If I'm not misunderstanding your question, you want to change their position only when you start the game, right?
Exactly, but recently, as I tried it, objects collided with each other, for example one loaded on the other.
I see... the collisions might be problematic... I'm a beginner with Unity, and I'm not using it for games XD But I think there should be a way, I hope my answer gave you a small hint.