Pergunta

I'm trying to replicate MonoBehaviour of the Unity 3D engine. I'm using monodevelop on Linux, and most testing will be done in Windows Unity 3D engine editor.

more about MonoBehaviour.Update can be read here

I want to invoke the Update method on all types which inherit from MonoBehavior every 10ms.

this is how I'm doing with Start

using System;
using System.Reflection;
public class MonoBehaviour{

    public static void Main (){
        Type[] types = Assembly.GetExecutingAssembly().GetTypes();

        foreach (Type type in types) {
            if (type.IsSubclassOf(typeof(MonoBehaviour))){

                System.Reflection.MethodInfo mInfo = type.GetMethod ("Start", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null); // it is run 2 times
                if (mInfo != null) {
                    ConstructorInfo ctor = type.GetConstructor (new Type[] { });
                    if (ctor != null) {
                        object inst = ctor.Invoke (new object[] { });
                        mInfo.Invoke (inst, new object[] { });
                    }
                }
            }
        }
    }
}

class example : MonoBehaviour{
    void Start(){
        // this works perfectly
        Console.WriteLine ("HelloWorld");
    }
    void Update(){
        // I want this to be run every 10 ms
        Console.WriteLine ("HelloinUpdate");
    }
}
Foi útil?

Solução

You could do this without using reflection, it would be a bit faster (and safer):

using System;
using System.Linq;
using System.Timers;

public static class Program
{
    public static void Main()
    {
        IEnumerable<Type> assemblyTypes = typeof(MonoBehaviour).Assembly.GetTypes();

        IEnumerable<Type> behaviourTypes = assemblyTypes
            .Where(type => typeof(MonoBehaviour).IsAssignableFrom(type))
            .Where(type => !type.IsAbstract);

        List<MonoBehaviour> behaviours = behaviourTypes
            .Select(Activator.CreateInstance)
            .Cast<MonoBehaviour>()
            .ToList();

        foreach (MonoBehaviour monoBehaviour in behaviours)
        {
            monoBehaviour.Start();
        }

        var timer = new Timer(10 /* Milliseconds */);

        timer.Elapsed += (sender, eventArgs) =>
        {
            foreach (MonoBehaviour monoBehaviour in behaviours)
            {
                monoBehaviour.Update();
            }
        };

        timer.Start();

        Console.WriteLine("Press a key to stop.");
        Console.ReadKey();
    }
}

public abstract class MonoBehaviour
{
    public virtual void Start()
    {
    }

    public virtual void Update()
    {
    }

    protected static void Log(string message)
    {
        Console.WriteLine("{0} - {1}", DateTime.Now, message);
    }
}

public class Behaviour1 : MonoBehaviour
{
    public override void Start()
    {
        Log("Behaviour1 - Start");
    }

    public override void Update()
    {
        Log("Behaviour1 - Update");
    }
}

public class Behaviour2 : MonoBehaviour
{
    public override void Start()
    {
        Log("Behaviour2 - Start");
    }

    public override void Update()
    {
        Log("Behaviour2 - Update");
    }
}:

The output would be something like this (I adjusted the timer to 1000ms):

Output

Outras dicas

Basically, something like this should do the trick:

var timer = new Timer(10);
timer.Elapsed += new ElapsedEventHandler(MonoBehavior.Update);
timer.Start();

It creates a timer with 10ms then binds your method to the elapsed event and enables the timer to count down. When it reaches 0, the event is fired and the time resets.

Use Timer:

Timer t = new System.Threading.Timer(Update, this, 10, 10);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top