Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

UniState is a modern, high-performance, scalable state machine package for Unity.

License

NotificationsYou must be signed in to change notification settings

bazyleu/UniState

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Last ReleasesLast Release DateAll TestsLast CommitLicense

UniState is a modern, high-performance, scalable state machine package for Unity. It can serve as a core architecturalpattern or be used to address specific tasks.

  • Performance: optimized for minimal runtime allocations, seeperformance section for details.
  • Modularity: designed to definestates,substates, andstate machines in anisolated way. States can be easily replaced or removed without hidden effects even in big projects.
  • Scalability: memory allocations happen only on demand,performance does not degrade with the number ofstates and state machines.
  • Asynchronous: modern asynchronous API with async-await andUniTask
  • Reliability: allows you to defineglobal error handling at the state machine level,and guarantees that all resources will bedisposed.
  • Simplicity: if you usestate base you have to implement only one method for fast start.
  • Flexibility: everything in framework core is an abstraction. Can be replaced with your own implementation,seestate creating andcreating a state machine sections for details.
  • Testability: UniState is designed to be testable. All abstractions use interfaces that can be easily mocked withNSubstitutes or any other framework. States can be run separately for testingpurposes.
  • DI friendly: hasintegration with most popular DI containers

Table of Contents

Getting Started

Step 1:Install UniState by adding the following URL to Unity Package Manager:
https://github.com/bazyleu/UniState.git?path=Assets/UniState#1.1.0.
Details on installation are availablehere.

Step 2: Create a state by defining a class that inherits fromStateBase orStateBase<T>. Example transition logic:

