Unity3D Coroutine compiler error - c#

I'm a complete beginner in unity, and i'm tring to play an animation with a coroutine, but get the following erros:
1.error CS1502: The best overloaded method match for UnityEngine.MonoBehaviour.StartCoroutine(System.Collections.IEnumerator)' has some invalid arguments
2.error CS1503: Argument#1' cannot convert System.Collections.IEnumerable' expression to typeSystem.Collections.IEnumerator'
The code:
using UnityEngine;
using System.Collections;
public class Trap : MonoBehaviour {
//public float delayTime;
// Use this for initialization
void Start () {
StartCoroutine (Go ());
}
// Update is called once per frame
void Update () {
}
IEnumerable Go(){
while (true) {
animation.Play();
yield return new WaitForSeconds(3f);
}
}
}

change
IEnumerable Go(){
while (true) {
animation.Play();
yield return new WaitForSeconds(3f);
}
}
for a IEnumerator...
IEnumerator Go(){
while (true) {
animation.Play();
yield return new WaitForSeconds(3f);
}
}

The return type for an Coroutine will be IEnumerator.

Related

Unity -3D: StartCoroutine

any way i can make this code print "attacking" and than for 2 seconds then print it again and so on. this script just waits for 2 seconds the first time. and then keeps printing it with every frame
public class ZombieAI : MonoBehaviour
{
// Update is called once per frame
void Update()
{
StartCoroutine(time());
}
IEnumerator time()
{
yield return new WaitForSeconds(4);
Debug.Log("Attacking");
}
}
You can implement it by doing this
public class ZombieAI : MonoBehaviour
{
// Update is called once per frame
void Start()
{
StartCoroutine(time());
}
IEnumerator time()
{
Debug.Log("Attacking");
yield return new WaitForSeconds(2);
StartCoroutine(time());
}
}
You have to start the coroutine from inside the coroutine. However, if you want to implement this WITHOUT coroutines, do this:
public class ZombieAI : MonoBehaviour
{
float timer = 0;
public float attackTimer = 2;
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
if (timer >= attackTimer)
{
Debug.Log("Attacking!");
timer = 0;
}
}
}
Coroutines can cause headaches, but use whichever one you want :)
Firstly, do not put StartCoroutine() in Update(). That will begin a new coroutine every frame.
Apart from that, you just need to put the action inside a loop, e.g. a for loop. If you want it to keep looping indefinitely until you manually stop the coroutine, you can use:
public class ZombieAI : MonoBehaviour
{
void Start() // Or anywhere that will only be called once when you want to start the coroutine)
{
StartCoroutine(time());
}
IEnumerator time()
{
while( true ) {
yield return new WaitForSeconds(2);
Debug.Log("Attacking");
}
}
}

New to unity and c#, unexpected symbol issue in (14,29)

