Browse Source

Merge pull request #582 from sp-francisco-ruiz/master

Refactor EventHandler notification in order to avoid FindObjectsOfType calls
master
Chris Gregan 8 years ago committed by GitHub
parent
commit
b764064a22
  1. 8
      Assets/Fungus/Scripts/Components/Clickable2D.cs
  2. 85
      Assets/Fungus/Scripts/Components/Draggable2D.cs
  3. 32
      Assets/Fungus/Scripts/Components/EventHandler.cs
  4. 25
      Assets/Fungus/Scripts/EventHandlers/DragCancelled.cs
  5. 49
      Assets/Fungus/Scripts/EventHandlers/DragCompleted.cs
  6. 26
      Assets/Fungus/Scripts/EventHandlers/DragEntered.cs
  7. 28
      Assets/Fungus/Scripts/EventHandlers/DragExited.cs
  8. 26
      Assets/Fungus/Scripts/EventHandlers/DragStarted.cs
  9. 174
      Assets/Fungus/Scripts/EventHandlers/EventDispatcher.cs
  10. 12
      Assets/Fungus/Scripts/EventHandlers/EventDispatcher.cs.meta
  11. 3
      Assets/Fungus/Scripts/EventHandlers/FlowchartEnabled.cs
  12. 8
      Assets/Fungus/Scripts/EventHandlers/GameStarted.cs
  13. 27
      Assets/Fungus/Scripts/EventHandlers/ObjectClicked.cs

8
Assets/Fungus/Scripts/Components/Clickable2D.cs

@ -39,13 +39,7 @@ namespace Fungus
return; return;
} }
// TODO: Cache these objects for faster lookup EventDispatcher.Raise(new ObjectClicked.ObjectClickedEvent(this));
var handlers = GameObject.FindObjectsOfType<ObjectClicked>();
for (int i = 0; i < handlers.Length; i++)
{
var handler = handlers[i];
handler.OnObjectClicked(this);
}
} }
protected virtual void DoPointerEnter() protected virtual void DoPointerEnter()

85
Assets/Fungus/Scripts/Components/Draggable2D.cs

