I was faced with a need to send an Event to a PlayMaker FSM from a non-PlayMaker Script. So I created something generic that you can drop into a GO (via the inspector). PlaymakerProxy is simple to use if you just need to send a single event to a FSM. But since you can only have one instance of this attached to a GO, I also wrote PlaymakerProxyObjPass, which uses the object-passing capability of the Unity messaging system to pass a simple dictionary with the FSM name and the event name. The comments and example embedded in this second script should show how to use it.
/*
* PlaymakerProxy.cs
*
* author: Jeff Sasmor. jeff@sasmor.com
* Copyright 2011 Jeff Sasmor
*
* this script can be used to transition from a message sent by a script to a PlayMaker FSM
* that's attached to a GameObject. It gets all the FSMs attached to this GameObject
* and sends the named event to the named FSM (defaults to FSM).
*
* Use case: you have a script that wants to send an event to a PlayMaker FSM attached to
* the same GO or to another one.
*
* Add this script to the target GO which has the target FSM.
* Set the target to the correct destination. If not set it looks for an FSM on the same GO
* Change FSMname if necc
* set the correct FSM name
*
* Set your messaging fcn to send a message to the PMProxy method in the target GO.
* The script CANNOT be sending an object along with the message.
*
* The PMProxy method will send an event to the FSM.
*
*
* Shortcoming: only one PMProxy can be attached to a GO.
* see PlaymakerProxyObjPass.cs for more info and an example.
*/
using UnityEngine;
//using System.Collections;
using HutongGames.PlayMaker;
public class PlaymakerProxy : MonoBehaviour {
public GameObject target = null; //if not changed, code uses 'this' i.e. the GO the script is attached to
public string FSMname = "FSM";
public string eventName = "A Global Event Name";
public bool debug = false;
//find the fsm and optionally set the object then invoke the FSM Event
void PMProxy() {
PlayMakerFSM the_fsm; //the FSM we want to send an event to
PlayMakerFSM[] components; //all the FSMs attached to the GO are stored here
if( !target )
target = this.gameObject;
components = target.GetComponents<PlayMakerFSM>(); //Get all FSMs on this game object
the_fsm = null; //we haven't found one yet
//loop thru all the FSMs and find one with the correct name
foreach(PlayMakerFSM fsm in components) {
if (fsm.FsmName.CompareTo(FSMname) == 0) {
the_fsm = fsm;
break;
}
}
//if we found one
if (the_fsm != null)
the_fsm.Fsm.Event(eventName); //send the Event to the FSM
else //Foo-bar
Debug.Log( "GameObject: " + target.name + " doesn't have named FsmComponent: " + FSMname, this);
if (debug)
Debug.Log("Proxy Activated");
}
}
and
/*
* PlaymakerProxyObjPass.cs
*
* author: Jeff Sasmor. jeff@sasmor.com
* Copyright 2011 Jeff Sasmor
*
* this script can be used to transition from a message sent by a script to a PlayMaker FSM
* that's attached to a GameObject. It gets all the FSMs attached to this GameObject
* and sends the named event to the named FSM (defaults to FSM).
*
* Use case: you have a script that wants to send an event to a PlayMaker FSM attached to
* the same GO or to another one and you want to be able to steer to a particular FSM/event.
*
* Add this script to the target GO which has the target FSM.
* Set the target to the correct destination. If not set it looks for an FSM on the same GO
* Change FSMname if necc
* set the correct GLOBAL event name
*
* Set your messaging fcn to send a message to the PMProxy method in the target GO.
* The fcn must send along an object.
* The object sent is a dictionary (System.Collections.Generic.Dictionary) with K,V:
* {fsm: fsmname, event: eventname}
*
* for example:
* put this in some script that you want to have "call" an FSM event.
* ---> "this.gameObject" may or may not be appropriate.
*
* using System.Collections.Specialized;
*
* ListDictionary Dict = new ListDictionary();
*
* Dict.Add("fsm","FSM"); //the normal name for an FSM
* Dict.Add("event","globEvName"); //the global event sent to the fsm
*
* this.gameObject.SendMessage("PMProxyObjPass",Dict,SendMessageOptions.DontRequireReceiver);
*
*
* The PMProxy method will send an event to the FSM.
* You might want to change DontRequireReceiver to RequireReciever to throw a message into the
* debug log if stuff doesn't seem to work.
*
* Note that the event HAS to be a GLOBAL event.
*
* Shortcoming: only one PMProxy can be attached to a GO.
*/
using UnityEngine;
using System.Collections.Specialized;
using HutongGames.PlayMaker;
public class PlaymakerProxyObjPass : MonoBehaviour {
public GameObject target = null; //if not changed, code uses 'this' i.e. the GO the script is attached to
//note: FSM name and Event must be passed in via the message. See above
private string FSMname = "FSM";
private string eventName = "xxx";
//find the fsm and optionally set the object then invoke the FSM Event
void PMProxyObjPass(ListDictionary Dict) {
PlayMakerFSM the_fsm; //the FSM we want to send an event to
PlayMakerFSM[] components; //all the FSMs attached to the GO are stored here
//Are the correct keys present?
if (Dict.Contains("fsm")==false || Dict.Contains("event")==false){
Debug.Log( "GameObject: " + target.name + " input dictionary missing keys when msg sent to PMProxyObjPass", this);
return;
}
//OK then :-)
FSMname = Dict["fsm"].ToString();
eventName = Dict["event"].ToString();
if( !target )
target = this.gameObject;
components = target.GetComponents<PlayMakerFSM>(); //Get all FSMs on this game object
the_fsm = null; //we haven't found one yet
//loop thru all the FSMs and find one with the correct name
foreach(PlayMakerFSM fsm in components) {
if (fsm.FsmName.CompareTo(FSMname) == 0) {
the_fsm = fsm;
break;
}
}
//if we found one
if (the_fsm != null)
the_fsm.Fsm.Event(eventName); //send the Event to the FSM
else //Foo-bar
Debug.Log( "GameObject: " + target.name + " doesn't have named FsmComponent: " + FSMname, this);
}
}