using System.Collections.Generic; namespace Passer { /// Easy universal way to attach script functions to events and statuses /// Event handlers are used in many Passer components like ControllerInput, /// CollisionEventHandler, TriggetEventHandler, HeadTarget and Handle to call functions /// based on events. /// /// Editing /// ======= /// An event handler can be edited by pressing on the button. /// For every event It is possible to attach multiple event Handlers. /// When an event Handler has been defined, /// a new empty button will appear below which you can use to add an additional event Handler. /// \image html EventHandlerUnselected.png /// When an event Handler has been selected, a number of fields become visible: /// \image html EventHandlerSelected.png /// /// Event Type /// ---------- /// The labels of this drop down field can be differen depending on the event, /// but in general they work as follows: /// * /ref Never: the %Target %Method is never called. /// * /ref On Start: the %Target %Method is called when the event starts. /// * /ref On End: the %Target %Method is called when the event ends. /// * /ref While Active: the %Target %Method is called while the event is active. /// * /ref While Inactive: the %Target %Method is called while the event is not active. /// * /ref On Change: the %Target %Method is called when the event starts of ends. /// * /ref Always: the %Target %Method is called independe from the event state. /// /// Target /// ------ /// The target GameObject in the scene on which the %Method is called. /// /// Method /// ------ /// The method to call on the GameObject. /// For each component on the GameObject an entry will be listed in the drop down. /// When selecting a component, the desired function can be chosen from /// the list of available functions. /// /// Method Parameter /// ---------------- /// This can be set to a constant value or to *%From %Event*. /// In the second option, the parameter value will come from the event itself. /// Like the status of the button pressed /// the GameObject which has entered the trigger collider or /// the GameObject to which the user is looking. /// /// Options /// ------- /// \image html EventHandlerOptions.png /// Depending on the parameter type additional settings can be set in the Options section. /// * Inverse: the parameter value will be inverted before it is sent to the %Method /// * Multiplication: the parameter value will be multiplied by the given value /// before it is sent to the %Method /// * Trigger Level: determines at which values the Event Start and End happen. /// In the example above, the event will end when the value drops below 0.2 /// and will start again when the value raises above 0.8. /// public abstract class EventHandler { /// /// The different types of events when the function is called /// public enum Type { Never, //!< The function is never called OnStart, //!< The function is called when the event starts OnEnd, //!< The function is called when the event ends WhileActive, //!< The function is called every frame while the event is active WhileInactive, //!< The function is called every frame while the event is not active OnChange, //!< The function is called every time the event changes Continuous //!< The functions is called every frame. } /// /// The event type for the function call /// public Type eventType = Type.Continuous; /// /// For future use :-) /// public bool eventNetworking = false; /// /// The function to call /// public FunctionCall functionCall; protected bool initialized; #region Bool Parameter protected bool _boolValue; public virtual bool boolValue { get { return _boolValue; } set { _boolValue = value; } } protected bool boolChanged = true; /// Negate the boolean state before calling event trigger public bool boolInverse = false; #endregion #region Int Paramter protected int _intValue; protected bool intChanged; #endregion #region Float Parameter protected float _floatValue; protected bool floatChanged; #endregion #region Update Value public virtual void Update() { if (functionCall.methodName != null && functionCall.methodName.Length > 21 && functionCall.methodName.Substring(0, 21) == "SetAnimatorParameter/") { UpdateAnimationParameter(); return; } if (functionCall.parameters == null || functionCall.parameters.Length == 0) UpdateVoid(); else { switch (functionCall.parameters[0].type) { case FunctionCall.ParameterType.Void: UpdateVoid(); break; case FunctionCall.ParameterType.Bool: UpdateBool(); break; case FunctionCall.ParameterType.Int: UpdateInt(); break; case FunctionCall.ParameterType.Float: UpdateFloat(); break; case FunctionCall.ParameterType.Vector3: UpdateVector3(); break; case FunctionCall.ParameterType.String: UpdateString(); break; case FunctionCall.ParameterType.GameObject: UpdateGameObject(); break; case FunctionCall.ParameterType.Rigidbody: UpdateRigidbody(); break; } } } protected void UpdateAnimationParameter() { string parameterName = functionCall.methodName.Substring(21); switch (functionCall.parameters[0].type) { case FunctionCall.ParameterType.Bool: UpdateStringBool(parameterName); break; case FunctionCall.ParameterType.Float: UpdateStringFloat(parameterName); break; case FunctionCall.ParameterType.Int: UpdateStringInt(parameterName); break; case FunctionCall.ParameterType.Void: UpdateString(parameterName); break; } } virtual protected void UpdateVoid() { if (CheckCondition(boolValue, boolChanged, boolChanged)) { functionCall.Execute(); } } virtual protected void UpdateBool() { FunctionCall.Networking networking = eventNetworking ? FunctionCall.Networking.Yes : FunctionCall.Networking.No; if (CheckCondition(boolValue, boolChanged, boolChanged)) { if (functionCall.parameters[0].fromEvent) functionCall.Execute(boolValue, networking); else functionCall.Execute(functionCall.parameters[0].boolConstant, networking); } } virtual protected void UpdateInt() { if (CheckCondition(boolValue, boolChanged, intChanged)) { functionCall.Execute(functionCall.parameters[0].intConstant); } } virtual protected void UpdateFloat() { if (CheckCondition(boolValue, boolChanged, floatChanged)) { functionCall.Execute(functionCall.parameters[0].floatConstant); } } protected virtual void UpdateString() { if (CheckCondition(boolValue, boolChanged, floatChanged)) { if (functionCall.parameters[0].fromEvent) { functionCall.Execute(_floatValue.ToString(), eventNetworking); } else functionCall.Execute(functionCall.parameters[0].stringConstant, eventNetworking); } } virtual protected void UpdateVector3() { if (CheckCondition(boolValue, boolChanged, true)) // valueChanged is not yet implemented functionCall.Execute(functionCall.parameters[0].vector3Constant); } protected virtual void UpdateGameObject() { if (CheckCondition(boolValue, boolChanged, true)) // valueChanged is not yet implemented functionCall.Execute(functionCall.parameters[0].gameObjectConstant); } protected virtual void UpdateRigidbody() { if (CheckCondition(boolValue, boolChanged, true)) // valueChanged is not yet implemented functionCall.Execute(functionCall.parameters[0].rigidbodyConstant); } protected virtual void UpdateString(string s) { if (CheckCondition(boolValue, boolChanged, boolChanged)) functionCall.Execute(s, eventNetworking); } protected virtual void UpdateStringBool(string s) { if (CheckCondition(boolValue, boolChanged, boolChanged)) { if (functionCall.parameters[0].fromEvent) functionCall.ExecuteString(s, boolValue); else functionCall.ExecuteString(s, functionCall.parameters[0].boolConstant); } } protected virtual void UpdateStringFloat(string s) { if (CheckCondition(boolValue, boolChanged, floatChanged)) { functionCall.ExecuteString(s, functionCall.parameters[0].floatConstant); } } protected virtual void UpdateStringInt(string s) { if (CheckCondition(boolValue, boolChanged, intChanged)) { functionCall.ExecuteString(s, functionCall.parameters[0].intConstant); } } #endregion protected bool CheckCondition(bool active, bool changed, bool valueChanged) { switch (eventType) { case Type.Never: return false; case Type.WhileActive: return active; case Type.WhileInactive: return !active; case Type.OnStart: return active && changed; case Type.OnEnd: return !active && changed; case Type.OnChange: return valueChanged; case Type.Continuous: default: return true; } } /// /// True when the eventHandler is dead and can be removed /// /// A function is dead when it does nothing. /// This is when the functionCall is not defined or when the target of the functionCall is empty public bool isDead { get { bool isDead = false; // This is not dead, but temporarily disabled so that it can be re-enabled //isDead |= eventType == EventHandler.Type.Never; isDead |= functionCall == null; isDead |= functionCall.targetGameObject == null; return isDead; } } public enum OverrideMode { Prepend, //!< Prepend this handler before existing handlers Append, //!< Append this handler after existing handlers Replace, //!< Replace the topmost handler with this handler } public OverrideMode overrideMode; } /// /// A list of event Handlers /// /// For each input, one or more events can be defined when the input changes. /// The type of event handler [System.Serializable] public class EventHandlers { /// /// The id of the event handler /// public int id; /// /// The label or name of the Event Handlers /// public string label; /// /// The tooltip text for the Event Handlers /// public string tooltip; /// /// The labels for the EventHandler.Type to use in the GUI /// public string[] eventTypeLabels; /// /// For future use... /// public string fromEventLabel; /// /// The EventHandlers /// public List events = new List(); } }