- Home /
Pause a script completely
Hello,
I have a small modding system and want to make a wait option in it. First, let me explain how the modding system works. I get the lines from a txt file, separate them into words, then test for a certain word using an if statement and do the action.
My problem is that I made it so that when I have a keyword wait, it will set a bool to false and will let other lines pass. This bool is also set automatically to true before a wait, it will go to false only when using wait, and after a WaitForSeconds, it will go back to true and let the commands/lines pass. The thing is that when it's waiting with WaitForSeconds, the script lets the next lines pass, and the next line sees that the bool is set to false, so it will not activate, so I lose that line.
Here is the bit of the code: bool ready;
void Start () {
ready = true;
}
(...)
if (param[0] == "wait") { //The first word of the line/command
ready = false;
StartCoroutine(float.Parse(param[1]));
}
if (ready == true) {
(...)
}
IEnumerator Wait (float amount) {
yield return new WaitForSeconds(amount);
ready = true;
}
Note this code may be wrong because I had to make it again (I removed the original part as it wasn't working.)
Thank you!
Answer by Catlard · May 07, 2015 at 05:22 AM
I believe the problem is your perception of how coroutines (and the command StartCoroutine) works. Basically, Startcoroutines happen, and then it runs the code immediately afterward, in a seperate thread. If you want the stuff in a coroutine to happen first, and for the game to "wait" for that to be over, you need to use
print("a!");
yield return StartCoroutine(yourWaitingFunctionName);
print("b!");
This will only print b after your coroutine is over. HOWEVER, this said, you cannot yield return like this unless you're already in a coroutine. So your calling function must also be an ienumerator. Does that make sense?
I understand but I want to keep my basic code to be in the normal method, I don't want to move it in the coroutine as this wait system is only called if the user wants it to happen. But I still want the other stuff to happen if there is no param wait.
Here is an example:
if (param[0] == "wait") { //The first word of the line/command
ready = false;
StartCoroutine(float.Parse(param[1]));
}
if (ready == true) {
if (param[0] == test) {
Debug.Log("Test");
}
}
The thing is that I still want the test to happen if param[0] has test. So basically it's kind of a command system but with multiple commands. I have the command test and the command wait.
If I do wait and then test, it would wait before doing test. But If I do test, it would immediately do test.
I hope you understand what I mean
I think you're saying you don't want to yield return coroutine in the middle of the function -- so that means you should set a flag wherever it happens, and then at the end of the function yield return the coroutine (if the flag is true? Like this:
public IEnumerator CheckForPause(string[] parameters) {
bool isShouldPause = DoSomeChecks (parameters);
if (isShouldPause) {
yield return StartCoroutine ("Wait");
} else {
yield return 0; //we have to wait at least once in a coroutine -- this waits one frame.
}
}
public bool DoSomeChecks(string[] parameters) {
bool isShouldPauseLater = false;
foreach (string s in parameters) {
if(s=="wait") {
isShouldPauseLater = true;
}
}
return isShouldPauseLater;
}
Thing is that I don't know if it'll work because I am sending each line separately as an array from another script.
Basically I have a script Load$$anonymous$$od.cs which basically takes a txt file, parses it into lines and puts them in an array. Then in this script (the $$anonymous$$od script) I separate each line using a while loop and then send each separately to the method which I showed previously. This method will get the line, separate it into words and put them in the array param[].
I then check if param[0] which is the first word is equal to wait or test, and then I do my thing. So I don't really know if your code would work.
Also If it works, which function should I call? And from where?
I'm not sure exactly what you're saying, but I think you're saying that you can't do any waiting until after all the mod information has been received by all the objects in your scene. So, you have three phases: before the commands have been received, the reception of all the commands, and then the time after the commands are received (which is also when you, personally, want to wait). If this is true, then you can just use a flag like isShouldPauseLater in the code above. Write your code so that nothing is affected by this flag until you've reached the third phase. Then allow your objects to wait -- perhaps you'll need to also send some information, like "pause time amount", to each object that your code pauses.
I should be clear -- none of the code that I wrote is meant to fit directly into your code. It's just an example of how some things work -- how I often do these sorts of things -- so you can use those ideas in your code.
Could i possibly (ins$$anonymous$$d of making all that) disable the object that has the mod script?
So that when there is Wait(), it would first send to another script, in that other script, disable the normal script, do a waitforseconds, then re-enable it? Or would I loose all the params?
Answer by Bunny83 · May 08, 2015 at 01:40 AM
I think you haven't understood what a coroutine actually is or how it works ^^. If you don't yield in a coroutine it will run through your code like a normal function. However you have the option to wait for certain things conditionally. Example:
IEnumerator Start()
{
// Do your loading
while (not done with the file)
{
// parse your params from the current "command"
// [...]
if (param[0] == "wait") {
yield return new WaitForSeconds(float.Parse(param[1]));
}
else if(param[0] == "someOtherAwesomeCommand"){
Debug.Log("Execute someOtherAwesomeCommand");
}
// [...]
}
}
If there's no "wait" command in the file it will just rush through your file without any delay and will finish even before the first Update is called. However if a wait command is encountered it will stop executing for the given time and then continue with the next command.
That would not work.
Let's say my script is called $$anonymous$$od.cs ok, so I use another script called Load$$anonymous$$od.cs that basically sends each line separately to $$anonymous$$od.cs like that $$anonymous$$od(line[1]);
So when there is wait, I basically want it to stop the script completely. Which I'm not sure will work, but it won't with yours because when there is wait, it will just stop the instance of that script as there is nothing else to do. There is only wait in that line.
So it'll send the next line and not care about the wait.
@$$anonymous$$ig35700:
What doesn't work is your approach. It's absolutely impossible with your setup. period. If you iterate through all lines in your Load$$anonymous$$od script with an ordinary loop you can't "wait" in that loop.
Well you could use `System.Threading.Thread.Sleep()` but it will freeze your whole application for the time specified. Unity only runs in a single thread (at least the whole scripting environment). So while an ordinary method is executing nothing (absolutely nothing) can happen in between until the method is finished. Only coroutines allow you to cooperatively have chunks of code see$$anonymous$$gly run in parallel.
If you have your loop in Start without a coroutine that means the game doesn't even start before your Start method is done. No visuals will be rendered and no Update will run.
What's the point of having another script loading the lines of the file? The parsing of the file should be handled in one place.
Hey, no need to be so mad...
The thing is that I am parsing in the $$anonymous$$od.cs and Sending the lines to parse in Load$$anonymous$$od.cs
Now, Catlard may be on something, so let's not say that something is impossible or anything, NOTHING IS I$$anonymous$$POSSIBL$$anonymous$$
@$$anonymous$$ig35700:
At which point i appear "mad"? o.O
I just made sure that with your current setup (at least the way you presented it) it's impossible. Sure nothing is impossible but you have to change something. The best "start" to solve your problem is to actually post the code where and how you actually process the text file. You only posted fragments of code which could be inside anything. If you don't process it either in a coroutine or in Update you can't "wait".
Answer by PandawanFr · May 11, 2015 at 08:16 AM
Ok, for clarification, here's my LoadMod.cs
using UnityEngine;
using System.Collections;
using System.Xml;
using System;
using System.IO;
public class LoadMod : MonoBehaviour {
//This script loads all mods that are found in A Game/mods
string path; //Path to app
public string[] files;
ModParser parser;
void Start () {
parser = this.GetComponent<ModParser>();
//Setup mods folder in app
path = Application.dataPath;
//If there is no mods directory, make one
if (!Directory.Exists(path+"/mods")) {
Directory.CreateDirectory(path+"/mods");
}
Load();
}
public void Load() {
//Set all mods files in one array
files = Directory.GetFiles(path + "/mods", "*.txt");
Debug.Log ("Mods Installed:");
for (int i = 0; i < files.Length; i++){
string file = files[i];
GetComponent<ModParser>().x = files.Length;
//Debug.Log (file); //Debugs all mods
string[] lines = System.IO.File.ReadAllLines(file);
parser.Parse(lines);
}
}
}
Then there is ModParser.cs (which I renamed, it used to be Mod.cs). It's a simplified version as there are more if statements for param[0] but they would make this post too big
using UnityEngine;
using System.Collections;
using UnityStandardAssets.Characters.FirstPerson;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.UI;
public class ModParser : MonoBehaviour
{
//This script takes the strings (mods) from LoadMod and translates them into a Unity based system.
//This is basically the odding system itself, LoadMod is just to load the mods, this script makes all the processing and modding
public int x = 0; // Used for information
bool ready;
//This will translate the string into the unity system
public void Parse (string[] modLines)
{
int i = 0;
lineNumber = 1;
while (i < modLines.Length) {//Makes each line a unique string
Use (modLines [i]);
lineNumber++;
i++;
}
}
public void Use (string modLine){
string[] param = modLine.Split (" " [0]);
if (param[0] == "wait") {
ready = false;
StartCoroutine(Wait(float.Parse(param[1])));
}
if (param [0] == "display" && ready == true) { //Display text in chat or title
if (param [1] == "chat") {
string finalOutput = "";
int i = 0;
while (i < param.Length) {
if (i != 0 && i != 1) {
finalOutput = finalOutput + " " + param [i];
}
i++;
}
GameObject.FindGameObjectWithTag ("Player").GetComponent<Commands> ().output = finalOutput; //Commands is basically the Chat script, output is the text that appears in the chat
}else {
Error (1);
}
}
else {
Error (1);//This will send an error from another method
}
}
IEnumerator Wait (float time) {
yield return new WaitForSeconds(time);
ready = true;
}
}
The problem is that after a wait, it will see that ready is still equal to false, so it will not activate and go to the next line. If when going to the next line it's still not done (still not ready = true) then it will go to the next...
Because no one seems to want to help, I'm just going to remove this thread.
Your answer
Follow this Question
Related Questions
Make enemy wait before attacking player 2 Answers
Problem getting AI to wait 1 Answer
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Cant Make C# Use waitforseconds Command 3 Answers