- Home /
(Solved) Invoke vs WaitForSeconds, and reusable waits.
I am working on a resource collection script. Every frame, the game checks if you are hovering over a resource and if you are holding down right mouse button. If so, and here is my problem, there should be a collection wait time(cooldown) and then your resource amount should increase by one. However, neither route i've tried to take works. With invoke, it correctly waits for the specified time before actually giving the resource, but than continues to give me resources, without waiting again. Same goes for WaitForSeconds in a coroutine. I need a way to reuse the wait for either of these methods, but can't seem to find out how. Any help would be very much appreciated. Here is my code:
using System.Collections;
using UnityEngine;
[RequireComponent(typeof(CameraRaycaster))]
public class gatherResource : MonoBehaviour
{
new Camera camera;
CameraRaycaster camRay;
bool onResource = false;
bool onCooldown = true;
public float gatherSpeed = 3;
public int testResource = 0;
public Coroutine collectResource = null;
// Use this for initialization
void Start ()
{
camera = FindObjectOfType<Camera>();
camRay = camera.GetComponent<CameraRaycaster>();
camRay.onLayerChange += LayerIsResource;
}
private void Update()
{
while (Input.GetMouseButton(1) && onResource == true)
{
print(testResource);
Invoke("CollectResource", gatherSpeed);
break;
}
}
void LayerIsResource(Layer currentLayer)
{
if (currentLayer == Layer.Resource)
onResource = true;
else
onResource = false;
}
float CollectResource()
{
return testResource++;
}
}
Answer by Bunny83 · Mar 05, 2018 at 11:27 PM
Update is executed once every frame. Your strange "while loop" is actually just an if statement since you have a break in it. GetMouseButton returns the state of the button. That means as long as the button is pressed down you will start a new Invoke every frame. It's not really clear how your script is supposed to work. Even when you use GetMouseButtonDown (which is only true for one frame when the button is pressed down) the user can simply click two or more times and each time it starts a new invoke. If that's what you want just replace GetMouseButton with GetMouseButtonDown.
However if you want to only allow "collecting" the resource once every "gatherSpeed" you better use a coroutine like this:
void Start()
{
StartCoroutine(CollectResource());
}
IEnumerator CollectResource()
{
while (true)
{
if (onResource && Input.GetMouseButtonDown(1))
{
testResource++;
yield return new WaitForSeconds(gatherSpeed);
}
yield return null;
}
}
This allows the user to click when onResource is true but restrict the clicking to once every "gatherSpeed" seconds. If you like to delay the increment to after the wait time, just move it right below the WaitForSeconds.
Dude, thank you! I have been messing with this forever, and I knew the answer was simple, I just couldn't get it! $$anonymous$$y original code, when I was messing with Coroutines, looked similar to this, but I missed 2 very important things. First, I didn't realize a coroutine can continue to be uses when initialized in start, and two, I forgot the yield return null part. That is what I really needed!! Thanks again!
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Invoke/Coroutine problems with events 2 Answers
How do I pause a script while until after a function is done running? 3 Answers
NativeHashMap missing in 2021? 1 Answer