I am creating an RTS game and want to assign commands to my unit, but want to avoid having a currentCommand enum and doing just a switch on that in update, oncollision, onDestroy, etc.
I chose to use delegates and assign methods to them from the command source file to implement this.
I found a very nice article here:
I have my delegates defined in my unit controller class, and I have my configureState method that takes a RTSCommand object (child command classes override methods that get assigned to the delegates) and it will assign methods form the input to the delegates with reflection.
My current problem is, how to pass an RTSCommand to this method when I call another method that gets passed in an enum of a command to give. Show I just switch on the enum and call the appropriate method with the RTSCommand reference that matches with the enum value?
Is there any better way to accomplish this?
(I also want efficiency as this is for mobile as well (ipad3 or later for ios) )
Here is part of my code right now:
private RTSCommand currentCommand;
public Action DoUpdate = DoNothing;
public Action DoLateUpdate = DoNothing;
public Action DoFixedUpdate = DoNothing;
public Action<Collider> DoOnTriggerEnter = DoNothingCollider;
public Action<Collider> DoOnTriggerStay = DoNothingCollider;
public Action<Collider> DoOnTriggerExit = DoNothingCollider;
public Action<Collision> DoOnCollisionEnter = DoNothingCollision;
public Action<Collision> DoOnCollisionStay = DoNothingCollision;
public Action<Collision> DoOnCollisionExit = DoNothingCollision;
public Action DoOnMouseEnter = DoNothing;
public Action DoOnMouseUp = DoNothing;
public Action DoOnMouseDown = DoNothing;
public Action DoOnMouseOver = DoNothing;
public Action DoOnMouseExit = DoNothing;
public Action DoOnMouseDrag = DoNothing;
public Action DoOnGUI = DoNothing;
public IEnumerator DoNothingIE() {yield return null;}
public delegate IEnumerator ExitState(IEnumerator i);
ExitState exitState = DoNothingCoroutine;
public delegate IEnumerator EnterState(IEnumerator e);
EnterState enterState = DoNothingCoroutine;
public static void DoNothing(){}
public static void DoNothingCollider(Collider c){}
public static void DoNothingCollision(Collision c){}
public static IEnumerator DoNothingCoroutine(IEnumerator i){return i;}
//change this to include passing in a class of the command to fetch methods from
void ConfigureCurrentState(RTSCommand c)
{
//If we have an exit state, then start it as a
//coroutine
if(exitState != null)
{
StartCoroutine(exitState( DoNothingIE()) );
}
//Now we need to configure all of the methods
DoUpdate = ConfigureDelegate<Action>(c,"Update", DoNothing);
DoOnGUI = ConfigureDelegate<Action>(c,"OnGUI", DoNothing);
DoLateUpdate = ConfigureDelegate<Action>(c,"LateUpdate", DoNothing);
DoFixedUpdate = ConfigureDelegate<Action>(c,"FixedUpdate", DoNothing);
DoOnMouseUp = ConfigureDelegate<Action>(c,"OnMouseUp", DoNothing);
DoOnMouseDown = ConfigureDelegate<Action>(c,"OnMouseDown", DoNothing);
DoOnMouseEnter = ConfigureDelegate<Action>(c,"OnMouseEnter", DoNothing);
DoOnMouseExit = ConfigureDelegate<Action>(c,"OnMouseExit", DoNothing);
DoOnMouseDrag = ConfigureDelegate<Action>(c,"OnMouseDrag", DoNothing);
DoOnMouseOver = ConfigureDelegate<Action>(c,"OnMouseOver", DoNothing);
DoOnTriggerEnter = ConfigureDelegate<Action<Collider>>(c,"OnTriggerEnter", DoNothingCollider);
DoOnTriggerExit = ConfigureDelegate<Action<Collider>>(c,"OnTriggerExir", DoNothingCollider);
DoOnTriggerStay = ConfigureDelegate<Action<Collider>>(c,"OnTriggerEnter", DoNothingCollider);
DoOnCollisionEnter = ConfigureDelegate<Action<Collision>>(c,"OnCollisionEnter", DoNothingCollision);
DoOnCollisionExit = ConfigureDelegate<Action<Collision>>(c,"OnCollisionExit", DoNothingCollision);
DoOnCollisionStay = ConfigureDelegate<Action<Collision>>(c,"OnCollisionStay", DoNothingCollision);
enterState = ConfigureDelegate<EnterState>(c,"EnterState", DoNothingCoroutine);
exitState = ConfigureDelegate<ExitState>(c,"ExitState", DoNothingCoroutine);
//Optimisation, turn off GUI if we don't
//Start the current state
StartCoroutine(enterState(DoNothingIE()) );
}
//Define a generic method that returns a delegate
//Note the where clause - we need to ensure that the
//type passed in is a class and not a value type or our
//cast (As T) will not work
T ConfigureDelegate<T>(RTSCommand c, string methodRoot, T Default) where T : class
{
//Find a method called CURRENTSTATE_METHODROOT
//The method can be either public or private
var mtd = c.GetType().GetMethod(currentCommand.ToString() + "_" + methodRoot, System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod);
//If we found a method
if(mtd != null)
{
//Create a delegate of the type that this
//generic instance needs and cast it
return Delegate.CreateDelegate(typeof(T), this, mtd) as T;
}
else
{
//If we didn't find a method return the default
return Default;
}
}
public void giveCommand(Commander.Commands command, Transform targetTrans, Vector3 targetPos)
{
//verify we can rceieve the command (we can transition form current command state to new one)
//then configure the new state
if(canDoCommand(currentCommand.getCommandValue(), command) )
{
//can then do command
//find RTSCommand reference for given enum input
}
}