Unity 2D While Loop Problems in simple shoot script (C#)

Hello all,

I am working on top down 2D game. As part of the game’s mechanics you will no be able to move while “Drawing” your bow, and we have reduced movement speed for a short time after firing the bow.

I have made two separate scripts. One for most of the logic and the shooting (not actually implemented yet because the logic doesn’t work), and one for the player movement which uses two public static bool variables to apply speed multipliers to the movement.

Currently the logic and shooting script has something wrong with the logic that I can’t identify. There are a couple print lines in the script and neither of them are ever called.

First Script (ArrowFire.cs):

using UnityEngine;
using System.Collections;

public class ArrowFire : MonoBehaviour {

	private float BowTimer;
	private float RecoverTimer;

	private bool Ready;

	public float BowDraw = 0.7f;
	public float Recover = 0.5f;

	public static bool Recovering = false;
	public static bool Drawing = false;

	// Use this for initialization
	void Start () 
	{
		Ready = true;	
	}

	void OnLevelWasLoaded ()
	{
		Ready = true;
		Bow();
	}


	void Bow () {
		while (true)
		{
			while (Input.GetKeyDown (KeyCode.Space) && Ready)
			{
				Drawing = true;
				BowTimer += Time.deltaTime;

				if (BowTimer >= BowDraw)
				{

					//insert projectile fire code here
					print ("bam");

					Ready = false;
				}
			}

			while (!Ready)
			{
				BowTimer = 0.0f;
				Drawing = false;
				Recovering = true;

				RecoverTimer += Time.deltaTime;

				if (RecoverTimer > Recover)
				{
					print ("recovering");
					Ready = true;
					Recovering = false;
				}
	
			}
			RecoverTimer = 0.0f;
		}
	
	}
}

Second Script (PlayerMove.cs)

using UnityEngine;
using System.Collections;


public class PlayerMove : MonoBehaviour {
	//define public variable for speed control
	public float setmulti; //set speed multiplyer in engine
	public float multidiag; //diaganal speed multiplier (should be less than 1.0f)

	private float multi; //internal speed multiplier
 
	private Vector2 vectmove; //make new Vector2 for velocity control

	private float recovermulti = .5f; //speed multiplier when recovering from bow shot

	public static bool Recovering; //shared variable recovering from bow shot
	public static bool Drawing; //share variable currently drawing bow


	// Update is called once per frame
	void Update () {
		//Upate Drawing and Recovering status from Arrow Fire script
		Recovering = ArrowFire.Recovering;
		Drawing = ArrowFire.Drawing;

		//Check key status
		float horz = Input.GetAxis("Horizontal"); //set horz to equal the value of the horizontal axis
		float vertz = Input.GetAxis("Vertical"); //set vertz to equal the value of the vertical axis



		//internal multi multipliers
		if (Drawing) //When drawing bow
		{
			multi = 0.0f; //set speed multiplier to 0 (no movement)

		}
		else if (Recovering) //When recovering from bow shot
		{
			multi = setmulti * recovermulti; //set internal speed multiplier to speed multiplier specified in engine times the recovering speed multiplier specified in engine
		}
		else
		{
			multi = setmulti; //set internal speed multiplier to speed mulitplier specified in engine
		}




		if (horz > 0 && vertz == 0) //if not diagnal movement
		{
			vectmove = new Vector2 (horz * multi, vertz * multi); //multiply vertical and horizontal speed by multiplyer and apply movement to player
		}
		else if (horz == 0 && vertz > 0) //if not diagnal movement
		{
			vectmove = new Vector2 (horz * multi, vertz * multi); //multiply vertical and horizontal speed by multiplyer and apply movement to player
		}
		else if (horz == 0 && vertz < 0) //if not diagnal movement
		{
			vectmove = new Vector2 (horz * multi, vertz * multi); //multiply vertical and horizontal speed by multiplyer and apply movement to player
		}
		else if (horz < 0 && vertz == 0) //if not diagnal movement
		{
			vectmove = new Vector2 (horz * multi, vertz * multi); //multiply vertical and horizontal speed by multiplyer and apply movement to player
		}
		else
		{
			vectmove = new Vector2 ((horz * multi)*multidiag, (vertz * multi))*multidiag; //multiply vertical and horizontal speed by multiplyer AND DIAGNAL MOVEMENT MULTIPLYER and apply movement to player

		}


		//Move player
		rigidbody2D.velocity = vectmove;




	}
}

Yes, as sysameca says, while does not work like that. while loops are just logic loops like For loops. They can just keep looping and not allow the rest of your code to work. You are probably thinking they will run in parallel with the rest of the code, this is not the case. For something like that you can use Coroutines. But in this case you don’t need those either.

Also it’s worth noting that OnLevelWasLoaded() only fires when a new scene is loaded from the current one. It won’t do anything if you are not switching scenes.

So to fix it change the OnLevelWasLoaded() to Update() and remove the ready = true; you can add an if check in front of the Bow() call if you would like to enable/disable it.
Then in Bow() remove the first while and change the other two to If statements, and move the RecoverTimer = 0.0f; to inside the if (RecoverTimer > Recover). Finally, the Input.GetKeyDown only fires Once when the key is pressed; use Input.GetKey to check the state of the key.

This should make the whole Bow() method be run through once per frame and should make it work.