Skip to content

Commit 64e186e

Browse files
authored
Convert repo to host only GameEvent (now ScriptableEvent) funcionality (#2)
* Remove mutable object func * Initial rework of events * Use new game event API * Fixup most tests, disable some (for now) * Cleanup, rename *GameEvent to *ScriptableEvent * Fixup editor a bit * Remove images and unused csproj files * Update project settings * Update namespace * Cleanup DotSettings * Update event editor, add package validator * Suppress faulty warnings * Simplify assemblies * Make API more strict, Clear functionality, overload + and - operators for adding and removing events * Cleanup imports * Add tests for all event and listener implementations and their attributes * Update Unity version * Remove universal RP * Simplify editor API * Improve UX by ordering events and listeners, update tests * Remove old samples, add samples showing how to use simple & arg events * Rename sample scripts * Add custom event example * Cleanup sample scenes * Move library assets to Packages/com.chark.scriptable-events * Move samples to Samples~/ dir
0 parents  commit 64e186e

167 files changed

Lines changed: 6760 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Changelog
2+
All notable changes to this project will be documented in this file.
3+
4+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6+
7+
## [1.0.0] - 2021-01-25
8+
Initial release, here we list changes made after moving away from [Unity Scriptable Objects](https://github.com/chark/unity-scriptable-objects).
9+
10+
### Changed
11+
- Naming of events, `*GameEvent` -> `*ScriptableEvent`.
12+
- Rewrote event, listener and inspector GUI APIs.
13+
- Rewrote test code.
14+
- Documentation to only focus on events.

CHANGELOG.md.meta

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

Documentation~/README.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# Documentation
2+
Most of the documented features can be imported as samples via Unity Package Manager or taken directly from [Samples](../Samples%7E) directory.
3+
4+
## Table of contents
5+
- [General](#general)
6+
- [Simple events](#simple-events)
7+
- [Events with arguments](#events-with-arguments)
8+
- [Custom events](#custom-events)
9+
10+
## General
11+
12+
### Tips
13+
- When creating prefabs, event assets can be referenced in them. Then when you add in your prefabs into a scene, no additional setup is necessary!
14+
- Event assets can be used to communicate between scenes, this is particularly useful when using [Multi Scene Editing](https://docs.unity3d.com/Manual/MultiSceneEditing.html).
15+
16+
### Event asset GUI
17+
<p align="center">
18+
<img src="simple-event.png"/>
19+
</p>
20+
21+
- Description - custom description for the event, what it does, etc, [Rich Text](https://docs.unity3d.com/Packages/com.unity.ugui@1.0/manual/StyledText.html) is also supported.
22+
- Lock button - disables the _Description_ field, useful to avoid accidental edits.
23+
- Suppress Exceptions - if an event has more than one listener, the first listener to throw an exception will break the chain. When enabled, the exception will get logged and other listeners will continue firing.
24+
- Trace - enable additional logging.
25+
- Raise Event - _Raise_ the event, available only in Play Mode.
26+
- Added Listeners - shows listeners which are subscribed to the event, available only in Play Mode.
27+
28+
## Simple Events
29+
Simple events are useful when you need to _ping_ a `MonoBehaviour` in order to trigger an action. For example, the player loses, and the game needs to show a game over screen (complete example can be found [here](../Samples~/SimpleEvents)).
30+
31+
### Event asset
32+
To create a simple event, _right click_ in the _Project_ window, and select _Create -> Scriptable Events -> Simple Scriptable Event_. This will create a `SimpleScriptableEvent` asset file, you can name the file however you like and place it anywhere in your project.
33+
34+
### Raise event
35+
After you have prepared the event, you will want to _Raise_ it. This can be done by dragging the event asset into any `UnityEvent` available on one of your `MonoBehaviour` and selecting the `Raise` method:
36+
<p align="center">
37+
<img src="simple-event-raise.png"/>
38+
</p>
39+
40+
Alternatively you can _Raise_ the event from within a script:
41+
```cs
42+
[SerializedField]
43+
private SimpleScriptableEvent simpleScriptableEvent;
44+
45+
...
46+
47+
simpleScriptableEvent.Raise();
48+
```
49+
50+
### Event listener
51+
Next thing you will need is a listener, select any `GameObject` in the scene, click _Add Component_ and select _Scriptable Events -> Simple Scriptable Event Listener_. Then, slot in the event asset in _Scriptable Event_ field and add a callback to the _On Raised_ `UnityEvent` under the listener which will invoke a method on a `MonoBehaviour`:
52+
<p align="center">
53+
<img src="simple-event-listener.png"/>
54+
</p>
55+
56+
Alternatively, you can subscribe to an event via a script:
57+
```cs
58+
public class CustomListener : MonoBehaviour, IScriptableEventListener<SimpleArg>
59+
{
60+
[SerializeField]
61+
private SimpleScriptableEvent simpleScriptableEvent;
62+
63+
public void OnRaised(SimpleArg arg)
64+
{
65+
// Handle event.
66+
}
67+
68+
private void OnEnable()
69+
{
70+
simpleScriptableEvent.Add(this);
71+
}
72+
73+
private void OnDisable()
74+
{
75+
simpleScriptableEvent.Remove(this);
76+
}
77+
}
78+
```
79+
80+
## Events with arguments
81+
Events with arguments are useful when you need to pass around data instead of just _pinging_. For example, the player picks up a coin, and you need to increment the score counter by a certain amount based on the coins value (complete example can be found [here](../Samples~/EventsWithArguments)).
82+
83+
### Event asset
84+
To create an event with an argument, the approach is similar to [Simple Events](#simple-events). Simply _right click_ in the _Project_ window, and select _Create -> Scriptable Events -> {Type} Scriptable Event_, where _{Type}_ is the type of the data you want to pass.
85+
86+
### Raise event
87+
To _Raise_ event with an argument, you will first need a `UnityEvent` that accepts a value of desired type. For each `ScriptableEvent` exists a `UnityEvent` with given type (see `ScriptableEvents.{Type}.{Type}UnityEvent` for existing implementations).
88+
89+
After that is sorted, you will need to expose the `UnityEvent` and `Invoke` it in your script, for example a `UnityEvent` that accepts `float` would looks like:
90+
```cs
91+
[SerializedField]
92+
private ScriptableEvents.Float.FloatUnityEvent floatUnityEvent;
93+
94+
...
95+
96+
floatUnityEvent.Invoke(1.0f);
97+
```
98+
99+
Then, to raise the `ScriptableEvent`, drag it into the exposed `UnityEvent` of specific type and select the **Dynamic** `Raise` method. This will ensure that the value passed to the `UnityEvent` gets forwarded to the `Raise` method:
100+
<p align="center">
101+
<img src="argument-event-raise.png"/>
102+
</p>
103+
104+
Alternatively, you can _Raise_ the event from a script:
105+
```cs
106+
[SerializedField]
107+
private FloatScriptableEvent floatScriptableEvent;
108+
109+
...
110+
111+
floatScriptableEvent.Raise(1.0f);
112+
```
113+
114+
### Event listener
115+
Next thing you will need is a listener. The approach of adding a listener is similar to [Simple Events](#simple-events) as well. Select any `GameObject` in the scene, click _Add Component_ and select _Scriptable Events -> {Type} Scriptable Event Listener_. The only difference is that when selecting your method, you must select a **Dynamic** method.
116+
117+
When subscribing via a script, you will also need to specify a different type argument rather than using `SimpleArg`, in this example `float` is used:
118+
```cs
119+
public class CustomListener : MonoBehaviour, IScriptableEventListener<float>
120+
{
121+
[SerializeField]
122+
private FloatScriptableEvent floatScriptableEvent;
123+
124+
public void OnRaised(float arg)
125+
{
126+
// Handle event.
127+
}
128+
129+
private void OnEnable()
130+
{
131+
floatScriptableEvent.Add(this);
132+
}
133+
134+
private void OnDisable()
135+
{
136+
floatScriptableEvent.Remove(this);
137+
}
138+
}
139+
```
140+
141+
## Custom Events
142+
You can also create custom events where you can pass any kind of data. For example, the player loses, and you want to send the reference to the player, and the enemy which collided with the player (complete example can be found [here](../Samples~/CustomEvents)).
143+
144+
First define the data that you want to send:
145+
```cs
146+
public class CustomData
147+
{
148+
public float ValueA { get; }
149+
150+
public int ValueB { get; }
151+
152+
public MaterialData(float valueA, int valueB)
153+
{
154+
ValueA = valueA;
155+
ValueB = valueB;
156+
}
157+
}
158+
```
159+
160+
Similarly to [Events with arguments](#events-with-arguments) you will need a `UnityEvent` which accepts your custom data type:
161+
```cs
162+
[Serializable]
163+
public CustomDataUnityEvent : UnityEvent<CustomData>
164+
{
165+
}
166+
```
167+
168+
Next up, define the scriptable event:
169+
```cs
170+
[CreateAssetMenu(
171+
fileName = "CustomDataScriptableEvent",
172+
menuName = "Custom Scriptable Events/Custom Data Scriptable Event"
173+
)]
174+
public class CustomDataScriptableEvent : BaseScriptableEvent<CustomData>
175+
{
176+
}
177+
```
178+
179+
Finally, create a listener which will glue everything together:
180+
```cs
181+
[AddComponentMenu("Custom Scriptable Events/Custom Data Event Listener")]
182+
public class CustomDataScriptableEventListener
183+
: BaseScriptableEventListener<
184+
CustomDataScriptableEvent,
185+
CustomDataUnityEvent,
186+
CustomData
187+
>
188+
{
189+
}
190+
```
191+
192+
After setting everything, you can use your custom event the same way as described in [Events with arguments](#events-with-arguments). However, you will not be able to use additional GUI features as with built-in events. To solve this, define a custom editor script (make sure to place it under `Editor` directory):
193+
```cs
194+
[CustomEditor(typeof(CustomDataScriptableEvent))]
195+
public class CustomDataScriptableEventEditor : BaseScriptableEventEditor<CustomData>
196+
{
197+
protected override CustomData DrawArgField(CustomData value)
198+
{
199+
// Initially the value will be null as BaseScriptableEventEditor does not know how to
200+
// construct an instance of CustomData.
201+
if (value == null)
202+
{
203+
return new CustomData(0f, 0);
204+
}
205+
206+
// Add input fields under the inspector. Note that these can also be objects - you can drag
207+
// them in from the scene window!
208+
209+
// Also note that you can omit this step if your data is complex. For example,
210+
// SimpleScriptableEvent does not render any fields.
211+
EditorGUILayout.BeginVertical();
212+
var valueA = EditorGUILayout.FloatField("Value A", value.ValueA);
213+
var valueB = EditorGUILayout.IntField("Value B", value.ValueB);
214+
EditorGUILayout.EndVertical();
215+
216+
return new CustomData(valueA, valueB);
217+
}
218+
}
219+
```
28 KB
Loading
30.3 KB
Loading
21.5 KB
Loading

Documentation~/simple-event.png

30.2 KB
Loading

Editor.meta

Lines changed: 8 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)