The following strategy was suggested, in order to allow some time for a big system to finish all the loading, etc...
So, the idea is to make sure I have waited for long enough for everything to be loaded, and then do my own command. Let's call it CMD() for now.
void Start()
{
StartCoroutine( TakeYourTime() );
}
IEnumerator TakeYourTime()
{
yield return new WaitForNewFrame();
yield return new WaitForNewFrame();
yield return new WaitForNewFrame();
yield return new WaitForNewFrame();
CMD();
}
But of course, Unity3D does not recognize WaitForNewFrame()!
After googling, I realized there is only WaitForEndOfFrame() available, so I replaced it in the above, thinking that it would achieve the same, but my CMD() does not take effect.
So, I am wondering if this existing command is not the same as the originally-suggested one, or if I am not waiting long enough?
yield return null;
is the command that will get the method to return on next frame and continue.
But this is no good practice as you cannot know if one , two or more frames are required.
You should have some kind of control over the flow of your program. If some actions are long and spread over several frames, provide a callback to the coroutine:
void Awake()
{
StartCoroutine(Loading(CMD));
}
private void CMD(){ //Other actions }
private IEnumerator Loading (Action action)
{
// Many long action with yield
if(action != null) { action(); }
}
If CMD() is also an IEnumerator function, you have to do another StartCoroutine() function on it, or it will not work. Based on the information available that's the only issue I can think of to explain why CMD() would not start.
If you have additional logic after that requires to wait on the completion of CMD(), you can yield return the StartCoroutine() call to pause TakeYourTime() from continuing until CMD() is completed.
void Start()
{
StartCoroutine( TakeYourTime() );
}
IEnumerator TakeYourTime()
{
yield return new WaitForEndOfFrame();
yield return new WaitForEndOfFrame();
yield return new WaitForEndOfFrame();
yield return new WaitForEndOfFrame();
yield return StartCoroutine(CMD());
//Do the rest.
}
IEnumerator CMD()
{
//Do whatever.
}
If CMD() is not an IEnumerator function, then I apologize for this incorrect answer. You can troubleshoot further using Debug.Log() calls to determine where the application is getting stuck. I would put them before, after, and on the first line of CMD()
From your comments, though, I would recommend you do something else.
You mention that when you wait longer, it works. That means you're just waiting on something to complete, and there's no issue with methods firing.
You should do something like this instead:
IEnumerator TakeYourTime()
{
while(!otherThingIsFinished())
{
yield return new WaitForEndOfFrame();
}
CMD();
}
otherThingIsFinished() should be a call to check to see if the stuff you're waiting for has completed whatever it's doing. You can have a public method that you can call that checks some private boolean that gets set when it's completed.
You can also just have the other stuff call this method directly, although that may not be the best option either. It all depends on what exactly you're trying to do.
Related
For some reason whenever I Instantiate, I can only instantiate once per build/run/game. I've tried to see if it was that I could only use different prefabs, but that isn't it. Please help, I've been trying to find an answer but no one seems to have the same problem. Thanks for reading this.
heres the project (assets and project settings) if you wanna mess around with it yourself
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CreatePipe : MonoBehaviour
{
public GameObject Pipe;
public bool yes = false;
// Start is called before the first frame update
void Start()
{
StartCoroutine("initializationn");
Debug.Log("started");
}
// Update is called once per frame
void Update()
{
// if (yes){
// inst();
// yes = false;
// }
}
public IEnumerator initializationn()
{
Debug.Log("started");
inst();
// yes = true;
yield return new WaitForSeconds(3);
inst();
// yes = true;
yield return new WaitForSeconds(3);
inst();
// yes = true;
yield return new WaitForSeconds(3);
// while (true){
// inst()
// yield return new WaitForSeconds(3);
// }
}
public void inst(){
Debug.Log("in");
var g = Instantiate(Pipe, new Vector3(7f, Random.Range(-6.5f,0f), 0f), Quaternion.identity);
g.SetActive(true);
g.name = "Pipe";
}
}
The reason only one pipe exist at at time is that the script "PipeStuff" you attached to the Prefab "Pipe", makes it a singleton. So every time you create a duplicate instance you are deleting that object since a "PipeStuff" already exist.
Suggestions:
Your script is absolutely fine there is no problem with it but perhaps you are destroying that gameObject which is intantiating those pipe prefabs thats why its not working as you intend it to, any ways check if it is so because there seems to be no other problem with your script and also you can do it in one more way by using invokeRepeating function too like:
InvokeRepeating( nameof(inst), 0, 3 );
it will call this function repeatadely after every 3 seconds and the first parameter which is 0, is used for delay at the start so if you want to Invoke that function after some seconds you can do so as well and when you are done you can destroy or disable that gameObject too, its just a basic way of doing so otherwise there are tons of ways to do so anyways...
Hope it helps... Happy Coding :)
I want to set a delay after every dotween loop. Onstepcomplete method doesn't seem to work with Ienumorator and SetDelay method delay at the start of the Tween. How do I it?
void Movement()
{
transform.DOPath(path, moveduration, pathType, pathMode, 10).SetLoops(-1, LoopType.Yoyo).SetEase(ease).SetDelay(startdelay)
.OnStepComplete(StartCoroutine(Wait()));
}
private IEnumerator Wait()
{
yield return new WaitForSeconds(delay);
}
You need to put your tween in a sequence to do what you want.
DOTween.Sequence().SetDelay(1f).Append(transform.DOPath(XXX).OnComplete(XXX)).AppendInterval(1f).SetLoops(-1, LoopType.Yoyo).Play();
I have 2 instances of this IEnumerator on 2 scripts. Both are private, but one is working, the other isn't.
This is the first one that is working:
private IEnumerator EndGame()
{
yield return new WaitForSeconds(3);
SceneManager.LoadScene("Menu", LoadSceneMode.Single);
}
This is the second one that isn't working:
private IEnumerator EndGame()
{
yield return new WaitForSeconds(3);
SceneManager.LoadScene("Menu", LoadSceneMode.Single);
}
They're exactly the same. I can call the IEnumerator (proven by a Debug.Log), but in one case it waits for 3 seconds, and in the other one it stops at the return statement and doesn't continue. I also tried renaming the Coroutine that wasn't working and making them both private just in case you can't have Coroutines with the same name, but that also didn't work. My time scale is constantly remaining at 1 and the object that I called the Coroutine from doesn't get destroyed.
One weird thing that does happen is the object that I call the Coroutine from does get destroyed, but after the 3 seconds is up (The highlighted player is the one calling the Coroutine, and the same thing happens on both players):
I can't understand why.
I already read lots of documents about it and there are lots of comments that
StopCoroutine(string) can only stop the coroutine starts with StartCoroutine(string)
the code is below.
In Class CharTouchControl.cpp
if( Input.GetKeyDown( KeyCode.Q ) )
{
_CharControl.StartCoroutine("useFever", 10);
}
_CharControl is a member of CharTouchControl and of course _CharControl is referencing the CharControl instance below.
And InClass CharControl
public IEnumerator useFever(float _duration = 10)
{
if( m_nUseFever < _nFeverMax )
{
Debug.Log("Stop!!");
StopCoroutine("useFever");
yield return new WaitForEndOfFrame();
}
m_fgCharState = CharState._FEVER;
// fever particle
m_psFeverPaticle.Simulate(4);
yield return new WaitForEndOfFrame();
} // end of useFever
When m_nUseFever < _nFeverMax is true, i can see "Stop!!" log,
but the coroutine don't stop and simulate paticles.
anybody help for this?
Just as Jerdak mentioned, you should use yield break when your inside the Coroutine.
the coroutine will automatically stop when it finishes its code block. Using yield break, should send it to the end of the code block.
Additionally you could modify your code so that it only runs the code block if the condition is true. Ive done this in the example below. If the condition is false the coroutine will just wait for the end of the frame and then exit.
public IEnumerator useFever()
{
if( m_nUseFever > _nFeverMax )
{
m_fgCharState = CharState._FEVER;
// fever particle
m_psFeverPaticle.Simulate(4);
}
yield return new WaitForEndOfFrame();
} //Coroutine automatically exits here
EDIT:
Dan Puzey brought up a good point, Are you sure shouldn't be using
Invoke("useFever",10) or InvokeRepeating ("useFever",10,1)
instead? From your code it looks like you just want to run the useFever function in 10 seconds. If thats the case, you should be invoking it instead of running it as a coroutine, and useFever should be a normal function.
Just for reference, there is also CancelInvoke("useFever")
This is my code:
void playerproc(int player)
{
switch(player)
{
case 1:
move=(numSticks+4)%5;
return move;
break;
case 2:
srand(5);
move=(rand()%4)+1;
return move;
}
}
void nimmanager(int numStick)
{
numSticks=numStick;
int player;
Thread *t=new Thread("Players");
while(numSticks!=0)
{
player=1;
int move=t->Fork(playerproc,player);
numSticks-=move;
printf("Name of the player: %d\nNumber of sticks taken:%d\nNumber of sticks left=%d",player,move,numSticks);
player=2;
int move=t->Fork(playerproc,player);
numSticks-=move;
printf("Name of the player: %d\nNumber of sticks taken:%d\nNumber of sticks left=%d",player,move,numSticks);
}
printf("Winner is player 1");
}
This is a code for NIM game. Now I want to return value from the method playerproc(which i m spawning using fork()) and get it's return vale in the method NIM manager. I am not able to get it. I am using NachOs.
I think you should have a look at the Fork(...) source code in /threads/thread.cc. I always found answers in the source code when I was using NACHOS.
Fork(...) returns void. Unless you make the return value of your function a global variable, you shouldn't be able to access it. Fork(...) is allocating a new stack and adding a thread to run the function to the ready queue. So the scope of the return variable of your function is limited to that function.
Why exactly are you forking the threads for the playerproc() function? Multiple threads doesn't make that much sense here, since your main thread must wait for playerproc() to return anyway before continuing.