- Home /
infinite while loop checking if a gameObject is in the air
I'm trying to code a push/pull mechanic, and when the player pushes the box off the ledge I want to keep it not kinematic while it doesn't reach the floor. For that, I'm using a while loop inside Update() that checks, with raycasts, if the box is still in the air, but it crashes the unity.
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftShift) && PushableObject() && GroundCheck())
{
box.GetComponent<Rigidbody>().isKinematic = false;
box.gameObject.transform.parent = player.transform;
isPushing = true;
}
if ((Input.GetKeyUp(KeyCode.LeftShift) && isPushing) || (isPushing && PushableObject() == false))
{
if (BoxGroundCheck(box) == false)
{
bool onGround = false;
while(onGround == false)
{
box.GetComponent<Rigidbody>().isKinematic = false;
onGround = BoxGroundCheck(box);
}
}
box.GetComponent<Rigidbody>().isKinematic = true;
box.gameObject.transform.parent = null;
isPushing = false;
}
}
bool BoxGroundCheck(GameObject bx)
{
RaycastHit hit;
float distance = 0.5f;
Vector3 dir = new Vector3(0, -1);
bool isGrounded;
if (Physics.Raycast(bx.transform.position, dir, out hit, distance) || Physics.Raycast(bx.transform.position + new Vector3(-0.2f, 0, 0), dir, out hit, distance) || Physics.Raycast(bx.transform.position + new Vector3(+0.2f, 0, 0), dir, out hit, distance))
{
isGrounded = true;
}
else
{
isGrounded = false;
}
return isGrounded;
}
bool PushableObject()
{
RaycastHit hit;
float distance = 1f;
bool isPushable;
if (Physics.Raycast(player.transform.position, new Vector3(x, y, z), out hit, distance))
{
if (hit.collider.gameObject.tag == "Box")
{
isPushable = true;
box = hit.collider.gameObject;
}
else
{
isPushable = false;
}
}
else
{
isPushable = false;
}
return isPushable;
}
The answer below is correct. I would just like to emphasize an important detail, which is as long as the while loop is running, Unity does not execute any Update() or FixedUpdate() functions. Because you are using physics to check if the box is on the ground, you need to keep running FixedUpdate() while you are checking if the box is on the ground, so you cannot use this while loop structure.
Answer by cwalshwarder · Jul 31, 2020 at 10:53 PM
When you do a loop, unity needs to finish it before it can do anything else. Maybe you can just do that each Update() or each FixedUpdate(), without putting it in a while loop. Maybe you need to start a coroutine where the while loop is.
While you're fixing this, to avoid crashes, you could add a variable to which you add 1 in the while loop, and stop the loop & Debug.Log("infinite loop") if it's over like 1000.
I agree 100%. The update loop is already a while loop that doesn’t stall the thread unless you put an infinite loop inside it. If you need to wait for something to complete before continuing, you either have a condition in the update method. Or use a coroutine, which is also on the same thread as everything else running in Unity, but allows you to yield and wait for something to finish by means of one of the WaitFor methods or by use of a while loop with a yield statement inside.
Whoa, thank you for those tips. I didn't know about coroutines yet. I did this and it worked well:
void Update()
{
...
if (!BoxGroundCheck(box))
{
box.gameObject.transform.parent = null;
StartCoroutine("KeepNotKinematic");
}
...
}
IEnumerator KeepNotKinematic()
{
while(!BoxGroundCheck(box))
{
box.GetComponent<Rigidbody>().isKinematic = false;
BoxGroundCheck(box);
yield return null;
}
}
Your answer
