Skip to content

Commit eb13d62

Browse files
committed
Add new EventReference class
1 parent e6d7e45 commit eb13d62

File tree

8 files changed

+182
-21
lines changed

8 files changed

+182
-21
lines changed

Documentation~/articles/events.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ An event can be created through the Asset menu, `Zigurous > Events > Game Event`
1313
### Game Event Listener
1414

1515
A [GameEventListener](/api/Zigurous.Architecture/GameEventListener) component can be added to any game object that needs to listen for an event. This is a class that derives from `MonoBehaviour` and will register and unregister itself as a listener for the specified event. The listener also declares a standard `UnityEvent` response property that is invoked when the event is raised.
16+
17+
### Event Reference
18+
19+
The [EventReference](/api/Zigurous.Architecture/EventReference) class allows a `UnityEvent` or `GameEvent` to be referenced. The option to switch between the two choices is available in the editor. Anywhere you might declare a variable as a `UnityEvent` or a `GameEvent` consider declaring it as an `EventReference` for more flexibility.

Documentation~/articles/scriptable-variables.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ For example, the player can declare their hitpoints as a `FloatVariable` instead
1212

1313
The downside with this is it can be cumbersome to create assets for every variable declared in a behaviour. Instead of declaring `FloatVariable` we can declare a `FloatReference` for additional flexibility. This allows the value to either be a constant value or a reference to a variable asset; the choice is customizable in the editor. These reference types derive from [ValueReference\<TValue, TVariable\>](/api/Zigurous.Architecture/ValueReference-2).
1414

15-
Supported Types:
15+
### Supported Types
1616

1717
- Bool
1818
- Bounds
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using UnityEditor;
2+
using UnityEngine;
3+
4+
namespace Zigurous.Architecture.Editor
5+
{
6+
[CustomPropertyDrawer(typeof(EventReference), true)]
7+
public sealed class EventReferencePropertyDrawer : PropertyDrawer
8+
{
9+
private readonly string[] popupOptions = { "Use Unity Event", "Use Game Event" };
10+
private static GUIStyle popupStyle;
11+
12+
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
13+
{
14+
if (popupStyle == null)
15+
{
16+
popupStyle = new GUIStyle(GUI.skin.GetStyle("PaneOptions"));
17+
popupStyle.imagePosition = ImagePosition.ImageOnly;
18+
}
19+
20+
SerializedProperty useUnityEvent = property.FindPropertyRelative("useUnityEvent");
21+
SerializedProperty unityEvent = property.FindPropertyRelative("unityEvent");
22+
SerializedProperty gameEvent = property.FindPropertyRelative("gameEvent");
23+
24+
label = EditorGUI.BeginProperty(position, label, property);
25+
26+
if (!useUnityEvent.boolValue) {
27+
position = EditorGUI.PrefixLabel(position, label);
28+
}
29+
30+
Rect popupRect = new Rect(position);
31+
popupRect.width = popupStyle.fixedWidth + popupStyle.margin.right;
32+
popupRect.height = EditorGUIUtility.singleLineHeight;
33+
popupRect.y += (popupRect.height - popupStyle.fixedHeight) / 2f;
34+
position.width -= popupRect.width;
35+
popupRect.x += position.width;
36+
37+
EditorGUI.BeginChangeCheck();
38+
39+
int indent = EditorGUI.indentLevel;
40+
EditorGUI.indentLevel = 0;
41+
42+
int result = EditorGUI.Popup(popupRect, useUnityEvent.boolValue ? 0 : 1, popupOptions, popupStyle);
43+
useUnityEvent.boolValue = result == 0;
44+
45+
if (useUnityEvent.boolValue) {
46+
EditorGUI.PropertyField(position, unityEvent, label, true);
47+
} else {
48+
EditorGUI.PropertyField(position, gameEvent, GUIContent.none, true);
49+
}
50+
51+
if (EditorGUI.EndChangeCheck()) {
52+
property.serializedObject.ApplyModifiedProperties();
53+
}
54+
55+
EditorGUI.indentLevel = indent;
56+
EditorGUI.EndProperty();
57+
}
58+
59+
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
60+
{
61+
SerializedProperty useUnityEvent = property.FindPropertyRelative("useUnityEvent");
62+
SerializedProperty unityEvent = property.FindPropertyRelative("unityEvent");
63+
SerializedProperty gameEvent = property.FindPropertyRelative("gameEvent");
64+
65+
return EditorGUI.GetPropertyHeight(useUnityEvent.boolValue ? unityEvent : gameEvent, true);
66+
}
67+
68+
}
69+
70+
}

Editor/Events/EventReferencePropertyDrawer.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Editor/Variables/ValueReferencePropertyDrawer.cs

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,26 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten
3232
popupStyle.imagePosition = ImagePosition.ImageOnly;
3333
}
3434

35-
label = EditorGUI.BeginProperty(position, label, property);
36-
position = EditorGUI.PrefixLabel(position, label);
37-
38-
EditorGUI.BeginChangeCheck();
39-
4035
SerializedProperty useConstant = property.FindPropertyRelative("useConstant");
4136
SerializedProperty constantValue = property.FindPropertyRelative("constantValue");
4237
SerializedProperty variable = property.FindPropertyRelative("variable");
4338

