Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Invoke or just call a function as commonly we do ?

Discussion in 'Scripting' started by U7Games, Apr 8, 2014.

  1. U7Games

    U7Games

    Joined:
    May 21, 2011
    Posts:
    943
    Hi all

    What is the difference between:

    Code (csharp):
    1.  
    2. function Start()
    3. {
    4.   Invoke(OpenDoor, 1);
    5. }
    6.  
    7. function OpenDoor ()
    8. {
    9.   Debug.Log("Make something");
    10. }
    11.  
    12.  
    and this:

    Code (csharp):
    1.  
    2. function Start ()
    3. {
    4.   OpenDoor();
    5. }
    6.  
    7. function OpenDoor ()
    8. {
    9.  Debug.Log("Make something");
    10. }
    11.  
    Maybe the second one keeps on memory and the first one destroyes itself ?...
    (My question is a performance thing)..

    Thank you.
     
    Last edited: Apr 8, 2014
  2. bigmisterb

    bigmisterb

    Joined:
    Nov 6, 2010
    Posts:
    4,221
    void Invoke(string methodName, float time);
    Description

    Invokes the method methodName in time seconds.

    simply calling it calls it now.

    Other than the timer and small stuff, there should be no difference in processor usage.
     
  3. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Well, there is the overhead of invoking a method by reflection, and by name. Frankly, Invoke should not take a string, but a delegate.
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,594
    Agreed, I wrote my own invoke system that does take a delegate instead.
     
  5. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    You should share that. :p
     
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,594
    I can, but it's quite a bit of code, because it hooks into my coroutine system I wrote as well (the coroutine system allows for custom yield statements and canceling of the coroutine).

    All the Invoke system does is operate a predefined coroutine that waits a certain amount of time. And it tracks the coroutine so that if you pass in the delegate to a 'CancelInvoke' method it cancels that custom coroutine.

    Before I wrote my custom coroutine system that wraps around the existing coroutine, I used the Invoke system to do it. So it still had to call by string internally, and it served to just allow passing in a delegate (it was nice for anonymous methods). I did it by merely having a private method with a weird name, stacking the delegates in a list, and calling them as that Invoke came back. I could cancel it by removing it from the list. I prefer this newer coroutine model.

    So get ready to scroll.

    RadicalCoroutine:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5.  
    6. namespace com.spacepuppy
    7. {
    8.     public class RadicalCoroutine : IRadicalYieldInstruction, System.Collections.IEnumerator
    9.     {
    10.  
    11.         #region Fields
    12.  
    13.         private Coroutine _coroutine;
    14.  
    15.         private System.Collections.IEnumerator _routine;
    16.         private object _current;
    17.         private DerivativeOperation _derivative;
    18.  
    19.         private bool _cancelled = false;
    20.  
    21.         #endregion
    22.  
    23.         #region CONSTRUCTOR
    24.  
    25.         private RadicalCoroutine(System.Collections.IEnumerator routine)
    26.         {
    27.             _routine = routine;
    28.         }
    29.  
    30.         private void SetOwner(Coroutine co)
    31.         {
    32.             _coroutine = co;
    33.         }
    34.  
    35.         #endregion
    36.  
    37.         #region Properties
    38.  
    39.         /// <summary>
    40.         /// A refernence to the routine that is operating this RadicalCoroutine.
    41.         /// This can be used for yielding this RadicalCoroutine in the midst of
    42.         /// a standard coroutine.
    43.         /// </summary>
    44.         public Coroutine Coroutine { get { return _coroutine; } }
    45.  
    46.         public bool Cancelled { get { return _cancelled; } }
    47.  
    48.         #endregion
    49.  
    50.         #region Methods
    51.  
    52.         public void Cancel()
    53.         {
    54.             _cancelled = true;
    55.         }
    56.  
    57.         public void Reset()
    58.         {
    59.             _current = null;
    60.             _derivative = null;
    61.             _cancelled = false;
    62.             _routine.Reset();
    63.         }
    64.  
    65.         private bool MoveNext()
    66.         {
    67.             _current = null;
    68.  
    69.             if (_cancelled)
    70.             {
    71.                 _derivative = null;
    72.                 return false;
    73.             }
    74.  
    75.             int derivativeResult = -1;
    76.  
    77.             derivativeResult = this.OperateDerivative();
    78.             if (derivativeResult >= 0)
    79.             {
    80.                 return (derivativeResult > 0);
    81.             }
    82.  
    83.             while (_routine.MoveNext())
    84.             {
    85.                 var obj = _routine.Current;
    86.  
    87.                 if (obj is IRadicalYieldInstruction)
    88.                 {
    89.                     _derivative = new DerivativeOperation(obj as IRadicalYieldInstruction);
    90.                     derivativeResult = this.OperateDerivative();
    91.                     if (derivativeResult >= 0)
    92.                     {
    93.                         return (derivativeResult > 0);
    94.                     }
    95.                 }
    96.                 else if (obj is System.Collections.IEnumerable)
    97.                 {
    98.                     _derivative = new DerivativeOperation(new RadicalCoroutine((obj as System.Collections.IEnumerable).GetEnumerator()));
    99.                     derivativeResult = this.OperateDerivative();
    100.                     if (derivativeResult >= 0)
    101.                     {
    102.                         return (derivativeResult > 0);
    103.                     }
    104.                 }
    105.                 else if (obj is System.Collections.IEnumerator)
    106.                 {
    107.                     _derivative = new DerivativeOperation(new RadicalCoroutine(obj as System.Collections.IEnumerator));
    108.                     derivativeResult = this.OperateDerivative();
    109.                     if (derivativeResult >= 0)
    110.                     {
    111.                         return (derivativeResult > 0);
    112.                     }
    113.                 }
    114.                 else
    115.                 {
    116.                     _current = obj;
    117.                     return true;
    118.                 }
    119.             }
    120.  
    121.             _current = null;
    122.             _derivative = null;
    123.             return false;
    124.         }
    125.  
    126.         /// <summary>
    127.         /// 1 - continue blocking
    128.         /// 0 - stop blocking
    129.         /// -1 - loop past
    130.         /// </summary>
    131.         /// <returns></returns>
    132.         private int OperateDerivative()
    133.         {
    134.             if (_derivative == null) return -1;
    135.  
    136.             if (_derivative.ContinueBlocking(this))
    137.             {
    138.                 if (_cancelled)
    139.                 {
    140.                     _current = null;
    141.                     return 0;
    142.                 }
    143.                 _current = _derivative.CurrentYieldObject;
    144.                 return 1;
    145.             }
    146.             else
    147.             {
    148.                 _derivative = null;
    149.                 if (_cancelled)
    150.                 {
    151.                     _current = null;
    152.                     return 0;
    153.                 }
    154.                 _current = null;
    155.                 return -1;
    156.             }
    157.         }
    158.  
    159.         #endregion
    160.  
    161.         #region IRadicalYieldInstruction Interface
    162.  
    163.         object IRadicalYieldInstruction.CurrentYieldObject
    164.         {
    165.             get { return _current; }
    166.         }
    167.  
    168.         bool IRadicalYieldInstruction.ContinueBlocking(RadicalCoroutine routine)
    169.         {
    170.             return this.MoveNext();
    171.         }
    172.  
    173.         #endregion
    174.  
    175.         #region IEnumerator Interface
    176.  
    177.         object System.Collections.IEnumerator.Current
    178.         {
    179.             get { return _current; }
    180.         }
    181.  
    182.         bool System.Collections.IEnumerator.MoveNext()
    183.         {
    184.             return this.MoveNext();
    185.         }
    186.  
    187.         void System.Collections.IEnumerator.Reset()
    188.         {
    189.             this.Reset();
    190.         }
    191.  
    192.         #endregion
    193.  
    194.         #region Factory Methods
    195.  
    196.         public static RadicalCoroutine StartCoroutine(MonoBehaviour behaviour, System.Collections.IEnumerator routine)
    197.         {
    198.             if (behaviour == null) throw new System.ArgumentNullException("behaviour");
    199.             if (routine == null) throw new System.ArgumentNullException("routine");
    200.  
    201.             var co = new RadicalCoroutine(routine);
    202.             co.SetOwner(behaviour.StartCoroutine(co));
    203.             return co;
    204.         }
    205.  
    206.         #endregion
    207.  
    208.         #region Special Types
    209.  
    210.         private class DerivativeOperation : IRadicalYieldInstruction
    211.         {
    212.             private IRadicalYieldInstruction _instruction;
    213.             private DerivativeOperation _derivative;
    214.  
    215.             public DerivativeOperation(IRadicalYieldInstruction instruction)
    216.             {
    217.                 if (instruction == null) throw new System.ArgumentNullException("instruction");
    218.                 _instruction = instruction;
    219.             }
    220.  
    221.             public object CurrentYieldObject
    222.             {
    223.                 get { return (_derivative != null) ? _derivative.CurrentYieldObject : _instruction.CurrentYieldObject; }
    224.             }
    225.  
    226.             public bool ContinueBlocking(RadicalCoroutine routine)
    227.             {
    228.                 if (_derivative != null)
    229.                 {
    230.                     if (_derivative.ContinueBlocking(routine))
    231.                     {
    232.                         return true;
    233.                     }
    234.                     else
    235.                     {
    236.                         _derivative = null;
    237.                     }
    238.                 }
    239.  
    240.                 while (_instruction.ContinueBlocking(routine))
    241.                 {
    242.                     if (_instruction.CurrentYieldObject is IRadicalYieldInstruction)
    243.                     {
    244.                         _derivative = new DerivativeOperation(_instruction.CurrentYieldObject as IRadicalYieldInstruction);
    245.                         if (!_derivative.ContinueBlocking(routine))
    246.                         {
    247.                             _derivative = null;
    248.                         }
    249.                         else
    250.                         {
    251.                             return true;
    252.                         }
    253.                     }
    254.                     else if (_instruction.CurrentYieldObject is System.Collections.IEnumerable)
    255.                     {
    256.                         _derivative = new DerivativeOperation(new RadicalCoroutine((_instruction.CurrentYieldObject as System.Collections.IEnumerable).GetEnumerator()));
    257.                         if (!_derivative.ContinueBlocking(routine))
    258.                         {
    259.                             _derivative = null;
    260.                         }
    261.                         else
    262.                         {
    263.                             return true;
    264.                         }
    265.                     }
    266.                     else if (_instruction.CurrentYieldObject is System.Collections.IEnumerator)
    267.                     {
    268.                         _derivative = new DerivativeOperation(new RadicalCoroutine(_instruction.CurrentYieldObject as System.Collections.IEnumerator));
    269.                         if (!_derivative.ContinueBlocking(routine))
    270.                         {
    271.                             _derivative = null;
    272.                         }
    273.                         else
    274.                         {
    275.                             return true;
    276.                         }
    277.                     }
    278.                     else
    279.                     {
    280.                         return true;
    281.                     }
    282.                 }
    283.  
    284.                 return false;
    285.             }
    286.         }
    287.  
    288.         #endregion
    289.  
    290.     }
    291.  
    292. }
    293.  
    IRadicalYieldInstruction (implement this to make a custom yield statement):
    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. namespace com.spacepuppy
    5. {
    6.     public interface IRadicalYieldInstruction
    7.     {
    8.         object CurrentYieldObject { get; }
    9.  
    10.         bool ContinueBlocking(RadicalCoroutine routine);
    11.     }
    12. }
    13.  
    SPComponent (where Invoke is implemented, all my component inherit from this):
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4.  
    5. namespace com.spacepuppy
    6. {
    7.  
    8.     /// <summary>
    9.     /// Base contract for any interface contract that should be considered a Component
    10.     /// </summary>
    11.     public interface IComponent
    12.     {
    13.         Component component { get; }
    14.         GameObject gameObject { get; }
    15.         Transform transform { get; }
    16.     }
    17.  
    18.     public abstract class SPComponent : MonoBehaviour, IComponent
    19.     {
    20.  
    21.         #region Fields
    22.  
    23.         private List<InvokeInfo> _invokeList;
    24.  
    25.         #endregion
    26.  
    27.         #region CONSTRUCTOR
    28.  
    29.         protected virtual void Awake()
    30.         {
    31.             if (com.spacepuppy.Utils.Assertions.AssertRequireLikeComponentAttrib(this))
    32.             {
    33.                 Object.Destroy(this);
    34.             }
    35.         }
    36.  
    37.         protected virtual void OnDestroy()
    38.         {
    39.             if (_invokeList != null)
    40.             {
    41.                 foreach (var info in _invokeList)
    42.                 {
    43.                     info.Cancel();
    44.                 }
    45.                 _invokeList = null;
    46.             }
    47.         }
    48.  
    49.         protected virtual void OnEnable()
    50.         {
    51.             this.SendMessage(SPConstants.MSG_ONSPCOMPONENTENABLED, this, SendMessageOptions.DontRequireReceiver);
    52.         }
    53.  
    54.         protected virtual void OnDisable()
    55.         {
    56.             this.SendMessage(SPConstants.MSG_ONSPCOMPONENTDISABLED, this, SendMessageOptions.DontRequireReceiver);
    57.         }
    58.  
    59.         #endregion
    60.  
    61.         #region Invoke
    62.  
    63.         public void Invoke(System.Delegate method, float time, params object[] args)
    64.         {
    65.             if (method == null) throw new System.ArgumentNullException("method");
    66.             if (time <= 0f)
    67.             {
    68.                 method.DynamicInvoke(args);
    69.                 return;
    70.             }
    71.  
    72.             if (_invokeList == null)
    73.             {
    74.                 _invokeList = new List<InvokeInfo>();
    75.             }
    76.  
    77.             var info = new InvokeInfo(method, time, args);
    78.             var r = RadicalCoroutine.StartCoroutine(this, InvokeCoroutine(info));
    79.             info.Radical = r;
    80.             _invokeList.Add(info);
    81.         }
    82.  
    83.         private System.Collections.IEnumerator InvokeCoroutine(InvokeInfo info)
    84.         {
    85.             yield return new WaitForSeconds(info.WaitTime);
    86.             info.Invoke();
    87.             if(_invokeList != null) _invokeList.Remove(info);
    88.         }
    89.  
    90.         public new void CancelInvoke()
    91.         {
    92.             base.CancelInvoke();
    93.             if (_invokeList != null)
    94.             {
    95.                 foreach (var info in _invokeList)
    96.                 {
    97.                     info.Cancel();
    98.                 }
    99.                 _invokeList = null;
    100.             }
    101.         }
    102.  
    103.         public void CancelInvoke(System.Delegate method)
    104.         {
    105.             if (_invokeList == null) return;
    106.  
    107.             foreach (var info in _invokeList.ToArray())
    108.             {
    109.                 if (info.Method == method)
    110.                 {
    111.                     info.Cancel();
    112.                     _invokeList.Remove(info);
    113.                 }
    114.             }
    115.         }
    116.  
    117.         private class InvokeInfo
    118.         {
    119.             public float WaitTime;
    120.             public System.Delegate Method;
    121.             public object[] Args;
    122.             public RadicalCoroutine Radical;
    123.  
    124.             public InvokeInfo(System.Delegate m, float t, object[] a)
    125.             {
    126.                 WaitTime = t;
    127.                 Method = m;
    128.                 Args = a;
    129.                 Radical = null;
    130.             }
    131.  
    132.             public void Invoke()
    133.             {
    134.                 if (Method != null) Method.DynamicInvoke(Args);
    135.             }
    136.  
    137.             public void Cancel()
    138.             {
    139.                 if(Radical != null) Radical.Cancel();
    140.                 Method = null;
    141.                 Args = null;
    142.             }
    143.         }
    144.  
    145.         #endregion
    146.  
    147.         #region Coroutine
    148.  
    149.         public Coroutine StartCoroutine(System.Collections.IEnumerable enumerable)
    150.         {
    151.             return this.StartCoroutine(enumerable.GetEnumerator());
    152.         }
    153.  
    154.         public Coroutine StartCoroutine(System.Delegate method, params object[] args)
    155.         {
    156.             if (method == null) throw new System.ArgumentNullException("method");
    157.  
    158.             System.Collections.IEnumerator e;
    159.             if (com.spacepuppy.Utils.ObjUtil.IsType(method.Method.ReturnType, typeof(System.Collections.IEnumerable)))
    160.             {
    161.                 e = (method.DynamicInvoke(args) as System.Collections.IEnumerable).GetEnumerator();
    162.             }
    163.             else if (com.spacepuppy.Utils.ObjUtil.IsType(method.Method.ReturnType, typeof(System.Collections.IEnumerator)))
    164.             {
    165.                 e = (method.DynamicInvoke(args) as System.Collections.IEnumerator);
    166.             }
    167.             else
    168.             {
    169.                 throw new System.ArgumentException("Delegate must have a return type of IEnumerable or IEnumerator.", "method");
    170.             }
    171.  
    172.             return this.StartCoroutine(e);
    173.         }
    174.  
    175.  
    176.  
    177.         public RadicalCoroutine StartRadicalCoroutine(System.Collections.IEnumerator e)
    178.         {
    179.             return RadicalCoroutine.StartCoroutine(this, e);
    180.         }
    181.  
    182.         public RadicalCoroutine StartRadicalCoroutine(System.Collections.IEnumerable e)
    183.         {
    184.             return RadicalCoroutine.StartCoroutine(this, e.GetEnumerator());
    185.         }
    186.  
    187.         public RadicalCoroutine StartRadicalCoroutine(System.Delegate method, params object[] args)
    188.         {
    189.             if (method == null) throw new System.ArgumentNullException("method");
    190.  
    191.             System.Collections.IEnumerator e;
    192.             if (com.spacepuppy.Utils.ObjUtil.IsType(method.Method.ReturnType, typeof(System.Collections.IEnumerable)))
    193.             {
    194.                 e = (method.DynamicInvoke(args) as System.Collections.IEnumerable).GetEnumerator();
    195.             }
    196.             else if (com.spacepuppy.Utils.ObjUtil.IsType(method.Method.ReturnType, typeof(System.Collections.IEnumerator)))
    197.             {
    198.                 e = (method.DynamicInvoke(args) as System.Collections.IEnumerator);
    199.             }
    200.             else
    201.             {
    202.                 throw new System.ArgumentException("Delegate must have a return type of IEnumerable or IEnumerator.", "method");
    203.             }
    204.  
    205.             return RadicalCoroutine.StartCoroutine(this, e);
    206.         }
    207.  
    208.         #endregion
    209.  
    210.         #region IComponent Interface
    211.  
    212.         Component IComponent.component
    213.         {
    214.             get { return this; }
    215.         }
    216.  
    217.         //implemented implicitly
    218.         /*
    219.         GameObject IComponent.gameObject { get { return this.gameObject; } }
    220.         Transform IComponent.transform { get { return this.transform; } }
    221.         */
    222.  
    223.         #endregion
    224.  
    225.     }
    226.  
    227. }
    228.  
    I didn't look through the code, but it probably references some other classes that I didn't link here. Probably some utility classes, or custom collections. It's all part of my SP (space puppy) framework that I've been developing for my personal use with unity.


    Also, I've considered breaking the StartCoroutine methods out as extension methods so you don't necessarily have to inherit SPComponent for them to work.

    Invoke though, since it stores a reference to the list of invoke calls, needs to be here. Otherewise I'd have to write a manager for it that tracked all the components and when they died and what not. I wasn't a big fan of that, and went this way instead.

    Lastly, I may change to use some generics as well. Haven't really considered how though. But it'd be nice to get compile time checks on the calls.
     
    Last edited: Apr 8, 2014