@ -4,6 +4,7 @@
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.Serialization; using UnityEngine.Serialization;
using System.Collections.Generic;
namespace Fungus namespace Fungus
{ {
@ -40,6 +41,23 @@ namespace Fungus
protected Vector3 newPosition; protected Vector3 newPosition;
protected Vector3 delta = Vector3.zero; protected Vector3 delta = Vector3.zero;
#region DragCompleted handlers
protected List<DragCompleted> dragCompletedHandlers = new List<DragCompleted>();
public void RegisterHandler(DragCompleted handler)
{
dragCompletedHandlers.Add(handler);
}
public void UnregisterHandler(DragCompleted handler)
{
if(dragCompletedHandlers.Contains(handler))
{
dragCompletedHandlers.Remove(handler);
}
}
#endregion
protected virtual void LateUpdate() protected virtual void LateUpdate()
{ {
// iTween will sometimes override the object position even if it should only be affecting the scale, rotation, etc. // iTween will sometimes override the object position even if it should only be affecting the scale, rotation, etc.
@ -57,20 +75,7 @@ namespace Fungus
{ {
return; return;
} }
EventDispatcher.Raise(new DragEntered.DragEnteredEvent(this, other));
var dragEnteredHandlers = GetHandlers<DragEntered>();
for (int i = 0; i < dragEnteredHandlers.Length; i++)
{
var handler = dragEnteredHandlers[i];
handler.OnDragEntered(this, other);
}
var dragCompletedHandlers = GetHandlers<DragCompleted>();
for (int i = 0; i < dragCompletedHandlers.Length; i++)
{
var handler = dragCompletedHandlers[i];
handler.OnDragEntered(this, other);
}
} }
protected virtual void OnTriggerExit2D(Collider2D other) protected virtual void OnTriggerExit2D(Collider2D other)
@ -79,26 +84,7 @@ namespace Fungus
{ {
return; return;
} }
EventDispatcher.Raise(new DragExited.DragExitedEvent(this, other));
var dragExitedHandlers = GetHandlers<DragExited>();
for (int i = 0; i < dragExitedHandlers.Length; i++)
{
var handler = dragExitedHandlers[i];
handler.OnDragExited(this, other);
}
var dragCompletedHandlers = GetHandlers<DragCompleted>();
for (int i = 0; i < dragCompletedHandlers.Length; i++)
{
var handler = dragCompletedHandlers[i];
handler.OnDragExited(this, other);
}
}
protected virtual T[] GetHandlers<T>() where T : EventHandler
{
// TODO: Cache these object for faster lookup
return GameObject.FindObjectsOfType<T>();
} }
protected virtual void DoBeginDrag() protected virtual void DoBeginDrag()
@ -111,12 +97,7 @@ namespace Fungus
startingPosition = transform.position; startingPosition = transform.position;
var dragStartedHandlers = GetHandlers<DragStarted>(); EventDispatcher.Raise(new DragStarted.DragStartedEvent(this));
for (int i = 0; i < dragStartedHandlers.Length; i++)
{
var handler = dragStartedHandlers[i];
handler.OnDragStarted(this);
}
} }
protected virtual void DoDrag() protected virtual void DoDrag()
@ -144,38 +125,32 @@ namespace Fungus
bool dragCompleted = false; bool dragCompleted = false;
var handlers = GetHandlers<DragCompleted>(); for (int i = 0; i < dragCompletedHandlers.Count; i++)
for (int i = 0; i < handlers.Length; i++)
{ {
var handler = handlers[i]; var handler = dragCompletedHandlers[i];
if (handler.DraggableObject == this) if (handler != null && handler.DraggableObject == this)
{ {
if (handler.IsOverTarget()) if (handler.IsOverTarget())
{ {
handler.OnDragCompleted(this);
dragCompleted = true; dragCompleted = true;
if (returnOnCompleted) EventDispatcher.Raise(new DragCompleted.DragCompletedEvent(this));
{
LeanTween.move(gameObject, startingPosition, returnDuration).setEase(LeanTweenType.easeOutExpo);
}
} }
} }
} }
if (!dragCompleted) if (!dragCompleted)
{ {
var dragCancelledHandlers = GetHandlers<DragCancelled>(); EventDispatcher.Raise(new DragCancelled.DragCancelledEvent(this));
for (int i = 0; i < dragCancelledHandlers.Length; i++)
{
var handler = dragCancelledHandlers[i];
handler.OnDragCancelled(this);
}
if (returnOnCancelled) if (returnOnCancelled)
{ {
LeanTween.move(gameObject, startingPosition, returnDuration).setEase(LeanTweenType.easeOutExpo); LeanTween.move(gameObject, startingPosition, returnDuration).setEase(LeanTweenType.easeOutExpo);
} }
} }
else if(returnOnCompleted)
{
LeanTween.move(gameObject, startingPosition, returnDuration).setEase(LeanTweenType.easeOutExpo);
}
} }
protected virtual void DoPointerEnter() protected virtual void DoPointerEnter()

32
Assets/Fungus/Scripts/Components/EventHandler.cs

@ -41,6 +41,38 @@ namespace Fungus
[FormerlySerializedAs("parentSequence")] [FormerlySerializedAs("parentSequence")]
[SerializeField] protected Block parentBlock; [SerializeField] protected Block parentBlock;
#region Unity Messages Propagation
protected virtual void UnityOnEnable()
{
}
protected virtual void UnityOnDisable()
{
}
protected virtual void UnityStart()
{
}
void OnEnable()
{
UnityOnEnable();
}
void OnDisable()
{
UnityOnDisable();
}
void Start()
{
UnityStart();
}
#endregion
#region Public members #region Public members
/// <summary> /// <summary>

25
Assets/Fungus/Scripts/EventHandlers/DragCancelled.cs