in my code theres this error
Assets/TextChangeScript.cs(14,29): error CS1525: Unexpected symbol (', expecting,', ;', or='
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TextChangeScript : MonoBehaviour
{
public Text m_MyText;
public Text OtherText;
void Start()
{
m_MyText.text = "There was once a mother and her child";
yield WaitForSeconds (3);
m_MyText.text = "The mother loved her child very dearly";
}
}
You are trying to call yield WaitForSeconds in a function that doesn't return an IEnumerator. You need to create a new function that returns IEnumerator and call it with StartCoroutine.
The code after the yield will be executed.
You can check the documentation. Unity is well documented.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class WaitForSecondsExample : MonoBehaviour
{
public Text m_MyText;
public Text OtherText;
void Start()
{
StartCoroutine(Example());
}
IEnumerator Example()
{
m_MyText.text = "There was once a mother and her child";
yield return new WaitForSeconds(3);
m_MyText.text = "The mother loved her child very dearly";
}
}
Use a Coroutine, Unity is well documented on how they work and you can use the link in Chopi's answer.
Now to avoid any confusion, normally in a function you will want a return to be the last call in your function as code behind it typically does not get called. This is not the case for an IEnumerator.
The line yield return new WaitForSeconds(3); returns an expression from a function and is used as a place to mark where execution is to continue, in this case in 3 seconds at that line.
Your start method is not an IEnumerator, and as far as I am tracking there isn't a way to yield in your start in Unity. You can start a coroutine in start and have that coroutine yield. Here is an example of a coroutine that will give you, your 3 second delay between your text:
using UnityEngine;
using UnityEngine.UI;
public class TextChangeScript : MonoBehaviour
{
public Text m_MyText;
public Text OtherText;
IEnumerator StoryText() {
m_MyText.text = "There was once a mother and her child";
yield return new WaitForSeconds (3);
m_MyText.text = "The mother loved her child very dearly";
yield return new WaitForSeconds (3);
m_MyText.text = "Then one day blah blah blah";
}
void Start()
{
StartCoroutine(StoryText());
}
void Update()
{
}
}
Here is an example of using a for loop to loop through text with a 3 second delay between them:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TextChangeScript : MonoBehaviour
{
public Text m_MyText;
public List<string> storyText;
IEnumerator StoryText() {
foreach (string sz in storyText)
{
text.text = sz;
yield return new WaitForSeconds(3); // in 3 seconds. execution will begin here and iterate to the next string in the storyText.
}
}
void Start()
{
StartCoroutine(StoryText());
}
void Update()
{
}
}
Edit:
Thanks to what R1PFake shared in the comments you can also do this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class CenterName : MonoBehaviour {
public Text text;
public List<string> storyText;
// Use this for initialization
IEnumerator Start () {
foreach (string sz in storyText)
{
text.text = sz;
yield return new WaitForSeconds(3);
}
}
}

How to access a value from OnTriggerEnter2D in another function?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RedHP : MonoBehaviour
{
public float HP = 5;
public GameObject BlueWon;
public GameObject Restart;
void OnTriggerEnter2D(Collider2D trig)
{
if (trig.gameObject.tag == "ThrowableBlue")
{
StartCoroutine(BowlDestroyTime());
HP--;
if (HP <= 0)
{
BlueWon.SetActive(true);
Restart.SetActive(true);
PlayerBlueController.canMove = false;
PlayerBlueController.canFire = false;
}
}
}
IEnumerator BowlDestroyTime()
{
yield return new WaitForSeconds(1);
Destroy(trig.gameObject);
}
}
I simply want to destroy my object after too little period of time to make it look better. In IEnumerator I can't access trig.gameObject because it is defined in OnTriggerEnter2D. Is there a way to access this value?
I also tried to put IEnumerator in OnTriggerEnter2D it also didn't work. Kinda newbie
You don't have to do that. The Destroy function can take a second parameter as a delay time before the Object is destroyed.
Destroy(trig.gameObject, 1f);
If you still want to use coroutine to do this, simply make the BowlDestroyTime function to take GameObject as parameter then pass the GameObject from the OnTriggerEnter2D function to the BowlDestroyTime function to be destroyed.
void OnTriggerEnter2D(Collider2D trig)
{
if (trig.gameObject.tag == "ThrowableBlue")
{
StartCoroutine(BowlDestroyTime(trig.gameObject));
HP--;
if (HP <= 0)
{
BlueWon.SetActive(true);
Restart.SetActive(true);
PlayerBlueController.canMove = false;
PlayerBlueController.canFire = false;
}
}
}
IEnumerator BowlDestroyTime(GameObject tartgetObj)
{
yield return new WaitForSeconds(1);
Destroy(tartgetObj);
}

How to shortcut a coroutine?

I wrote a co-routine to do batch work every frame, I have no problem starting it, but I want to stop the execution when specific conditions are met.
Such as :
public IEnumerator workCoroutine(){
int i = 0;
if(GLOBAL_LOCK){
return; //will not work here.
//we will not execute this coroutine further more, ie,shortcut it;
//but how to ?
}
while( i<=1000){
doingSomeWorkHere(i);
i++;
yield return null;
}
}
I know I could maybe do this by:
public IEnumerator workCoroutine(){
int i = 0;
if(!GLOBAL_LOCK){
while( i<=1000){
doingSomeWorkHere(i);
i++;
yield return null;
}
}
}
But I think this way may cause the code to get ugly when there are multiple conditions.
So is there a way to cut off the co-routine?
EDIT
I really don't understand what people are saying in the comments, here is a fully functioning test script, will somebody point out how to test if the co-routine has exited? or give me some material to read on?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestCoroutine : MonoBehaviour {
private bool GLOBAL_LOCK = true;
public IEnumerator workCoroutine()
{
int i = 0;
if (!GLOBAL_LOCK)
{
while (i <= 10)
{
Debug.Log(i);
i++;
yield return null;
}
Debug.Log(" I am in if condition");
}
Debug.Log(" will exit the coroutine");
}
// Use this for initialization
void Start () {
StartCoroutine(workCoroutine());
}
}
You need to check for the GLOBAL_LOCK inside while loop as follows -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestCoroutine : MonoBehaviour {
private bool GLOBAL_LOCK = true;
public IEnumerator workCoroutine()
{
int i = 0;
while (i <= 10)
{
if (GLOBAL_LOCK)
{
Debug.Log(" I am in if condition");
Debug.Log(" will exit the coroutine");
yield break;
}else{
Debug.Log(i);
i++;
yield return null;
}
}
}
// Use this for initialization
void Start () {
StartCoroutine(workCoroutine());
}
}
This code will print the Log statements from if condition and exit the coroutine because GLOBAL_LOCK is set to true.
Beside #MukeshSaini, answer you can also stop execution of your coroutine using StopCoroutine Function.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestCoroutine : MonoBehaviour {
private bool GLOBAL_LOCK = true;
// keep a copy of the executing script
private IEnumerator coroutine;
public IEnumerator workCoroutine()
{
int i = 0;
while (i <= 10)
{
Debug.Log(i);
i++;
yield return null;
}
}
// Use this for initialization
void Start () {
StartCoroutine(workCoroutine());
}
void Update() {
if (GLOBAL_LOCK )//your specific condition
{
StopCoroutine(coroutine);
}
}
}
Advantage: This will allow you to stop your coroutine from any place, i provide example with update

