Unity - A Complete Scriptable Objects Events System (Including Passing Arguments)

preview_player
Показать описание
A thorough tutorial on how to create and implement a scriptable objects based events system. Based on Ryan Hipple talk in 2017, but in this video I showcase my own solution to handle the passing of arguments, which was not touched in Ryan's talk.

00:00 Intro
00:53 Tutorial scene/game
02:22 Scriptable Objects Events System (2 component system)
07:36 Issues with not being able to pass arguments
10:30 Passing arguments (3 component system)
12:32 Implementing the GameEventHub
19:39 Conclusion
20:22 Outro

#FumestsuHito#Unity#ScriptableObjects
Рекомендации по теме
Комментарии
Автор

Interesting... though the usage of the Hub_* classes seem error prone as you might forget to set the arguments before raising the event and you might also forget which argument class is associated with which event..

I would probably drop the GameEventHub altogether, make the Hub_* classes static and add a method that raises events and takes parameters...

So... rename Hub_ScoreChange to ScoreChangeArgs and instead of this:

= player;
= block.points;
scoreChange.Raise();

just raise the event like this:

ScoreChangeArgs.Raise(scoreChange, player, block.points)

that's far less clunky - what do you say?

for completeness sake... the class would look like this then:

public static class ScoreChangeArgs {
public static PlayerControl player;
public static float scoreToAdd;
public static Raise(GameEvent e, PlayerControl player, float scoreToAdd) {
ScoreChangeArgs.player = player;
ScoreChangeArgs.scoreToAdd = scoreToAdd;
e.Raise();
}
}

and in Listeners you can also access the args more naturally:

ScoreChangeArgs.scoreToAdd instead of

DerClaudius
Автор

Fantastic Tutorial. Simply and clearly explained. This is how all tutorials should be.

xtreme-software
Автор

Nice tutor, however I don`t like arguments passing method for some reason. And why are subtitles not available?

YasnaKo
Автор

Great video and very well presented.
I too implemented a similar system based on the same video linked and tackled the "passing arguments" problem, but I love watching other approaches to this. My solution was pretty different though, based on generic versions of GameEvent and Listener:

public class GameEventGeneric<T> : ScriptableObject
{
private readonly HashSet<Action<T>> _actions =
new HashSet<Action<T>>();
// rest almost same as GameEvent
}

zionen
Автор

how can avoid duplicated events? I mean I follow almost the same steps, but I am seeing duplicated events, do I need to create different events to do the same? I go to my Data folder, and create an event using the scriptable object "GameEvent" which I can create a template for that event, similar to the base tempalte that Ryan Hipple does.... but the problem is I got a problem like you showed in "issue passing NO arguments"... however I pass the 2 arguments and I continue seeing the same change in all of my prefab... like if they using polymorphism, and I am not using polymorphism. the behaviour of bad practice, in my case, is having the same behaviour for duplicated prefabs. also the "hub classes"? are monobehaviours? but they are not still attached to any object? .

risingforce
Автор

I heard that using static variables is not good because of memory allocation...

darkman
Автор

Surprised you didn't use GameEventT for the base class of game events.

Scriptable events are uncoupled and scalable, but GameEventHub is very coupled and unscalable.

If you used GameEventT each defined Scriptable Evenf would define the parameters they pass on broadcast, not requiring couple another class that also needs maintaining.

MrGluto
Автор

Arguments can be passed by using Invoke(params[] object arguments) kind of function

Lycam
Автор

This solution is creative, but... but...
I have trouble understanding the difference between dragging-dropping events and creating hard references through the code. They are the same thing, almost.
When we do this we artificially create hard references anyway, they are just not visible, like sweeping the dust under the rug.
Also if we are going to use a centralized static class, we can just create a huge, single static class that is going to be called anyways by any event raiser, and will be listened by all the listeners, and use it as a middleman. The ease of this video solution is to manage the event relationships through the editor, but in reality the cases are more complex. You have to create all these soft dependencies during runtime, and someone needs to manage this. Who will drag and drop the new connection during runtime?
If you are worried about megalithic classes, and finding your code inside a huge static event manager, just make it a partial class and separate them into different sheets, label them with comments, or use inheritence or interface to differentiate between them, or just separate the events based on their functionality, like UIEvents, DataEvents, CollisionEvents etc. Which you already do here.
Don't get me wrong. I don't have the answer and in fact I'm still searching for it. And this video showed me a new way, a clever way indeed, to change global variables when the event is raised and to read them when responding, because they happen sequentially anyways. And I will think about this, but just can't cope with editor drag&drop connections.

windwalkerrangerdm
Автор

great tutorial!! wish i found your channel earlier! liked and subscribed :)

ewwitsantonio
Автор

Great clean code and great example many thanks : D

skippythemagnificent
Автор

Static Class (lol)

You can add an argument to the event by deriving a generic version and marking it as serializable:
[Seriallizable] class PlayerEvent : UnityEvent<Player> { }

Though I don't find it very clean either.

Cyberfoxxy
Автор

pls add an auto subtitle for people who main language is not english :)

GameShorts
Автор

Seems like a big round about way of just requesting player ID and passing through player ID on collision update on collision get id of object i.e playerid player=player Id update event like what

DeathxStrike
Автор

Thank you for the great tutorial. My only problem with the code is like it defeats the purpose of having the event not care about the listener. Like if I want to create an event. The player must know what data and argument to pass in each listener. and is not good at handling multiple types of listeners that have different data needed but listen with the same event. Generics can solve it but add complexity in creating an event. But on in all great tutorial and help me in some concept in the scriptable object.

lAztechl
Автор

designing with globals is … .. real bad design

Alperic
Автор

Oh you mean what Unreal Engine has out of the box. Got it.

brannonharris