- Home /
Unity Keeps Freezing on Play
So I am creating a Bullet Hell game, and I have created a shooting system where you have an amount of bullets you can fire that recharges slowly so you cant spam the gun. I added that feature and when i went back to Unity the editor just froze on play. I restarted it a few times, but nothing works. I did a little digging and people say its becuase of an infinite loop or something, but I dont have the skill to figure out what in my code is the problem. Any Ideas?
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;
public class PlayerController : MonoBehaviour {
//shooting and player controlls
public float speed = 15;
public GameObject bulletPrefab;
public Transform bulletSpawn;
public float bulletspeed = 15;
public int bulletshot = 10;
public int bulletstotal = 10;
public int shotpower = 1;
public bool useInvoke;
public bool running;
//sounds/maybe animations?
public AudioClip shootnoise;
public AudioSource source;
//score related things
public float stomata = 0;
public Text score;
// Use this for initialization
void Start () {
source.clip = shootnoise;
if (useInvoke)
InvokeRepeating("ShotTimer", 0, 3);
else
StartCoroutine(ShotTimer());
}
// Update is called once per frame
void Update () {
stomata += 1;
score.text = stomata.ToString();
Vector3 moveDir = Vector3.zero;
moveDir.x = Input.GetAxis("Horizontal");
transform.position += moveDir * speed * Time.deltaTime;
if (Input.GetButtonDown("Fire1"))
{
if (bulletshot > 0)
{
bulletshot = bulletshot - 1;
shoot();
source.Play();
}
}
}
void shoot()
{
var bullet = (GameObject)Instantiate(
bulletPrefab,
bulletSpawn.position,
bulletSpawn.rotation);
bullet.GetComponent<Rigidbody>().velocity = bullet.transform.up * bulletspeed;
Destroy(bullet, 1.0f);
}
IEnumerator ShotTimer()
{
running = true;
while (running)
{
if (bulletshot < bulletstotal)
{
bulletshot = bulletshot + 1;
yield return new WaitForSeconds(0f + shotpower);
}
}
}
void TestInvoke()
{
bulletshot = bulletshot + 1;
}
}
While loops are quite usefull on many occasions along side infinite for loops. Anyway the issue here is that once bulletshot is greater than bulletstotal the code inside the if statement won't get executed thus the yield won't executed meaning it will not return control to the caller meaning you ve stuck in an infinite loop , as mentioned. To fix it, do something like this
while (running)
{
if (bulletshot < bulletstotal)
{
bulletshot = bulletshot + 1;
yield return new WaitForSeconds(0f + shotpower);
continue;
}
yield return null;
}
or remove the continue and encapsulate the second yield in an else. Also you don't won't to use InvokeRepeating in this occasion, which will call a function on specified time intervals but thats something you don't need here.
Cheers.
Side note on how to avoid infinite loops if the loop is inside a coroutine make sure you have a yield return inside the loop and will get to be executed eventually or in general I tend to use this pattern (and remove it as soon i am sure i got the conditions right)
void SomeFunction(){
int safeCount =0;
while(){
//do stuff;
safeCount++;
if (safeCount > 10000) // where the number is an estimation, or limit, on how many times this loop will need to run
break;
}
Answer by Ginxx009 · Dec 04, 2017 at 07:01 AM
I always avoid on using while loop in the game cause it's prone to infinite loop well it depends always on the programmer. But just do it like this i guess
running = true;
if(running == true){
if(bulletshot < bulletstotal){
....
}
}
something like that.
Hey thanks! That stopped the freezing, but it also made the system not work... It no longer adds a bullet every second. Any Idea why it wouldn't be working?
make sure you have useInvoke = true;
Answer by Dennisdb1997 · Dec 04, 2017 at 06:50 AM
Infinite while loop ;)! Its always true which means it would never break out of the loop.
Answer by suIly · Oct 20, 2019 at 04:41 PM
it's because you have an infinite loop the ShotTimer IEnumerator
Answer by JulianRice · Aug 14, 2020 at 10:31 AM
For those that run into this error and still want to use a while loop in an IEnumerator, keep in mind that if you don't have a default yield return new WaitForEndOfFrame() or something like that, then the while loop will go on forever and you'll crash on Play.
TLDR: Add the following to the end (or beginning) of any while loop inside of an IEnumerator:
yield return new WaitForEndOfFrame();
So that your code looks like this:
IEnumerator ShotTimer()
{
running = true;
while (running)
{
if (bulletshot < bulletstotal) {
bulletshot = bulletshot + 1;
yield return new WaitForSeconds(0f + shotpower);
}
yield return new WaitForEndOfFrame();
}
}