Looping a simple Function
Hello people of Unity. Got a question to someone with an Answer. It's simple. I have a script prepared to make a virtual pet poop ._., now what i want to do is this:
After i clean up the whole poop i want the function to repeat the process of counting down to the next poop. Here's what i got.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Poop : MonoBehaviour {
private Image poop;
public int time;
public bool poopToggle;
void Start ()
{
StartCoroutine (delaytime ());
poop = GetComponent<Image> ();
poopToggle = false;
}
void Update ()
{
if (poopToggle == false) {
poop.enabled = false;
} else {
if (poopToggle == true) {
poop.enabled = true;
}
}
}
IEnumerator delaytime()
{
while (poopToggle == false) {
yield return new WaitForSeconds (5);
poopToggle = true;
}
}
}
also. the moment i inserted this script in the game my unity stops cooperating after 4 seconds. Which is why i'm here, my loop is probably making the whole thing fall down.
Answer by Toon_Werawat · Apr 01, 2016 at 11:42 AM
Here.. I shorten down your script...
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Poop : MonoBehaviour {
private Image poop;
public int time;
public bool poopToggle
{
get { return _poopToggle; }
set { poop.enable = value; _poopToggle = value; }
}
//Added variable//
public float lastTime = 0;
private bool _poopToggle;
public const float WaitTime = 5;
void Start ()
{
lastTime += Time.time;
poop = GetComponent<Image> ();
poopToggle = false;
}
void Update ()
{
if (lastTime > Time.time && !poopTiggle)
{
lastTime += WaitTime;
poopToggle = true;
}
}
}
Great Solution :D. However i found a different solution for people like me who have less than 2 months with C#. Here it is, there are issues but they are fixable fully flexible to fill your needs.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Poop : $$anonymous$$onoBehaviour {
private Image poop;
public int time;
public float delay = 5.0f;
public bool poopToggle;
void Start ()
{
poop = GetComponent<Image> ();
poopToggle = false;
}
void Update()
{
if (poopToggle == false) {
poop.enabled = false;
} else {
if (poopToggle == true) {
poop.enabled = true;
}
}
delay -= Time.deltaTime;
if (delay < 0 && poopToggle == false)
{
delay = 10.0f;
poopToggle = true;
}
}
}
Answer by Fredex8 · Apr 01, 2016 at 07:26 AM
Any time Unity freezes after adding some code the first thing to check if probably the while
loop.
IEnumerator delaytime()
{
while (poopToggle == false) {
yield return new WaitForSeconds (5);
poopToggle = true;
}
}
What your coroutine is doing there is telling it to start waiting for 5 seconds all the while it equals false... and since it is never going to equal true that creates an infinite wait. You don't need a while loop for this at all:
void Update ()
{
if (poopToggle == false)
{
poop.enabled = false;
}
else
{
poop.enabled = true;
StartCoroutine (delaytime());
}
}
IEnumerator delaytime()
{
poopToggle == false;
yield return new WaitForSeconds (5);
poopToggle = true;
}
Your else statement was also written wrong by the way. Check the difference above. You could of course just remove the poopToggle
condition entirely and have the coroutine just set enabled directly.
IEnumerator delaytime()
{
poop.enabled = false;
yield return new WaitForSeconds (5);
poop.enabled = true;
}
That would do the same thing as you are doing in update with the conditions, provided you called it again when it ended. The difference is it only sets poop.enabled = false;
once rather than every single frame. Whilst more efficient it isn't going to actually make a noticeable difference but it is generally just better practice I think.
Sorry, but what you did doesn't work either, here's why.
void Update ()
{
if (poopToggle == false)
{
poop.enabled = false;
//StartCoroutine (delaytime()); works here but the problem is as follows, when i press my button the bool is almost instantly setting back to true
}
else
{//if(poopToggle == true) <== you missed that part doesn't work otherwise on Unity5
poop.enabled = true;
StartCoroutine (delaytime()); //When This starts poopToggle=false, that makes the thing pop up for a frame only
//I want the opposite effect.
}
}
IEnumerator delaytime()
{
poopToggle == false;
yield return new WaitForSeconds (5);
poopToggle = true;
//When i set PoopToggle to False i want THIS function to repeat itself.
}
I explained the problems in the Code Sample. It's checking for True or False every frame, i want to do it once every time it's set to False, when it's false i want to start the coroutine that you proposed and once it's true i want it to stay true till i click it, after i click it i want it to stay back false for a few seconds if not $$anonymous$$utes even when the game's done. What this above here does after fixing is checking every frame making it sometimes set back to true every frame.
Ah well you hadn't mentioned clicking a button to trigger anything. What is the actual behaviour you desire from this then? All I did was clean up your code to create a 5 second counter to set the image to visible which appeared to be what your script was attempting. What you probably want to be doing ins$$anonymous$$d is instantiating a new instance of the poop image as a new gameObject and having the cleanup script on that which destroys it after 5 seconds of cleaning or after being clicked. That would mean you could have multiple instances of it on screen in random places at the same time. I assume that is what you are trying to do.
Also whilst I am here...
//if(poopToggle == true) <== you missed that part doesn't work otherwise on Unity5
Writing that isn't actually necessary. Booleans can be checked true just with if(poopToggle)
and false just with if(!poopToggle)
. I generally prefer to use if(poopToggle == true)
as it makes it easier to read but in this instance I used just an else
statement as a boolean can only ever be true or false. If you have already written if (poopToggle == false)
then the only thing the else can be is true. Floats, ints, gameObjects and so on need an operator and a comparison value but booleans cannot be null and are themselves a comparison.
If you do want to write it out fully for the sake of clarity it should be:
if (poopToggle == false)
{
}
else if (poopToggle == true)
{
}
That will be checking the bool twice for no reason though, unless Unity optimises it automatically (I don't know). Whereas else
without a condition doesn't require an additional check. Either way it should not be:
if (poopToggle == false)
{
}
else
{
if (poopToggle == true)
{
}
}
I mean that will still work but with a boolean there is no reason to do that. It just means you are checking the condition of the boolean twice for no reason and any code accidentally placed within else
rather than if (poopToggle == true)
could cause the latter not to run. The boolean in the original answer works fine but it may not produce the desired behaviour... because I don't know what that desired behaviour is...
The thing is, it's much simpler to just disable the Image component than to instantiate the whole thing. I'll put both scripts here, also i kinda did not explain completely that i have a button with it.
here's the button code. I have a Pet, it has to take a Dump, it takes it and i Clean it up. After i clean it up I want it to take a dump again after the same ammount of time.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Cleanerr : $$anonymous$$onoBehaviour {
public Button button;
public Poop pooper;
void Start ()
{
button = GetComponent<Button> ();
}
void Update ()
{
if (pooper.poopToggle == true) {
button.interactable = false;
} else {
if (pooper.poopToggle == false) {
button.interactable = true;
}
}
}
public void CleanIt()
{
pooper.poopToggle = true;
}
}
Here's my current sh*tter code, it's made to enable the Image component 5 seconds after the bool is set to true. Give me the simplest solution to my problems. <3
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Poop : $$anonymous$$onoBehaviour {
private Image poop;
public int time;
public bool poopToggle;
void Start ()
{
poop = GetComponent<Image> ();
poopToggle = true;
}
void Update ()
{
if (poopToggle == true) {
poop.enabled = false;
StartCoroutine (delaytime ());
} else {
if (poopToggle == false) {
poop.enabled = true;
}
}
}
IEnumerator delaytime()
{
poopToggle = true;
yield return new WaitForSeconds (5);
poopToggle = false;
}
}
Answer by Bleackk · Apr 01, 2016 at 02:36 PM
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Poop : MonoBehaviour {
private Image poop;
public int time;
public float delay = 5.0f;
public bool poopToggle;
void Start ()
{
poop = GetComponent<Image> ();
poopToggle = false;
}
void Update()
{
if (poopToggle == false) {
poop.enabled = false;
delay -= Time.deltaTime;
} else {
if (poopToggle == true) {
poop.enabled = true;
delay = Random.Range (50, 100);
}
}
if (delay < 0 && poopToggle == false)
{
poopToggle = true;
}
}
}
This script is Exactly What i was Looking For. :)
Your answer
Follow this Question
Related Questions
Break the loop when there are no more questions 0 Answers
Why is my script causing Unity to crash? 1 Answer
Unity update does not be called when lock screen 0 Answers
Why this script crashes Unity 1 Answer
if ALL items in array are something 1 Answer