I am trying to make some code that randomises my unity game's levels. This method is supposed to make a square filled with enemies. The IsPowered boolean randomly decides if a cloumn should be moving verticaly or not:
void Square(GameObject ship, float dY, float dX, float h, float w)
{
int i, j;
bool IsPowered = false;
float X = 2 Camera.transform.position.x, speed = Random.Range(50.0f, 100.0f);
//set position
float Y = h / 2 * dY dY / 2;
for (j = 1; j <= w; j )
{
IsPowered = false;
if(Random.Range(0, 1) == 1)
IsPowered = true;
for (i = 1; i <= h; i )
{
//makes ship
temp = Instantiate(ship);
if(IsPowered)
{
if(Random.Range(0, 1) == 1)
speed = -speed;
temp.GetComponent<Rigidbody2D>().AddForce(new Vector2(0, speed));
}
temp.transform.position = new Vector3(X j * dX, Y - i * dY, 0);
}
}
}
The problem is that if the first Random.Range(0, 1) statement is true unity freezes. Btw I checked and if I remove the statment or make is always be true this doesn't happen. Square being called:
void LateUpdate()
{
//if the player has moved 2 tiles then strat a fight
curentX = Camera.transform.position.x;
if(Mathf.Abs(lastX - curentX) >= 10 && Mathf.Abs(curentX - 60) >= 8)
{
lastX = curentX;
InBattle = true;
//!Arguments: 0 - square, 1 - triangle, 2 - circle, 3 - bounce;
CallRandom(0);
}
//if player has defeated all enemies exits battle mode
EnemiesOnBoard = GameObject.FindWithTag("Enemy");
if(EnemiesOnBoard == null && InBattle)
{
InBattle = false;
}
}
CallRandom method:
void CallRandom(float nb)
{
float dY, h, dX, w;
int nb2;
switch (nb)
{
//sets up random stuff for square type of formation
case 0:
//randomises vertical stuff
dY = Random.Range(1.0f, 2.0f);
h = Random.Range(2, 4);
while(h / 2 * dY dY / 2 >= 4)
dY -= 0.1f;
//randomizez horizontal stuff
dX = Random.Range(1.0f, 2.0f);
w = Random.Range(2, 4);
while(w * dX > 5);
dX -= 0.1f;
Square(EType0, dY, dX, h, w);
break;
//makes random triagnle type formation
case 1:
//vertical
dY = Random.Range(1.0f, 2.0f);
h = Random.Range(2.0f, 5.0f);
while(h / 2 * dY dY / 2 >= 4)
dY -= 0.1f;
//horizontal
dX = Random.Range(1.0f, 3.0f);
while(dX * h >= 5)
dX -= 0.1f;
Triangle(EType0, dY, dX, h);
break;
//makes random circle type fromation
case 2:
nb2 = Random.Range(4, 9);
Circle(EType0, nb2);
break;
//makes random bouncie formation
case 3:
nb2 = Random.Range(5, 12);
Bounce(EType0, nb2);
break;
default:
print("Something aint right");
break;
}
}
EDIT: I did some more testing and the problem seems to originate from one or both of the while loop in case 0 of the CallRandom method and it doesn't seem to happen enywhere else. Still don't know why is doesn't work
EDIT: I finally found the problem, and I actually hate myself now. The second while loop in case 0 of CallRandom had a ";" at the end of it so it created an infinite loop!
CodePudding user response:
The problem with your code is that there appears to be a direct link with frame updating (specifically LateUpdate()
) and spawning new pre-fabs attached to new GameObject
s. Our focus here isn't so much the prefabs but rather the GameObject
s. GameObject
s are a kinda expensive and there appears to be an upper limit you can have at one time per scene.[1][2]
Now LateUpdate
is called every frame and let's say your game is running at 60 frames/second (FPS). So worst case is that you might be spawning 60 GameObject
s/second. Unless you have coded some sort of lifetime management, you might be reaching Unity's limit causing it to crash.
Thar be dragons
It's actually a little worse. LateUpdate()
(remember 60 FPS in our example) calls CallRandom()
which calls Square()
which living up to it's name isn't limited to spawning a single GameObject
but a square of them with your nested loops of w * h
. Backtracking to CallRandom()
we see that w
and h
could be anything up to 4
in value.
So:
<frame-rate> x 4 x 4 = <spawn-rate>
...or:
60 x 4 x 4 = 960 game objects/sec
With some reports of the upper limit of GameObjects to be ~5,000, you would exceed that in approximately 5.2 seconds! [1][2]
The fix
You have a few choices:
if you plan on spawning say 960 objects/sec you will need to delete older objects as you go. Think of the famous Snake game
consider restructuring your visuals so that you need less
GameObject
s. e.g. Unity's Particle System works by having a singleGameObject
and component yet it can render 1,000s of particles effortlessly
1 https://answers.unity.com/questions/408298/max-number-of-gameobjects-5000-1.html
2 https://answers.unity.com/questions/365552/why-would-you-use-a-scriptable-object-versus-an-em.html