WaitForSeconds on C#

Look at this simple code:
function Start()
{
yield WaitForSeconds (4);
Application.LoadLevel(1);
}
It works! I'm trying to make something similiar using C#, but the processor just ignore the WaitForSeconds. This is my code in C#:
using UnityEngine;
using System.Collections;
public class openingC : MonoBehaviour
{
void Start()
{
executeWait(5);
Application.LoadLevel(1);
}
void executeWait(float aux)
{
StartCoroutine(Wait(aux));
}
IEnumerator Wait(float seconds)
{
yield return new WaitForSeconds(seconds);
}
}
Can someone explain to me why it's not working? Thanks for your time.
public class openingC : MonoBehaviour
{
void Start()
{
executeWait(5);
Application.LoadLevel(1);
}
void executeWait(float aux)
{
StartCoroutine(Wait(aux));
}
IEnumerator Wait(float seconds)
{
yield return new WaitForSeconds(seconds);
}
}
First, the Start method runs, executeWait is called, the program jumps to the method. It finds the coroutine and starts running it until a yield is found or the end of the method. Yield returns to the program, the pointer goes back up to executeWait and finishes the method. The pointer goes back up to Start and calls for Application.LoadLevel.
You want to hang the LoadLevel call.
public class openingC : MonoBehaviour
{
void Start()
{
StartCoroutine(Wait(5));
}
//You don't need executeWait
IEnumerator Wait(float seconds)
{
yield return new WaitForSeconds(seconds);
Application.LoadLevel(1);
}
}
Try this:
Thread.Sleep(500); //500 millisecond waiting...
Reference
This should also be okay.
IEnumerator Start()
{
yield return new WaitForSeconds(4);
Application.LoadLevel (1);
}

Categories

Resources