6

How can you pass a Monobehaviour inside an instance of a non Monobehaviour class? I found this link where TonyLi mentions that you can pass a Monobehaviour to start and stop coroutines inside a instance of a class, but he does not show how you can do that. He does this theEvent.StartEvent(myMonoBehaviour); but he does not show where he gets myMonobehaviour from. I looked around on the internet but I cannot seem to find how.

  • Edit

Here is what I am trying to do. I want to run a coroutine inside an instance of a class. I also want to be able to stop the coroutine inside the instance of the class. I want to do it this way so that I don't have any objects in my scene that have large managers and also so that I can reuse the code for any object that I want to pingpong in this way. The code moves a Gameobject in one direction then takes a break and moves it in the other direction and takes a break again etc. But I cannot start the coroutine from outside the class.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

[RequireComponent (typeof(Image))]
public class SpecialBar : MonoBehaviour {

    public float rangeX;
    public float breakTime;
    public float step;
    float startProgress = 0.5f;
    PingPongGameObject pingPonger;

    Color[] teamColors = new Color[]{new Color(255,136,0),new Color(0,170,255)};

    void Start()
    {

        for(int i = 0; i < teamColors.Length; ++i)
        {
            teamColors[i] = StaticFunctions.NormalizeColor (teamColors[i]);
        }

        pingPonger = new PingPongGameObject (gameObject.transform.position,
            new Vector3(rangeX,0.0f,0.0f),
            gameObject,
            startProgress,
            breakTime,
            step
            );
    }
}

The second class is where my coroutine is in.

public class PingPongGameObject
{
    float step;
    Vector3 center;
    Vector3 range;
    GameObject ball;
    float progress;
    float breakTime;
    Vector3 endPos;
    Vector3 oppositePosition;


    public PingPongGameObject(Vector3 _center, Vector3 _range, GameObject _ball, float _startProgress, float _breakTime, float _step)
    {
        center = _center;
        range = _range;
        ball = _ball;
        progress = _startProgress;
        breakTime = _breakTime;
        step = _step;
        endPos = center - range;
        oppositePosition = center + range;
        // This is where I want to start the coroutine
    }

    public IEnumerator PingPong()
    {


        while (progress < 1) {
            progress += Time.deltaTime * step;
            Vector3 newPos = Vector3.Lerp (oppositePosition, endPos, progress);
            ball.transform.position = newPos;
            yield return null;
        }
        Vector3 temp = endPos;
        endPos = oppositePosition;
        oppositePosition = temp;
        progress = 0;
        yield return new WaitForSeconds (breakTime);
        yield return null;
    }

    public float Step
    {
        set{step = value;}
    }

    public void StopCoroutine()
    {
        // This is where I want to stop the coroutine
    }
}
Programmer
  • 121,791
  • 22
  • 236
  • 328
anonymous-dev
  • 2,897
  • 9
  • 48
  • 112
  • Yes, I will put an explenation in my question just one moment. – anonymous-dev Nov 09 '16 at 14:19
  • I reworked the question. – anonymous-dev Nov 09 '16 at 14:27
  • Check the answer I left. You can use the `this` keyword. – Programmer Nov 09 '16 at 14:28
  • Hi Mike - ignore my earlier comment saying you need a prefab. Actually, all you are talking about is *using components!!!!* It's that simple. – Fattie Nov 09 '16 at 14:47
  • No, OP want's to use `IEnumerator/Coroutine` in a class that does not derive from `MonoBehaviour`. Yes he can do but but then **cannot** be able to use the `StartCoroutine` and `StopCoroutine` function and is asking for a way to pass reference of `MonoBehaviour` to the other class so he can be able to do that. You can make a script without making it a `MonoBehaviour`. Sometimes, you have to. Ofcourse, he can make it `MonoBehaviour` like you said in your comments and answer but that's not what the question is about. The question is about passing `MonoBehaviour` reference. – Programmer Nov 09 '16 at 14:47
  • I appreciate that he has asked (literally) "how to call back to a game object from an abstract c# class I have instantiated". It's true that that is technically possible but it would be *incredibly wrong!* to do that in Unity - ie, to not understand that the absolutely central idea of Unity - the whole basic process of making Unity programs! - is to write behaviors for things like pingpong, and attach them to objects! – Fattie Nov 09 '16 at 14:55
  • Just BTW the "fancy-ass" way to do pingpongs and the like is to use **tweeng** http://stackoverflow.com/a/37228628/294884 .... it's the crack cocaine of Unity development. Since I feel you want to do it "in code" as it were, that's a good approach. – Fattie Nov 09 '16 at 15:28
  • 1. write a "PingPing" behavior. 2. attach it to the GameObject 3. when you want to ping pong, ***just turn it on or off*** – Fattie Jan 25 '17 at 15:38

1 Answers1

17

TonyLi mentions that you can pass a Monobehaviour to start and stop coroutines inside a instance of a class, but he does not show how you can do that. He does this

You are can do that with the this keyword. The this keyword will get the current instance of MonoBehaviour.

In this example there's a tree, which happens to have a component MonoScript:

enter image description here

That particular instance of MonoScript can if it wants (since it's a c# program) instantiate a general c# class, NonMonoScript:

Class to pass MonoBehaviour from:

public class MonoScript : MonoBehaviour
{
    void Start()
    {
        NonMonoScript  nonMonoScript = new NonMonoScript();
        //Pass MonoBehaviour to non MonoBehaviour class
        nonMonoScript.monoParser(this);
    }
}

Class that receives pass MonoBehaviour instance:

public class NonMonoScript 
{
    public void monoParser(MonoBehaviour mono)
    {
        //We can now use StartCoroutine from MonoBehaviour in a non MonoBehaviour script
        mono.StartCoroutine(testFunction());

       //And also use StopCoroutine function
        mono.StopCoroutine(testFunction());
    }

    IEnumerator testFunction()
    {
        yield return new WaitForSeconds(3f);
        Debug.Log("Test!");
    }
}

You can also store the mono reference from the monoParser function in a local variable to be re-used.

Programmer
  • 121,791
  • 22
  • 236
  • 328
  • 1
    Thanks guys! Programmer this was exactly what I was looking for. Joe Blow I realize that this may not be the smartest way of dealing with the problem I will look in to it and into your explenation. Since this was the awnser I was looking for I will take this for an awnser. – anonymous-dev Nov 09 '16 at 14:50
  • @MikeOttink You are welcome. I once ran into this problem of not being able to use the `StartCoroutine` and `StopCoroutine` function. This is how I solved it. Sometimes, you do not need to derive your script from `MonoBehaviour`. Other times you do. It depends on your situation but this answer is only to show how to pass the `MonoBehaviour` to another script like you asked. Joe's answer should also work. Happy coding! – Programmer Nov 09 '16 at 15:03
  • Passing the monobehaviour in is genius since often it will be called from a monobehaviour. Great for static classes that you want to use project-wide! – mberna Feb 10 '22 at 04:51