- Home /
How to Instatiate with space by order ?
Hello guys, i want instatiate object random on screen but with order.
I'm genearting object random on X and Y axis but i need to make it with my object size. I mean object must be pass way everytime. I hope you will understand that sorry for my english.
Here is my code;
public Gameobject block1
for (int i = 0; i < 30; i++)
{
Vector3 rndVector = new Vector3(Random.Range(-2.55f, 2.55f), Random.Range(-1.6f, 4.1f), 0);
GameObject block = Instantiate(block1, rndVector, Quaternion.identity);
float XYZ = Random.Range(0.27f,0.7f);
block.transform.localScale = new Vector3(XYZ, XYZ, XYZ);
}
In Game Looking Like This:
I'm having trouble understanding what you want, can you try explaining again please
are you asking how to prevent the objects from overlapping?
Answer by Bunny83 · Feb 08, 2020 at 11:42 AM
Ok I think I finally understood what this question is about. You just want to create 30 circular objects on the screen, randomly distributed, but without any overlap. It seems your other question was about the same issue but your approach was a bit strange. You probably should delete your other question as it's far more confusing what the outcome should be, so it's unlikely anybody will be able to answer it.
To distribute objects on the screen there are several approaches that would work. The most easiest way is to just put every object on its own vertical line and make sure that line is as far away from the previous line as the sum of the previous radius and your current radius. That way no matter where you place your object on that line it can never intersect with the previous one. However this will produce some constraints how the objects are distributed. With this approach it's impossible to have two objects next to each other on about the same line, even though there's enough space to put it there. So this approach will generally produce certain patterns and highly limit the amout of objects we can put on the screen since we essentially stack the objects on top of each other one-dimensionally.
Properly distribute objects randomly is a bit more tricky. In general you have to track / remember / save the position and dimension of all your previous created objects in order to check if there might be an overlap. There are several approaches to do this. I will quickly show some of them:
Just rely on Unity's physics system and use colliders and OverlapSphere (when 2d physics is used OverlapCircle). Just pick a random point and radius and see if you get an overlap, if you do generate a new position / radius and try again.
Just store all your object data in a list so you can easily access the generated position and radius. Now when generating a new object you can manually iterate through the list and see if the new position / radius wouldl overlap with any of the existing ones. If not we can create an object there and add it to the list. There's a CodingTrain video about this approach
The last approach uses a completely different approach. We just generate 30 random objects like you already did. But then we essentially run refinement steps over all objects. We essentially build a simple seperation logic. If we detect two object are overlapping we seperate them by moving them apart by half the overlap amount. This will ensure those two object do not overlap anymore. However by pushing them apart we might move one or both object over other objects or out of the viewing area. This doesn't matter since we do this process several times until there's no overlap anymore.
All these algorithms are not cheap from a performance point of view and all have the possibility of running forever. This happens when you just picked too many objects and you can not possibly fit that many circles into the screen area without overlap. So in all 3 approaches we have to ensure to stop at some point. Otherwise your application would just freeze and has to be force closed.
Physics based approach
So now tackle them one by one. For the first approach it's important to remember that creating objects with a collider in a loop has the issue that those new objects are unknown to the physics system until the next physics step runs. Since everything happens inside a loop the physics system can not detect any of the objects we have already created. Though we can now use Physics2D.SyncTransforms / Physics.SyncTransforms after we created an object to ensure the physics system is up to date. To actually create the object we could use a nested loop or just a variable to track how many tries we had and how many objects we have created already. This can be done with a single for loop:
float minSpacing = 0f;
Physics2d.SyncTransforms();
for (int i=0,c=0; i < 1000 && c < 30; i++)
{
Vector3 rndVector = new Vector3(Random.Range(-2.55f, 2.55f), Random.Range(-1.6f, 4.1f), 0);
float radius = Random.Range(0.27f,0.7f);
if (Physics2D.OverlapCircle(rndVector, radius + minSpacing) == null)
{
GameObject block = Instantiate(block1, rndVector, Quaternion.identity);
block.transform.localScale = new Vector3(radius, radius, 1f);
c++;
Physics2d.SyncTransforms();
}
}
So this loop will end when we either have created 30 objects, or when we run that loop 1000 times. So in case there is no room left to fit another circle in we just stop even though we did not create 30 objects. Note that "minSpacing" adds some extra amount to the radius to ensure two circles are not "touching" each other. Just increase this value if you want to have a minimum space between circles.
Even this approach uses Unity's 2d physics system it's probably one of the cheapest solutions because the physics system is highly optimised. However if performance is a concern, do a benchmark and test it.
Simple manual overlap test
Here we just create a List of custom objects which hold the information we need to define a circle object. At each step, like in the last approach, we generate a new position and radius and see if it overlaps with other circles and if it does, create a new one until we don't have an overlap..
static float minSpacing = 0f;
public class Circle
{
public Vector2 pos;
public float radius;
public bool Overlap(Circle aOther)
{
float rad = radius + aOther.radius + minSpacing;
return (aOther.pos - pos).sqrMagnitude < rad*rad;
}
}
List<Circle> circles = new List<Circle>();
void Start()
{
for (int i=0,c=0; i < 1000 && c < 30; i++)
{
Vector3 rndVector = new Vector3(Random.Range(-2.55f, 2.55f), Random.Range(-1.6f, 4.1f), 0);
float radius = Random.Range(0.27f,0.7f);
var newCircle = new Circle{ pos = rndVector, radius = radius };
bool validCircle = true;
foreach(var c in circles)
{
if (c.Overlap(newCircle))
{
validCircle = false;
break;
}
}
if (validCircle)
{
GameObject block = Instantiate(block1, rndVector, Quaternion.identity);
block.transform.localScale = new Vector3(radius, radius, 1f);
circles.Add(newCircle);
c++;
}
}
}
So this is the same approach as the first one but without any physics system involvement.
Refinement approach
In this case we create 30 random Circle objects right away. We run several refinement steps which wil gradually seperate the objects. Note that the end result will differ from the other two cases. In the first to approaches if we can't fit enough circles into the area we simply give up adding more circles after some point. So we end up with less circles than we wanted. This approach will always create as many circles as we want. However if there are too many circles they might still overlap after we run out max refinement steps. There's no nice way to solve this issue with this approach.
static float minSpacing = 0f;
public class Circle
{
public Vector2 pos;
public float radius;
public bool Refine(Circle aOther)
{
float rad = radius + aOther.radius + minSpacing;
var dir = aOther.pos - pos;
float overlap = rad*rad - dir.sqrMagnitude;
if ( overlap > 0 )
{
overlap = Mathf.Sqrt(overlap);
dir = dir.normalized * overlap * 0.5f;
pos -= dir;
aOther.pos += dir;
}
}
}
List<Circle> circles = new List<Circle>();
void Start()
{
for (int c = 0; c < 30; c++)
{
Vector3 rndVector = new Vector3(Random.Range(-2.55f, 2.55f), Random.Range(-1.6f, 4.1f), 0);
float radius = Random.Range(0.27f,0.7f);
var newCircle = new Circle{ pos = rndVector, radius = radius };
circles.Add(newCircle);
}
for(int i = 0; i < 100; i++)
{
bool refined = false;
for (int a = 0; a < circles.Count; a++)
{
for (int b = a; b < circles.Count; b++)
{
if(circles[a].Refine(circles[b]))
refined = true;
}
}
if (!refined)
break;
// ensure points are not pushed outside our initial range
foreach(var c in circles)
{
c.pos.x = Mathf.Clamp(c.pos.x, -2.55f, 2.55f);
c.pos.y = Mathf.Clamp(c.pos.y, -1.6f, 4.1f);
}
}
foreach(var c in circles)
{
GameObject block = Instantiate(block1, c.pos, Quaternion.identity);
block.transform.localScale = new Vector3(c.radius, c.radius, 1f);
}
}
Note that all of this code is untested. I have just written it here from scratch. If you find any error, let me know in a comment.
First thanks for helping about that.
I watched CodeTrain's video and i searched about Possion Dics Sampling i read so many texts etc.
I tested "Physics based approach" code it didn't work i mean here i used code and result ;
https://i.hizliresim.com/NG6JkP.png
https://i.hizliresim.com/agJRXO.png
"Simple manual overlap test" have problem on foreach(var c in circle)
And "Refinement approach" have problem on here public bool Refine(Circle aOther)
I'm trying to make this game but i have so many trouble with that pf.
Game Link ;
For the physics approach, make sure your block1 prefab actually has a 2d collider on it that matches its visual.
The foreach var c in circle is just a typo, it should be 'circles'.
For the refinement problem, the function just isnt' returning a bool yet, it should return false inside the if block and return true at end.
All 3 of those approaches are very reasonable and should work, it sounds like there are just a couple $$anonymous$$or bugs remaining so you are almost there!
Yep, that was a typo ^^ I just fixed it, thanks. And yes, even though I mentioned "objects with colliders" in the introduction, I never explititly said that the prefab must have one. Though one certain thing should be kind of obvious ^^. I also did not mention that the script need to be attached to a gameobject in the scene. However that's probably more obvious than the need for a 2d collider when using 2d physics :)
Note that I just replaced Physics2D.Simulate(0f)
with Physics2D.SyncTransforms()
which is more correct and probably less demanding.
Answer by RigbySug · Feb 07, 2020 at 09:30 PM
Anyone can help on this please. Nobody not know it?
Please answer the questions in the comments of your post so we can help you
I'm genarting object with instatie as you can see. But here is problem object up on object because Random.Range calling close number like(1.1F, 1.3F, 1.8F) and it's about size. How can i genarate object like picture 1. Thanks.
Answer by alexdevAo · Feb 07, 2020 at 04:24 PM
You most call block.transform.localScale = new Vector3(XYZ, XYZ, XYZ);
before Instantiate it It must be that way:
public Gameobject block1
for (int i = 0; i < 30; i++)
{
Vector3 rndVector = new Vector3(Random.Range(-2.55f, 2.55f), Random.Range(-1.6f, 4.1f), 0);
float XYZ = Random.Range(0.27f,0.7f);
block.transform.localScale = new Vector3(XYZ, XYZ, XYZ);
GameObject block = Instantiate(block1, rndVector, Quaternion.identity);
}
No... block doesn't even exist yet if you move it before the instantiate I don't think this code will even compile
Try this way, create a new variable put blovkList name.Inspector put size 30. It also increases the distance from the Random Scale so that you can see the difference in size.
public GameObject block1;
public GameObject[] block1List;
void Update()
{
for (int i = 0; i < 30; i++)
{
Vector3 rndVector = new Vector3(Random.Range(-5.55f, 5.55f), Random.Range(-4.6f, 7.1f), 0);
block1List[i] = block1;
GameObject tempBlock = block1List[i];
float XYZ = Random.Range(0.01f, 1.0f);
tempBlock.transform.localScale = new Vector3(XYZ, XYZ, XYZ);
GameObject block = Instantiate(tempBlock, rndVector, Quaternion.identity);
}
}
Don't forget to assign the block1 gameobject in the inspector tab
Answer by Arnoldlove · Dec 24, 2020 at 11:35 AM
Instantiate can be used to create new objects at runtime. Examples include objects used for projectiles, or particle systems for explosion effects. Instantiate can also clone script instances directly. Prepaidcardstatus
Your answer
Follow this Question
Related Questions
Instantiate issues 1 Answer
Why this error when trying to instantiate object ?(Solved) 2 Answers
GUIText transition trouble 1 Answer
Projectile not firing 2 Answers
There is a generation lag 1 Answer