Kassets is an implementation of Scriptable Object Architecture. Scriptable Object Architecture provides a clean and decoupled code architecture. It is implemented based on Ryan Hipple talk on Unite Austin 2017.
Kassets can be used independently. However, Kassets was originally made as an attempt to extend functionality of UniRx and UniTask into ScriptableObjectArchitecture. So, it is recommended and would be more effective to use Kassets along with [UniRx], [UniTask], or both. To use them, simply import any or both of these library along with Kassets.
UniRx is a Reactive Extensions for Unity.
UniTask provides an efficient allocation free async/await integration to Unity.
- Unity 2020.3+
- Note that this github project cannot be opened directly in Unity Editor. See Installation for cloning.
Add from OpenUPM | import via scoped registry, update from Package Manager
To add OpenUPM to your project:
- open
Edit/Project Settings/Package Manager
- add a new Scoped Registry:
Name: OpenUPM
URL: https://package.openupm.com/
Scope(s):
- com.kadinche
- com.neuecc.unirx (optional)
- com.cysharp.unitask (optional)
- click Save
- open Package Manager
- Select
My Registries
in top left dropdown - Select
Kassets
and clickInstall
- Select
UniRx
and clickInstall
(Optional) - Select
UniTask
and clickInstall
(Optional)
Add from GitHub | cannot updates through Package Manager Updates are now possible on Unity 2021.2 or later!
Add package directly from GitHub on Unity 2019.4+. You won't be able to receive updates through Package Manager this way, you'll have to update manually.
- open Package Manager
- click +
- select Add from Git URL
- paste
https://github.com/kadinche/Kassets.git
- click Add
Clone to Packages Folder | for those who want to make and manage changes
Clone this repository to Unity Project's Packages directory.
Modify source codes from containing Unity Project. Update changes to/from github directly just like usual github project. You can also clone the project as Submodule.
- clone this project using https: https://github.com/kadinche/Kassets.git
- clone this project using ssh: git@github.com:kadinche/Kassets.git
- clone this project to YourUnityProject/Packages/
Importing UniRx and/or UniTask
Both UniRx and UniTask can be added either from OpenUPM or GitHub.
- scope on openupm:
- package link on github:
- for more detailed information, please look at the respective github pages.
Kassets instances can be created from Create context menu or from Assets/Create menu bar. Simply right click on the Project window and select any instance to create. For Event instances, select any of event types from Create/Kassets/Game Events/
For Variables instances, select any of available types from Create/Kassets/Variables/
Kassets' Variable instance on Inspector window
Other available Kassets' Scriptable Object are
- Command. Class that contains an executable method.
- Collection. Can be either a List or Dictionary.
- ExchangeEvent. A Request-Response event.
Create a MonoBehavior
Script and add Kassets' instance as a serialized field.
Player.cs
:
HealthBarUI.cs
:
Drag and drop PlayerHealth
(FloatVariable
) to Player
's Health
field :
Drag and drop PlayerHealth
(FloatVariable
) to HealthBarUI
's Health
field :
From example above, Player
component's field Health
and HealthBarUI
component's field Health
both refer to the same FloatVariable ScriptableObject instance PlayerHealth
. Since both component refer to the same variable instance, the float
value they refer to is shared. Each component then manage their own need with the value without any coupling between components. I.e. HealthBarUI
doesn't have to request the Health
value to Player
component and Player component can manage its own Health
without the need to distribute its value to other components.
Kassets’s instance is a ScriptableObject asset. It can be referenced to UnityEvent via Inspector. You can aslo use dynamic method call on UnityEvent to pass a parameter.
If you had UniRx imported, you can use Reactive on Kassets' instances. First, make sure to import UniRx to your project. Upon import, Kassets will adjust internally to support UniRx using scripting define KASSETS_UNIRX
. It would normally be defined when UniRx is imported using package manager. If somehow KASSETS_UNIRX
is undefined, add it to Scripting Define Symbols
on Project Settings.
When importing UniRx, Kassets' GameEvent becomes Observable
. To use Kassets reactively, simply Subscribe
to a GameEvent instances or its derivation.
If you had UniTask imported, you can use Asynchronous on Kassets' instances. First, make sure to import UniTask to your project. Upon import, Kassets will adjust internally to support UniTask using scripting define KASSETS_UNITASK
. It would normally be defined when UniTask is imported using package manager. If somehow KASSETS_UNITASK
is undefined, add it to Scripting Define Symbols
on Project Settings.
To use Kassets Asynchronously, use the method EventAsync()
and add await
in front of it. Any Kassets' instances that derived from GameEvent can be used asynchronously. (For Command, use method ExecuteAsync()
)
In the example above, an asynchronous operation EventAsync()
on variable means to wait for its value to change. GameEvent in general, will wait for an event to fire.
According to this slide (Japanese), It is a best practice to always use cancellation token on every UniTask's asynchronous operation. Since Unity is not asynchronous, any asynchronous operation can be left behind waiting infinitely when the process is not stopped.
UniTask v2 has support for Asynchronous LINQ. Asynchronous LINQ is an extension to IUniTaskAsyncEnumerable<T>
and its usage can be very similar to UniRx, but the process behind it is different (UniRx is push-based while UniTask is pull-based).
Kassets' ScriptableObject
also make use of Asynchronous LINQ. Kassets' ScriptableObject
derived from IUniTaskAsyncEnumerable<T>
so it is possible to directly apply various features of UniTask as explained in its github page or from this slide (Japanese).
As an example, the sample class CounterAttackSkill
above used SubscribeAwait
which is part of UniTask.Linq. Since it is pull-based, when the process of OnCounterActivate
is still running, it won't be called again until it is over no matter how many times the event has been raised during the process. Reversely, push-based will execute every event raise.
When both UniRx and UniTask are imported together, It can be confusing which of the Subscription
behavior is in effect (pull-based or push-based?). To use Kassets' instance as IObservable
, use AsObservable()
. To use Kassets' instance as IUniTaskAsyncEnumerable
use AsAsyncEnumerable()
. Unless referenced by interface, Kassets instances Default Subscribe Behavior can be selected from the inspector window.
Note that UniTask Asynchronous LINQ is part of Cysharp.Threading.Tasks.Linq
namespace. To use, add UniTask.Linq
as reference to your project's Assembly Definition.
- https://github.com/neuecc/UniRx
- https://github.com/Cysharp/UniTask
- https://speakerdeck.com/torisoup/unitask2020 (Japanese/日本語)
- https://github.com/roboryantron/Unite2017
- https://www.slideshare.net/RyanHipple/game-architecture-with-scriptable-objects
- https://forpro.unity3d.jp/unity_pro_tips/2019/07/27/57/ (Japanese/日本語)
- Kassets is Licensed under MIT License
- UniRx is Licensed under MIT License
- UniTask is Licensed under MIT License