Getting started
Before you start working with AlchemyBow.Core, you need to get to know 2 classes:
- CoreProjectContext - that is used to store shared dependencies within the global (project) scope. Most often, you should have one class that is derived from it and a prefab that stores its instance (at
Assets/*/Resources/Core/YourCoreProjectContextClassName.prefab
). - CoreController - that is used as a scene scope handle of the framework. You need to have at least one class that is derived from it and a game object that stores its instance on the starting scene.
Starting with the editor tools
The quick start core wizard is a tool that allows you to quickly create a basic configuration.
Click Window > AlchemyBow > Core > Quick Start Core.
Then select the destination folder, enter an optional namespace name, enter class names and decide whether to create a CoreProjectContext prefab and a CoreController instance.
For more advanced editing you can use the core management window.
Click Window > AlchemyBow > Core > Core Management to open it.
The window can operate in two modes:
Core Project Contexts - where you can review, select and quickly create CoreProjectContext scripts and prefabs.
Core Controllers - where you can review, select and quickly create CoreController scripts and scene instances.
Starting manually
Create a class that inherits from CoreProjectContext.
using AlchemyBow.Core;
using System.Collections.Generic;
public class MyCoreProjectContext : CoreProjectContext
{
protected override IEnumerable<ICoreLoadable> GetLoadables()
{
return null;
}
}
Then, create a prefab and put it in the Resources
folder under the path Core/NameOfYourCoreProjectContextClass
, e.g. Assets/Resources/Core/MyCoreProjectContext.prefab
.
Then, create a class that inherits from CoreController (use your project context type as a generic parameter).
using AlchemyBow.Core;
using System.Collections.Generic;
public class MyCoreController : CoreController<MyCoreProjectContext>
{
protected override IEnumerable<ICoreLoadable> GetLoadables()
{
return null;
}
}
Finally, create a new game object on the starting scene and attach your CoreController to it.
Life circle
If you followed the instructions in the previous section, you can press the play button. Nothing special will happen, but the framework is already working. The next steps are mostly about overriding abstract and virtual members of CoreController and CoreProjectContext. The best way to understand what they are responsible for is to analyze the life cycle of the framework.
1. Starting stage
At the Awake
message the CoreController starts. CoreController.OnStarted(OperationHandle)
is called. You can override this method to implement some early logic, for example to enable a loading screen. However, note that dependencies are not injected at this stage.
Tip
The OperationHandle parameter is used for methods that are expected to perform multi-frame operations. For example, in the OnStarted
method you can start a coroutine or a task in another thread. The CoreController will hold until OperationHandle.MarkDone()
is called.
2. Binding stage
This stage handles dependency injection.
At first, the CoreController ensures that the CoreProjectContext exists. If it doesn't, the following three steps are performed:
- The project context prefab is instantiated and moved to
DontDestroyOnLoad
. - The project context installs bindings from its MonoInstallers list and calls
CoreProjectContext.InstallAdditionalBindings
(you can override this method to add some custom binding logic). - All project context dependencies are resolved in its container.
Then, the contents of the CoreProjectContext.Container
are copied to the CoreController.Container
(dynamic collection bindings are sealed during the process).
Then, the CoreController installs bindings from its MonoInstallers list and calls CoreController.InstallAdditionalBindings
(you can override this method to add some custom binding logic).
Finally, the CoreController resolves all dependencies and calls CoreController.OnBindingFinished()
.
3. Loading stage
This stage is dedicated to performing operations that are potentially time consuming. It consists of the following steps:
- Wait for realtime seconds defined by
CoreController.PreLoadingDelay
. - Get loadables (ICoreLoadable) returned by
CoreProjectContext.GetLoadables()
(only during the first loading) andCoreController.GetLoadables()
(during each loading). - Load each loadable sequentially. (You can override
CoreController.OnLoadablesProgressed(LoadablesProgress)
to respond to the loading process progress. For example, to update your loading screen.) - Wait for realtime seconds defined by
CoreController.PostLoadingDelay
. - Wait for the previous scene to finish unloading (if any).
At the end, CoreController.OnLoadingFinished()
is called. The default implementation of this method triggers related callbacks from the ICoreLoadingCallbacksHandler.
(For details on ICoreLoadable and ICoreLoadingCallbacksHandler see Loading.)
4. Working stage
This stage defines what happens between loading and unloading. The recommended solution is to use a state machine (see: stateful behaviour). However, it is not mandatory, so you can use any method you like.
5. Unloading stage
This stage is the last phase of the scene scope life cycle (for CoreController). It starts when you call CoreController.ChangeScene(int)
and consists of the following steps:
CoreController.OnSceneChangeStarted()
- the default implementation of this method triggers related callbacks from the ICoreLoadingCallbacksHandler (see Loading for more details).CoreController.OnKeepUnloading(OperationHandle)
- you can override this method to smoothly clean up external resources (such as additional scenes).
Warning
If you use the UnityEngine.UI
package, add UnityEngine.EventSystems.EventSystem.current.enabled = false;
to the CoreController.OnSceneChangeStarted()
method. Otherwise, the event system may crash during the scene change process.