Skip to content

kadinche/Kassets

Repository files navigation

Kassets

openupm

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 Version

  • Unity 2020.3+
  • Note that this github project cannot be opened directly in Unity Editor. See Installation for cloning.

Dependencies

Getting Started

Installation

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 click Install
  • Select UniRx and click Install (Optional)
  • Select UniTask and click Install (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.

Importing UniRx and/or UniTask

Both UniRx and UniTask can be added either from OpenUPM or GitHub.

Creating Kassets' ScriptableObjects

Create an Event Instance

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/

CreateEvent

Create a Variable Instance

For Variables instances, select any of available types from Create/Kassets/Variables/

CreateVariable

Kassets' Variable instance on Inspector window

Screenshot 2023-06-12 at 16 34 50

Create Other Instances

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.

Using Kassets' ScriptableObject Instances

Usage on MonoBehavior Script

Create a MonoBehavior Script and add Kassets' instance as a serialized field.

Player.cs :

Screen Shot 2020-11-16 at 20 47 36 copy

HealthBarUI.cs :

Screen Shot 2020-11-16 at 21 06 10 copy

Drag and drop PlayerHealth (FloatVariable) to Player's Health field :

Screen Shot 2020-11-19 at 6 25 46

Drag and drop PlayerHealth (FloatVariable) to HealthBarUI's Health field :

Screen Shot 2020-11-19 at 6 26 08

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.

Usage on UnityEvents

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.

UnityEvent

UnityEventDynamic

Reactive with UniRx

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.

Screen Shot 2021-10-18 at 11 19 20

Asynchronous with UniTask

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())

Screen Shot 2021-10-18 at 11 40 16

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.

Using UniTask.Linq and its Usages with UniRx

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.

Screenshot 2023-06-12 at 16 49 31

References:

LICENSE