publicclassMainMenuState:StateBase{publicoverrideasyncUniTask<StateTransitionInfo>Execute(CancellationTokentoken){// Add your state logic herereturnTransition.GoTo<GameplayState>();}}publicclassGameplayState:StateBase{publicoverrideasyncUniTask<StateTransitionInfo>Execute(CancellationTokentoken){// Add your state logic herereturnTransition.GoBack();}}

Detailed information about creating states isavailablehere.

Step 3: Configure Dependency Injection (DI) by registering the state machine and states in the DI container.

builder.RegisterStateMachine<StateMachine>();builder.RegisterState<MainMenuState>();builder.RegisterState<GameplayState>();

Additional information on DI configuration is availablehere.

Step 4: Create and run the state machine by specifying the initial state.

publicclassGame{privateIObjectResolver_objectResolver;privateCancellationTokenSource_ctx;publicasyncvoidRun(){varstateMachine=StateMachineHelper.CreateStateMachine<StateMachine>(_objectResolver.ToTypeResolver());awaitstateMachine.Execute<MainMenuState>(_ctx.Token);}}

More details on running the state machine can be foundhere.

That is it! Your first project with UniState is set up.

Installation

Requirements

  • Requires Unity version 2022.3 or higher.
  • Requires UniTask package installed. Guide regarding UniTask installation can be foundonCysharp/UniTask README.

Option 1: Add package from git URL

You can addhttps://github.com/bazyleu/UniState.git?path=Assets/UniState to Package Manager.

It is a good practice to specify target version, UniState uses the*.*.* release tag so you can specify a versionlike#1.1.0. For examplehttps://github.com/bazyleu/UniState.git?path=Assets/UniState#1.1.0.You can find latest version numberhere.

imageimage

Option 2: Add via manifest.json

You can add"com.bazyleu.unistate": "https://github.com/bazyleu/UniState.git?path=Assets/UniState" (or with versiontaghttps://github.com/bazyleu/UniState.git?path=Assets/UniState#1.1.0) toPackages/manifest.json.

Performance

UniState is the fastest and most efficient asynchronous state machine available for Unity. When compared to statemachine implementations based on MonoBehaviour, UniState delivers a performance boost of over 5000x in execution speedand up to a 10x reduction in allocations.

For typical scenarios involving small to medium state chains - the most common use case - UniState can reduce memoryallocations by a factor ranging between 2x and 10x. In cases where state chains exceed 200 states, the benefits inmemory allocation become less pronounced but execution speed remain consistent with 5000x+ boost.

Measurements for Windows PC (with IL2CPP scripting backend):

Benchmark Mono 10 states: 516.4 ms, 120.83 KBBenchmark Mono 50 states: 2520.9 ms, 150.44 KBBenchmark Mono 200 states: 10033.6 ms, 283.83 KBBenchmark UniState 10 states: 0.1 ms, 13.11 KBBenchmark UniState 50 states: 0.2 ms, 68.81 KBBenchmark UniState 200 states: 0.7 ms, 273.20 KBBenchmark UniState with history 10 states: 0.1 ms, 14.34 KBBenchmark UniState with history 50 states: 0.2 ms, 69.58 KBBenchmark UniState with history 200 states: 0.7 ms, 276.95 KB

Framework Philosophy

Dependency Injection

All dependencies for states, commands, and other entities should be passed through the constructor.UniState supports automatic integration with the most popular DI frameworks for Unity.Refer to theintegration documentation for more details.Dependencies must be registered in your DI framework, and they will automatically be resolved whencreatingstate,state machine.

What is a State?

A state is an abstraction that represents a specific condition or phase of the game, often corresponding to a "screen" that the user interactswith. For example, the main menu is a state, a settings popup is another state, and gameplay itself may take place in aseparateGameplayState. When the user opens a shop popup, they may transition into aShopState. However, states arenot always tied to visual elements. Some states, likeGameLoadingState, may handle background processes such asloading resources.

State class contains all logic related to that state including loading and unloading resources. UniState does not restrict the use of otherframeworks or patterns, meaning you can freely use whatever suits your needs. You could, for example, run controllersand follow an MVC approach, follow MVVM approach, or even execute ECS code within a state.

The key concept of the framework is that once a state is exited, all resources it allocated should be released. Fordetails on how to do this seeDisposables.

It is not recommended to use Unity GameObjects directly inside states, as it reduces testability and increases codecoupling. A better approach is to load GameObjects through an abstraction and use them as an interface (essentially as aView in UniState). Add a handler for unloading to the Disposables of the state that loaded it. All approaches / patternswhich were mentioned above support this, and you can choose any based on your preferences, as this functionality isoutside the scope of UniState.

//Popup prefab (Monobehaviour, view)publicclassSimplePopupView:ISimplePopupView,Monobehaviour{//...}// Simple popup state examplepublicclassSimplePopupState:StateBase{privateISimplePopupView_view;publicoverrideasyncUniTaskInitialize(CancellationTokentoken){_view=LoadPopupView(token);Disposables.Add(UnloadShopView);}publicoverrideasyncUniTask<StateTransitionInfo>Execute(CancellationTokentoken){await_view.Show(token);await_view.WaitForClick(token);returnTransition.GoBack();}publicoverrideasyncUniTaskExit(CancellationTokentoken){await_view.Hide(token);}// The implementation of this method depends on other frameworks/patterns used in the project.privateISimplePopupViewLoadShopView(CancellationTokentoken){// Loading logic}privatevoidUnloadShopView(){// Unloading logic}}

If the popup is complex with multiple features, it could be represented as its own state machine.In cases where you have a complex popup with its own state machine, it’s important to allocate resources specific to the popup before launching the separatestate machine, ensuring they are properly cleaned up after the state machine exits.

// This state loads resources, adds them to Disposables, and runs the internal state machine for ShopPopup.// When the StateMachine completes its execution, RootShopPopupState finishes and releases its resources.publicclassRootShopPopupState:StateBase{publicoverrideasyncUniTaskInitialize(CancellationTokentoken){// Load ShopView (a Unity GameObject) and create an IDisposable handler that// will unload the GameObject after Disposing.// After that, the GameObject will be available as IShopView in internal states.vardisposable=LoadShopView();Disposables.Add(disposable);}publicoverrideasyncUniTask<StateTransitionInfo>Execute(CancellationTokentoken){varstateMachine=StateMachineFactory.Create<StateMachine>();// Run the internal state machine for ShopPopup.// In all states inside this state machine, all resources allocated in this state will be available.awaitstateMachine.Execute<ShopPopupIdleState>(cts.Token);returnTransition.GoBack();}// The implementation of this method depends on other frameworks/patterns used in the project.privateIDisposableLoadShopView(){// Loading logic}}publicclassShopPopupIdleState:StateBase{// IShopView is a Unity GameObject loaded in RootShopPopupState (outside the current state machine).// IShopView will be available as long as RootShopPopupState is running,// meaning throughout the entire internal state machine's operation.privateIShopView_view;publicShopPopupIdleState(IShopViewview){_view=view;}publicoverrideasyncUniTask<StateTransitionInfo>Execute(CancellationTokentoken){varaction=await_view.Show(token);// Transition logic with 'action'}}

API Details and Usage

State

A state is a fundamental unit of logic in an application, often representing different screens or states, such as anidle scene, main menu, popup, or a specific state of a popup.

State Creating

To create your custom state, you can inherit fromStateBase orStateBase<T>. UseStateBase<T> if you need to passparameters to the state.

For highly customized states, you can manually implement theIState<TPayload> interface. However, in mostcases,StateBase will suffice.

// Simple State InheritancepublicclassFooState:StateBase{publicoverrideasyncUniTask<StateTransitionInfo>Execute(CancellationTokentoken){// State logic here}}// State with ParameterspublicclassFooStateWithPayload:StateBase<FooPayload>{publicoverrideasyncUniTask<StateTransitionInfo>Execute(CancellationTokentoken){// Get payloadFooPayloadpayload=Payload;// State logic with payload here}}//Custom State ImplementationpublicclassCustomFooState:IState<MyParams>{publicasyncUniTaskInitialize(CancellationTokentoken){// Initialization logic}publicasyncUniTask<StateTransitionInfo>Execute(MyParamspayload,CancellationTokentoken){// Execution logic with payload}publicasyncUniTaskExit(CancellationTokentoken){// Exit logic}publicvoidDispose(){// Cleanup logic}}

State Lifecycle

The lifecycle of a state consists of four stages, represented by the following methods:

  1. Initialize

    • Used for initializing resources, such as loading prefabs, subscribing to events, etc.
  2. Execute

    • The only method that must be overridden inStateBase. It contains the main logic of the state and remains activeuntil it returns a result with a transition to another state. For example, a state displaying a popup might waitfor button presses and handle the result here. See theState Transitions section for moredetails.
  3. Exit

    • Completes the state's work, such as unsubscribing from buttons and closing the popup (e.g., playing a closinganimation).
  4. Dispose

    • Cleans up resources. If you inherit fromStateBase, this method does not need implementation.

State Transitions

TheExecute method of a state should return aStateTransitionInfo object, which dictates the next actions of thestate machine. To simplify its generation, you can use theTransition property inStateBase. The possible transitionoptions are:

  1. GoTo

    • Used to transition to another state. If the state contains a payload, it should be passed toGoTo.
  2. GoBack

    • Returns to the previous state. If there is no previous state (the current state is the first), it will exit thestate machine. See theState Machine section for more details.
  3. GoToExit

    • Exits the current state machine. See theState Machine section for more details.
publicclassExampleState:StateBase{publicoverrideasyncUniTask<StateTransitionInfo>Execute(CancellationTokentoken){vartransition=awaitDoSomeAsyncLogic(token);switch(transition){caseTransitionExample.GoTo:returnTransition.GoTo<FooState>();caseTransitionExample.GoToWithPayload:varpayload=42;returnTransition.GoTo<BarState,int>(payload);caseTransitionExample.GoToAbstract:returnTransition.GoTo<IFooState>();caseTransitionExample.GoBack:returnTransition.GoBack();caseTransitionExample.GoToExit:returnTransition.GoToExit();default:returnTransition.GoToExit();}}privateUniTask<TransitionExample>DoSomeAsyncLogic(CancellationTokentoken){// Some logic herereturnUniTask.FromResult(TransitionExample.GoTo);}}

Disposables

Disposables are a part ofStateBase that allow users to tieIDisposable references and delegates to state'slifetime, guaranteeing disposal and delegate execution on state'sDispose, without overriding the method

publicclassLoadingState:StateBase<ILoadingScreenView>{privateCancellationTokenSource_loadingCts;publicoverrideasyncUniTask<StateTransitionInfo>Execute(CancellationTokentoken){// State's disposable references_loadingCts=CancellationTokenSource.CreateLinkedTokenSource(token);Disposables.Add(_loadingCts);// Handling of subscriptions with locality of behaviourPayload.CancelClicked+=OnCancelLoadingClicked;Disposables.Add(()=>Payload.CancelClicked-=OnCancelLoadingClicked);try{awaitPayload.PretendToWork(_loadingCts.Token);}catch(OperationCancelledException)when(!token.IsCancellationRequested){returnTransition.GoBack();}returnTransition.GoTo<NextState>();}privatevoidOnCancelLoadingClicked(){_loadingCts.Cancel();}}

State Behavior Attribute

It is possible to customize the behavior of a specific state using theStateBehaviour attribute.

This attribute has the following parameters:

  • ProhibitReturnToState (default value: false): When enabled, this state cannot be returned toviaTransition.GoBack(). The state with this attribute will be skipped, and control will return to the state beforeit. This behavior can be useful for states that represent 'loading', there is no point of returning to loading.

  • InitializeOnStateTransition (default value: false): When enabled, the initialization of the state will beginbefore exiting the previous state. Technically, this meansInitialize() of the state will be called beforeExit()of the previous state. This behavior can be useful for seamless transitions in complex animations, where the staterepresents only part of the animation.

[StateBehaviour(ProhibitReturnToState=true)]publicclassFooState:StateBase{//...}[StateBehaviour(InitializeOnStateTransition=true)]publicclassBarState:StateBase{//...}[StateBehaviour(InitializeOnStateTransition=true,ProhibitReturnToState=true)]publicclassBazState:StateBase{//...}

State Machine

The state machine is the entry point into the framework, responsible for running states.

Creating a State Machine

To create the initial state machine, use thehelperStateMachineHelper.CreateStateMachine<TSateMachine>(ITypeResolver typeResolver).

  • TSateMachine: Any class implementingIStateMachine. You can use the standardStateMachine or create customones by inheriting fromStateMachine or implementingIStateMachine.

  • ITypeResolver: Used to create the state machine. It acts as a factory for creating states and other statemachines. You can implement it yourself or use the provided implementation from DI frameworks like VContainer orZenject via the.ToTypeResolver() extension. SeeIntegrations for supported frameworksorCustom type resolvers for cases if you DI framework is not supported out of the box oryou do not have DI framework.

Running a State Machine

After creating the state machine, you can run it with the specified state:

awaitstateMachine.Execute<FooState>(cts.Token);varpayload=newBarPayload();awaitstateMachine.Execute<BarState>(payload,cts.Token);

Creating and Running a State Machine Inside States

Any state can create and run a state machine within itself using theStateMachineFactory property. This is therecommended method for creating a state machine inside a state.

ITypeResolver_newContext;publicUniTask<StateTransitionInfo>Execute(CancellationTokentoken){varstateMachine=StateMachineFactory.Create<StateMachine>();awaitstateMachine.Execute<FooState>(cts.Token);varstateMachineWithNewContext=StateMachineFactory.Create<StateMachine>(_newContext);awaitstateMachineWithNewContext.Execute<FooState>(cts.Token);    ...}

State Machine History

The state machine maintains a history of transitions between states, allowing for the use ofTransition.GoBack(). Thesize of this history can be customized through theStateMachineLongHistory.MaxHistorySize property (default value is15). If more transitions occur than the history size, only the most recent transitions will be retained, with nooverhead or errors resulting from the limit.

SettingMaxHistorySize = 0 disables the history, causingTransition.GoBack() to exit the state machine directly.

publicclassStateMachineWithDisabledHistory:StateMachine{protectedoverrideintMaxHistorySize=>0;}

State Machine Error Handling

In UniState, state machine error handling can be customized to control how exceptions within states are processed. Theprimary mechanism for this is theHandleError() method, which you can override in your custom state machine. Thismethod is called whenever an exception occurs, allowing you to define specific logic to handle errors.

Exceptions are caught and processed internally without propagating further, except forOperationCanceledException,which will stop the state machine.StateMachineErrorData provides metadata related to exceptions, andStateMachineErrorData.State may benull ifStateMachineErrorType is set toStateMachineFail.

publicclassBarStateMachine:StateMachine{protectedoverridevoidHandleError(StateMachineErrorDataerrorData){// Custom logic here}}

To halt state machine execution after an exception, include athrow statement inHandleError():In the example provided, the state machine will terminate after encountering a second exception within the same state in a row.

publicclassFooStateMachine:StateMachine{privateType_lastErrorState;protectedoverridevoidHandleError(StateMachineErrorDataerrorData){varstateType=errorData.State?.GetType();if(stateType!=null&&_lastErrorState==stateType){// Stop state mahine execution and throw an exception outthrownewException($"Second exception in same state.",errorData.Exception);}_lastErrorState=stateType;}}

If an exception is encountered in a state’sInitialize() orExit() methods, the state machine will continue working.However, if an exception occurs in the state’sExecute() method, the state machine defaults to aGoBack() operation, as thoughTransition.GoBack() were returned. You can override this behavior by customizingBuildRecoveryTransition, which receives anIStateTransitionFactory to specify any desired transition for errorrecovery.

When an exception occurs inExecute(),HandleError will be invoked first, followed byBuildRecoveryTransition.

publicclassBarStateMachine:StateMachine{// If exception occurs in the state in the Execute() method, the state machine will go to the ErrorPopupState.protectedoverrideStateTransitionInfoBuildRecoveryTransition(IStateTransitionFactorytransitionFactory)=>transitionFactory.CreateStateTransition<ErrorPopupState>();}

State Machine Custom Interface

When creating a state machine, you can use your custom interface. Interface should be inherit fromIStateMachine. Thisallows to implement additional, customized behavior.

publicinterfaceIExtendedStateMachine:IStateMachine{publicvoidRunCustomLogic();}

Once your custom interface is implemented, you can utilize a special version of the API that returns your interface.This can be useful for adding custom logic to the state machine.

// Option 1: Creating ExtendedStateMachine as entry pointvarstateMachine=StateMachineHelper.CreateStateMachine<ExtendedStateMachine,IExtendedStateMachine>(typeResolver);// Option 2: Creating ExtendedStateMachine inside statesvarstateMachine=StateMachineFactory.Create<ExtendedStateMachine,IExtendedStateMachine>();// Custom state machine has extended api that is defined by IExtendedStateMachine interfacestateMachine.RunCustomLogic();// Custom state machine can run states like default state machineawaitstateMachine.Execute<FooState>(cancellationToken);

State Machine Context

UniState natively supports sub-containers and sub-contexts available in modern DI frameworks.

When creating a state machine inside a state, you can use two method overloads:

  • StateMachineFactory.Create<TSateMachine>()
  • StateMachineFactory.Create<TSateMachine>(ITypeResolver typeResolver)

If the version withoutITypeResolver is used, the context is inherited from the parent state machine.IfITypeResolver is passed, it will have a new context.

For smaller projects, it's recommended to use the simplified version without creating a new context:

StateMachineFactory.Create<TSateMachine>();

For larger projects using sub-containers/sub-contexts in your DI framework to manage resources more efficiently, you canpass them intoCreate to force the state machine to use them for creating states and dependencies. Thus, UniStatesupports this natively without additional actions required from you.

Custom type resolvers

While UniState providesITypeResolver implementations for modern DI frameworks out of the box, you can create custom implementations, tailored to your needs

An example ofITypeResolver with automatic state bindings for Zenject/Extenject:

publicclassZenjectAutoBindTypeResolver:ITypeResolver{    ...publicobjectResolve(Typetype){if(!type.IsAbstract&&!type.IsInterface&&!_container.HasBinding(type)){_container.BindState(type);}return_container.Resolve(type);}}

If you do not have DI framework you have to implement ITypeResolver by your own by manually creating requested states andstate machines.

Composite State

Composite State is essential for complex areas of an application likely to be worked on by multiple peoplesimultaneously. They consist of various independent sub states, each with its own logic.

Creating a Composite State

To create a composite state, inherit fromCompositeStateBase (or implement theICompositeState interface for moredetailed control). You can also use the ready-made implementationDefaultCompositeState (seetheDefaultCompositeState section). No additional actions are needed.

SubState

SubStates are states tied to a composite state, created and run simultaneously with it. To create a SubState, inheritfromSubStateBase or implement theISubState interface for greater customization. When creating a sub state, specifythe parent composite state as a generic parameter, e.g.,FooSubState : SubStateBase<BarCompositeState>. In all otheraspects, it functions like a regular state.

Default Composite State

A ready-to-use implementation for a composite state that propagatesInitialize,Execute, andExit methods to allSubStates within it. The result of theExecute method will be the first completedExecute method among all substates.

If you useDefaultCompositeState and it is executed without any SubStates, itsExecute method will throwanInvalidOperationException.

To useDefaultCompositeState, simply inherit your composite state from it. Here's an example:

internalclassFooCompositeState:DefaultCompositeState{}internalclassBazSubState:SubStateBase<DefaultCompositeState>{}internalclassBarSubState:SubStateBase<DefaultCompositeState>{}

Integrations

UniState supports integrations with the most popular DI containers. If these frameworks are installed via UPM,everything will work out of the box, and no additional actions are required.

VContainer

GitHub:VContainer

VContainer Preparation

If the VContainer is installed via UPM, you can skip this step and proceed to theVContainer Usagesection.If the package is not installed via UPM, you need to manually add theUNISTATE_VCONTAINER_SUPPORT define symbol inScripting Define Symbols (Player Settings -> Player -> Scripting Define Symbols).

VContainer Usage

To use it, convertVContainer.IObjectResolver toUniState.ITypeResolver by calling the extensionToTypeResolver()and pass it to the state machine.

// Object resolver with main or child scope from VContainerVContainer.IObjectResolver_objectResolver;// Convert VContainer.IObjectResolver to ITypeResolver.TypeResolvervartypeResolver=_objectResolver.ToTypeResolver();// Create state machine with VContainer supportvarstateMachine=StateMachineHelper.CreateStateMachine<StateMachine>(typeResolver);

VContainer Registering

All state machines, states and their dependencies should be registered in DI container.For convenient registering of states and state machines, special extension methods are available. The main onesareRegisterStateMachine andRegisterState, which register both the classes themselves and all interfaces implemented bythese classes.

However, if you need to implement a transition into a state or launch a state machine via a base/abstract class, youshould useRegisterAbstractStateMachine andRegisterAbstractState.

Here's an example code:

privatevoidRegisterStates(IContainerBuilderbuilder){// Use this registration creating state machine via class or interface.// For example: StateMachineHelper.CreateStateMachine<BarStateMachine>(...)// For example: StateMachineHelper.CreateStateMachine<IBarStateMachine>(...)builder.RegisterStateMachine<BarStateMachine>();// Use this registration creating state machine via base/abstract class.// For example: StateMachineHelper.CreateStateMachine<FooStateMachineBase>(...)builder.RegisterAbstractStateMachine<FooStateMachineBase,FooStateMachine>();// Use this registration for transitions to class or interface.// For example: Transition.GoTo<BarState>() or Transition.GoTo<IBarState>()builder.RegisterState<BarState>();// Use this registration for transitions to base/abstract class.// For example: Transition.GoTo<FooStateBase>()builder.RegisterAbstractState<FooStateBase,FooState>();// Singleton version of states, not recommended in general use, but can be handy in some casesbuilder.RegisterStateMachine<BarStateMachine>(Lifetime.Singleton);builder.RegisterAbstractStateMachine<FooStateMachineBase,FooStateMachine>(Lifetime.Singleton);builder.RegisterState<BarState>(Lifetime.Singleton);builder.RegisterAbstractState<FooStateBase,FooState>(Lifetime.Singleton);}

You can always skip the extensions and register directly if you need custom behavior.

Zenject (Extenject)

GitHub:Extenject orZenject

Zenject Preparation

If the Zenject / Extenject is installed via UPM, you can skip this step and proceed totheZenject Usage section.If the package is not installed via UPM, you need to manually add theUNISTATE_ZENJECT_SUPPORT define symbol inScripting Define Symbols (Player Settings -> Player -> Scripting Define Symbols).

Zenject Usage

To use it, convertZenject.DiContainer toUniState.ITypeResolver by calling the extensionToTypeResolver() andpass it to the state machine.

// Zenject container / sub containerZenject.DiContainercontainer;// Convert Zenject.DiContainer to ITypeResolver.TypeResolvervartypeResolver=container.ToTypeResolver();// Create state machine with Zenject supportvarstateMachine=StateMachineHelper.CreateStateMachine<StateMachine>(typeResolver);

Zenject Registering

All state machines, states and their dependencies should be registered in DI container.For convenient registering of states and state machines, special extension methods are available. The main onesareBindStateMachine andBindState, which bind both the classes themselves and all interfaces implemented bythese classes.

However, if you need to implement a transition into a state or launch a state machine via a base/abstract class, youshould useBindAbstractStateMachine andBindAbstractState.

Here's an example code:

privatevoidBindStates(DiContainercontainer){// Use this registration creating state machine via class or interface.// For example: StateMachineHelper.CreateStateMachine<BarStateMachine>(...)// For example: StateMachineHelper.CreateStateMachine<IBarStateMachine>(...)container.BindStateMachine<BarStateMachine>();// Use this registration creating state machine via base/abstract class.// For example: StateMachineHelper.CreateStateMachine<FooStateMachineBase>(...)container.BindAbstractStateMachine<FooStateMachineBase,FooStateMachine>();// Use this registration for transitions to class or interface.// For example: Transition.GoTo<BarState>() or Transition.GoTo<IBarState>()container.BindState<BarState>();// Use this registration for transitions to base/abstract class.// For example: Transition.GoTo<FooStateBase>()container.BindAbstractState<FooStateBase,FooState>();// Singleton version of states, not recommended in general use, but can be handy in some casescontainer.BindStateMachineAsSingle<BarStateMachine>();container.BindAbstractStateMachineAsSingle<FooStateMachineBase,FooStateMachine>();container.BindStateAsSingle<BarState>();container.BindAbstractStateAsSingle<FooStateBase,FooState>();}

License

This library is under the MIT License. Full text ishere.


[8]ページ先頭

©2009-2025 Movatter.jp