44-
Rect buttonRect = new Rect(position);
45-
buttonRect.width = popupStyle.fixedWidth + popupStyle.margin.right;
46-
buttonRect.height = EditorGUIUtility.singleLineHeight;
47-
buttonRect.y += (buttonRect.height - popupStyle.fixedHeight) / 2f;
48-
position.width -= buttonRect.width;
49-
buttonRect.x += position.width;
39+
label = EditorGUI.BeginProperty(position, label, property);
40+
position = EditorGUI.PrefixLabel(position, label);
41+
42+
Rect popupRect = new Rect(position);
43+
popupRect.width = popupStyle.fixedWidth + popupStyle.margin.right;
44+
popupRect.height = EditorGUIUtility.singleLineHeight;
45+
popupRect.y += (popupRect.height - popupStyle.fixedHeight) / 2f;
46+
position.width -= popupRect.width;
47+
popupRect.x += position.width;
48+
49+
EditorGUI.BeginChangeCheck();
5050

5151
int indent = EditorGUI.indentLevel;
5252
EditorGUI.indentLevel = 0;
5353

54-
int result = EditorGUI.Popup(buttonRect, useConstant.boolValue ? 0 : 1, popupOptions, popupStyle);
54+
int result = EditorGUI.Popup(popupRect, useConstant.boolValue ? 0 : 1, popupOptions, popupStyle);
5555
useConstant.boolValue = result == 0;
5656

5757
EditorGUI.PropertyField(position, useConstant.boolValue ? constantValue : variable, GUIContent.none, true);
@@ -68,12 +68,9 @@ public override float GetPropertyHeight(SerializedProperty property, GUIContent
6868
{
6969
SerializedProperty useConstant = property.FindPropertyRelative("useConstant");
7070
SerializedProperty constantValue = property.FindPropertyRelative("constantValue");
71+
SerializedProperty variable = property.FindPropertyRelative("variable");
7172

72-
if (useConstant.boolValue) {
73-
return EditorGUI.GetPropertyHeight(constantValue, true);
74-
} else {
75-
return base.GetPropertyHeight(property, label);
76-
}
73+
return EditorGUI.GetPropertyHeight(useConstant.boolValue ? constantValue : variable, true);
7774
}
7875

7976
}

Runtime/Behaviours/TimerEvents.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using UnityEngine;
2-
using UnityEngine.Events;
32

43
namespace Zigurous.Architecture
54
{
@@ -13,13 +12,13 @@ public sealed class TimerEvents
1312
/// An event invoked every timer interval.
1413
/// </summary>
1514
[Tooltip("An event invoked every timer interval.")]
16-
public UnityEvent onTick;
15+
public EventReference onTick;
1716

1817
/// <summary>
1918
/// An event invoked every timer completion.
2019
/// </summary>
2120
[Tooltip("An event invoked every timer completion.")]
22-
public UnityEvent onComplete;
21+
public EventReference onComplete;
2322
}
2423

2524
}

Runtime/Events/EventReference.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using UnityEngine;
2+
using UnityEngine.Events;
3+
4+
namespace Zigurous.Architecture
5+
{
6+
/// <summary>
7+
/// A reference to a UnityEvent or a GameEvent.
8+
/// </summary>
9+
[System.Serializable]
10+
public sealed class EventReference
11+
{
12+
/// <summary>
13+
/// Uses a UnityEvent instead of a GameEvent.
14+
/// </summary>
15+
[Tooltip("Uses a UnityEvent instead of a GameEvent.")]
16+
public bool useUnityEvent = true;
17+
18+
/// <summary>
19+
/// The UnityEvent to use.
20+
/// </summary>
21+
[Tooltip("The UnityEvent to use.")]
22+
public UnityEvent unityEvent;
23+
24+
/// <summary>
25+
/// The GameEvent to use.
26+
/// </summary>
27+
[Tooltip("The GameEvent to use.")]
28+
public GameEvent gameEvent;
29+
30+
/// <summary>
31+
/// Creates a new event reference.
32+
/// </summary>
33+
public EventReference() {}
34+
35+
/// <summary>
36+
/// Creates a new event reference to the UnityEvent.
37+
/// </summary>
38+
/// <param name="unityEvent">The UnityEvent to use.</param>
39+
public EventReference(UnityEvent unityEvent)
40+
{
41+
this.useUnityEvent = true;
42+
this.unityEvent = unityEvent;
43+
}
44+
45+
/// <summary>
46+
/// Creates a new event reference to the GameEvent.
47+
/// </summary>
48+
/// <param name="gameEvent">The GameEvent to use.</param>
49+
public EventReference(GameEvent gameEvent)
50+
{
51+
this.useUnityEvent = false;
52+
this.gameEvent = gameEvent;
53+
}
54+
55+
/// <summary>
56+
/// Invokes or raises the event depending on the type.
57+
/// </summary>
58+
public void Invoke()
59+
{
60+
if (useUnityEvent) {
61+
unityEvent?.Invoke();
62+
} else {
63+
gameEvent?.Raise();
64+
}
65+
}
66+
67+
}
68+
69+
}

Runtime/Events/EventReference.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)