- Home /
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;
}
}
The while loops you define does not work like you think they will do. Inside a non updating function the while loop is running just one frame. First, I'd say get rid of those while loops and place that bow logic inside the Update(). Second those static variables are just calling for trouble. Those globally shared variables need to be inside a custom manager defined as a singleton.
Answer by daneislazy · Feb 05, 2015 at 12:47 PM
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.
daneislazy,
Thanks for your quick reply. I tried to implement the changes that you suggested, but I was unable to get the script the run successfully.
Here is the new version of the ArrowFire.cs:
using UnityEngine;
using System.Collections;
public class ArrowFire : $$anonymous$$onoBehaviour {
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 Update ()
{
Bow();
}
void Bow () {
if (Input.Get$$anonymous$$ey ($$anonymous$$eyCode.Space) && Ready)
{
Drawing = true;
BowTimer += Time.deltaTime;
if (BowTimer >= BowDraw)
{
//insert projectile fire code here
print ("bam");
Ready = false;
BowTimer = 0.0f;
}
}
if (!Ready)
{
Drawing = false;
Recovering = true;
RecoverTimer += Time.deltaTime;
if (RecoverTimer > Recover)
{
print ("recovering");
Ready = true;
Recovering = false;
RecoverTimer = 0.0f;
}
}
}
}
And what exactly is the problem here? It seems like the script should work now.When you hold space it will wait for the recover time and will shoot your arrow. Then the script will wait the bow timer to run out and then will shoot another arrow. And that process will repeat until holding space. Isn't this what are you trying to achieve. Please do a little bit of explanation when you say that something doesn't work right.
That is exactly what I'm trying to achieve. The print "bam" is never called when I hold down space. Nothing shows up in the console at all.
Hm. I just pasted the code and it prints out "bam". $$anonymous$$aybe you forgot to place the script inside a game object?
Alright, I'll try to figure it out tomorrow. I don know the script is in the game object though. Thank you for all of your help.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Button Enabling/Disabling using Collision Triggers? 1 Answer
2D platformer- getting errors I don't understand (c#) 1 Answer