@ -14,9 +14,34 @@ namespace Fungus
[AddComponentMenu("")] [AddComponentMenu("")]
public class DragCancelled : EventHandler public class DragCancelled : EventHandler
{ {
public class DragCancelledEvent
{
public Draggable2D DraggableObject;
public DragCancelledEvent(Draggable2D draggableObject)
{
DraggableObject = draggableObject;
}
}
[Tooltip("Draggable object to listen for drag events on")] [Tooltip("Draggable object to listen for drag events on")]
[SerializeField] protected Draggable2D draggableObject; [SerializeField] protected Draggable2D draggableObject;
protected override void UnityOnEnable()
{
base.UnityOnEnable();
EventDispatcher.AddListener<DragCancelledEvent>(OnDragCancelledEvent);
}
protected override void UnityOnDisable()
{
base.UnityOnDisable();
EventDispatcher.RemoveListener<DragCancelledEvent>(OnDragCancelledEvent);
}
void OnDragCancelledEvent(DragCancelledEvent evt)
{
OnDragCancelled(evt.DraggableObject);
}
#region Public members #region Public members
public virtual void OnDragCancelled(Draggable2D draggableObject) public virtual void OnDragCancelled(Draggable2D draggableObject)

49
Assets/Fungus/Scripts/EventHandlers/DragCompleted.cs

@ -14,6 +14,14 @@ namespace Fungus
[AddComponentMenu("")] [AddComponentMenu("")]
public class DragCompleted : EventHandler public class DragCompleted : EventHandler
{ {
public class DragCompletedEvent
{
public Draggable2D DraggableObject;
public DragCompletedEvent(Draggable2D draggableObject)
{
DraggableObject = draggableObject;
}
}
[Tooltip("Draggable object to listen for drag events on")] [Tooltip("Draggable object to listen for drag events on")]
[SerializeField] protected Draggable2D draggableObject; [SerializeField] protected Draggable2D draggableObject;
@ -24,6 +32,47 @@ namespace Fungus
// we have to listen to the callbacks and track the touching state ourselves. // we have to listen to the callbacks and track the touching state ourselves.
protected bool overTarget = false; protected bool overTarget = false;
protected override void UnityOnEnable()
{
base.UnityOnEnable();
EventDispatcher.AddListener<DragCompletedEvent>(OnDragCompletedEvent);
EventDispatcher.AddListener<DragEntered.DragEnteredEvent>(OnDragEnteredEvent);
EventDispatcher.AddListener<DragExited.DragExitedEvent>(OnDragExitedEvent);
if(draggableObject != null)
{
draggableObject.RegisterHandler(this);
}
}
protected override void UnityOnDisable()
{
base.UnityOnDisable();
EventDispatcher.RemoveListener<DragCompletedEvent>(OnDragCompletedEvent);
EventDispatcher.RemoveListener<DragEntered.DragEnteredEvent>(OnDragEnteredEvent);
EventDispatcher.RemoveListener<DragExited.DragExitedEvent>(OnDragExitedEvent);
if(draggableObject != null)
{
draggableObject.UnregisterHandler(this);
}
}
void OnDragCompletedEvent(DragCompletedEvent evt)
{
OnDragCompleted(evt.DraggableObject);
}
void OnDragEnteredEvent(DragEntered.DragEnteredEvent evt)
{
OnDragEntered(evt.DraggableObject, evt.TargetCollider);
}
void OnDragExitedEvent(DragExited.DragExitedEvent evt)
{
OnDragExited(evt.DraggableObject, evt.TargetCollider);
}
#region Public members #region Public members
/// <summary> /// <summary>

26
Assets/Fungus/Scripts/EventHandlers/DragEntered.cs

@ -17,12 +17,38 @@ namespace Fungus
[AddComponentMenu("")] [AddComponentMenu("")]
public class DragEntered : EventHandler public class DragEntered : EventHandler
{ {
public class DragEnteredEvent
{
public Draggable2D DraggableObject;
public Collider2D TargetCollider;
public DragEnteredEvent(Draggable2D draggableObject, Collider2D targetCollider)
{
DraggableObject = draggableObject;
TargetCollider = targetCollider;
}
}
[Tooltip("Draggable object to listen for drag events on")] [Tooltip("Draggable object to listen for drag events on")]
[SerializeField] protected Draggable2D draggableObject; [SerializeField] protected Draggable2D draggableObject;
[Tooltip("Drag target object to listen for drag events on")] [Tooltip("Drag target object to listen for drag events on")]
[SerializeField] protected Collider2D targetObject; [SerializeField] protected Collider2D targetObject;
protected override void UnityOnEnable()
{
base.UnityOnEnable();
EventDispatcher.AddListener<DragEnteredEvent>(OnDragEnteredEvent);
}
protected override void UnityOnDisable()
{
base.UnityOnDisable();
EventDispatcher.RemoveListener<DragEnteredEvent>(OnDragEnteredEvent);
}
void OnDragEnteredEvent(DragEnteredEvent evt)
{
OnDragEntered(evt.DraggableObject, evt.TargetCollider);
}
#region Public members #region Public members
/// <summary> /// <summary>

28
Assets/Fungus/Scripts/EventHandlers/DragExited.cs

@ -17,12 +17,40 @@ namespace Fungus
[AddComponentMenu("")] [AddComponentMenu("")]
public class DragExited : EventHandler public class DragExited : EventHandler
{ {
public class DragExitedEvent
{
public Draggable2D DraggableObject;
public Collider2D TargetCollider;
public DragExitedEvent(Draggable2D draggableObject, Collider2D targetCollider)
{
DraggableObject = draggableObject;
TargetCollider = targetCollider;
}
}
[Tooltip("Draggable object to listen for drag events on")] [Tooltip("Draggable object to listen for drag events on")]
[SerializeField] protected Draggable2D draggableObject; [SerializeField] protected Draggable2D draggableObject;
[Tooltip("Drag target object to listen for drag events on")] [Tooltip("Drag target object to listen for drag events on")]
[SerializeField] protected Collider2D targetObject; [SerializeField] protected Collider2D targetObject;
protected override void UnityOnEnable()
{
base.UnityOnEnable();
EventDispatcher.AddListener<DragExitedEvent>(OnDragEnteredEvent);
}
protected override void UnityOnDisable()
{
base.UnityOnDisable();
EventDispatcher.RemoveListener<DragExitedEvent>(OnDragEnteredEvent);
}
void OnDragEnteredEvent(DragExitedEvent evt)
{
OnDragExited(evt.DraggableObject, evt.TargetCollider);
}
#region Public members #region Public members
/// <summary> /// <summary>

26
Assets/Fungus/Scripts/EventHandlers/DragStarted.cs

@ -14,8 +14,34 @@ namespace Fungus
[AddComponentMenu("")] [AddComponentMenu("")]
public class DragStarted : EventHandler public class DragStarted : EventHandler
{ {
public class DragStartedEvent
{
public Draggable2D DraggableObject;
public DragStartedEvent(Draggable2D draggableObject)
{
DraggableObject = draggableObject;
}
}
[SerializeField] protected Draggable2D draggableObject; [SerializeField] protected Draggable2D draggableObject;
protected override void UnityOnEnable()
{
base.UnityOnEnable();
EventDispatcher.AddListener<DragStartedEvent>(OnDragStartedEvent);
}
protected override void UnityOnDisable()
{
base.UnityOnDisable();
EventDispatcher.RemoveListener<DragStartedEvent>(OnDragStartedEvent);
}
void OnDragStartedEvent(DragStartedEvent evt)
{
OnDragStarted(evt.DraggableObject);
}
#region Public members #region Public members
/// <summary> /// <summary>

174
Assets/Fungus/Scripts/EventHandlers/EventDispatcher.cs

@ -0,0 +1,174 @@
using System.Collections.Generic;
using System;
namespace Fungus
{
public class EventDispatcher
{
public delegate void TypedDelegate<T>(T e) where T : class;
#region Statics
static EventDispatcher _instance;
public static EventDispatcher Instance
{
get
{
if(_instance == null)
{
_instance = new EventDispatcher();
}
return _instance;
}
}
public static void AddLog(Action<string> log)
{
Instance.addLog(log);
}
public static void RemoveLog(Action<string> log)
{
Instance.removeLog(log);
}
public static void AddListener<T>(TypedDelegate<T> listener) where T : class
{
Instance.addListener(listener);
}
public static void RemoveListener<T>(TypedDelegate<T> listener) where T : class
{
Instance.removeListener(listener);
}
public static void Raise<T>(T evt) where T : class
{
Instance.raise(evt);
}
public static void Raise<T>() where T : class, new()
{
Instance.raise<T>(new T());
}
public static void UnregisterAll()
{
Instance.unregisterAll();
}
#endregion
#region Private Members
readonly Dictionary<Type, List<Delegate>> _delegates;
event Action<string> _onLog;
#endregion
#region Private Functions
private EventDispatcher()
{
_delegates = new Dictionary<Type, List<Delegate>>();
}
/// <summary>
/// Gets the delegate list copy.
/// </summary>
/// <remarks>
/// As listener can modify the list while iterating it, it is better to iterate a copy of the delegates list instead of a reference.
/// </remarks>
/// <returns>A copy of the delegates list if found. Null if the dictionary does not contain a delegate list for this event.</returns>
/// <param name="evt">Event instance.</param>
/// <typeparam name="T">Type of the received event.</typeparam>
List<Delegate> getDelegateListCopy<T>(T evt)
{
var type = typeof(T);
return _delegates.ContainsKey(type) ? new List<Delegate>(_delegates[type]) : null;
}
void log(string message)
{
if(_onLog != null)
{
_onLog(message);
}
}
#endregion
#region Public Functions
public void addLog(Action<string> log)
{
_onLog += log;
}
public void removeLog(Action<string> log)
{
_onLog -= log;
}
public void addListener<T>(TypedDelegate<T> listener) where T : class
{
var type = typeof(T);
if(!_delegates.ContainsKey(type))
{
_delegates.Add(type, new List<Delegate>());
}
var list = _delegates[type];
if(!list.Contains(listener))
{
list.Add(listener);
}
}
public void removeListener<T>(TypedDelegate<T> listener) where T : class
{
var type = typeof(T);
if(_delegates.ContainsKey(type))
{
_delegates[type].Remove(listener);
return;
}
}
public void raise<T>(T evt) where T : class
{
if(evt == null)
{
log("Raised a null event");
return;
}
var list = getDelegateListCopy(evt);
if(list == null || list.Count < 1)
{
log("Raised an event with no listeners");
return;
}
for(int i = 0; i < list.Count; ++i)
{
var callback = list[i] as TypedDelegate<T>;
if(callback != null)
{
try
{
callback(evt);
}
catch(Exception gotcha)
{
log(gotcha.Message);
}
}
}
}
public void raise<T>() where T : class, new()
{
raise<T>(new T());
}
public void unregisterAll()
{
_delegates.Clear();
}
#endregion
}
}

12
Assets/Fungus/Scripts/EventHandlers/EventDispatcher.cs.meta

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d6bacc8888852c94bab5c3b36cdf1574
timeCreated: 1483696929
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

3
Assets/Fungus/Scripts/EventHandlers/FlowchartEnabled.cs

@ -14,8 +14,9 @@ namespace Fungus
[AddComponentMenu("")] [AddComponentMenu("")]
public class FlowchartEnabled : EventHandler public class FlowchartEnabled : EventHandler
{ {
protected virtual void OnEnable() protected override void UnityOnEnable()
{ {
base.UnityOnEnable();
// Blocks use coroutines to schedule command execution, but Unity's coroutines are // Blocks use coroutines to schedule command execution, but Unity's coroutines are
// sometimes unreliable when enabling / disabling objects. // sometimes unreliable when enabling / disabling objects.
// To workaround this we execute the block on the next frame. // To workaround this we execute the block on the next frame.

8
Assets/Fungus/Scripts/EventHandlers/GameStarted.cs

@ -18,7 +18,13 @@ namespace Fungus
[Tooltip("Wait for a number of frames after startup before executing the Block. Can help fix startup order issues.")] [Tooltip("Wait for a number of frames after startup before executing the Block. Can help fix startup order issues.")]
[SerializeField] protected int waitForFrames = 1; [SerializeField] protected int waitForFrames = 1;
protected virtual IEnumerator Start() protected override void UnityStart()
{
base.UnityStart();
StartCoroutine(GameStartCoroutine());
}
protected virtual IEnumerator GameStartCoroutine()
{ {
int frameCount = waitForFrames; int frameCount = waitForFrames;
while (frameCount > 0) while (frameCount > 0)

27
Assets/Fungus/Scripts/EventHandlers/ObjectClicked.cs

@ -15,12 +15,39 @@ namespace Fungus
[AddComponentMenu("")] [AddComponentMenu("")]
public class ObjectClicked : EventHandler public class ObjectClicked : EventHandler
{ {
public class ObjectClickedEvent
{
public Clickable2D ClickableObject;
public ObjectClickedEvent(Clickable2D clickableObject)
{
ClickableObject = clickableObject;
}
}
[Tooltip("Object that the user can click or tap on")] [Tooltip("Object that the user can click or tap on")]
[SerializeField] protected Clickable2D clickableObject; [SerializeField] protected Clickable2D clickableObject;
[Tooltip("Wait for a number of frames before executing the block.")] [Tooltip("Wait for a number of frames before executing the block.")]
[SerializeField] protected int waitFrames = 1; [SerializeField] protected int waitFrames = 1;
protected override void UnityOnEnable()
{
base.UnityOnEnable();
EventDispatcher.AddListener<ObjectClickedEvent>(OnObjectClickedEvent);
}
protected override void UnityOnDisable()
{
base.UnityOnDisable();
EventDispatcher.RemoveListener<ObjectClickedEvent>(OnObjectClickedEvent);
}
void OnObjectClickedEvent(ObjectClickedEvent evt)
{
OnObjectClicked(evt.ClickableObject);
}
/// <summary> /// <summary>
/// Executing a block on the same frame that the object is clicked can cause /// Executing a block on the same frame that the object is clicked can cause
/// input problems (e.g. auto completing Say Dialog text). A single frame delay /// input problems (e.g. auto completing Say Dialog text). A single frame delay

Loading…
Cancel
Save