Using Cross-Scene Binding (Legacy) by Script
Before going straight into using Cross-Scene Binding in C#, let's be familiar on how to draw an Object Field using CommandGUI
first.
We will create a command that will print the name of the GameObject specified in the Object Field.
Create a new command script by opening the Assets menu and choose Create -> Sequine -> C# Command Script. Name the new file to LogGameObjectCommand (optional).
Drawing an Object Field
To draw an Object Field, let's first create a public GameObject field that will store the value.
From Creating Custom Command Type section, you might've been familiar that we should pass the field along with ref
keyword to draw the field. But to a draw field which the value is passed by reference such as Object Field, then instead of ref
keyword, we need to pass the current value, and the setter callback that will be invoked when the value is changed.
...
[System.Serializable]
public class LogGameObjectCommand : Command
{
public override float nodeWidth => 285;
public GameObject gameObjectToLog;
public override void Execute(CommandExecutionFlow _flow)
{
if (gameObjectToLog != null)
{
Debug.Log("The name is: " + gameObjectToLog.name);
}
Exit();
}
#if UNITY_EDITOR
public override void Editor_OnDrawContents(Vector2 _absPosition)
{
CommandGUI.DrawObjectField<GameObject>(
"GameObject to Log",
"The GameObject in which we print the name",
gameObjectToLog,
newGameObjectToLog => {
gameObjectToLog = newGameObjectToLog;
},
true);
}
#endif
}
CommandGUI.DrawObjectField
requires a type parameter to tell what kind of Unity Object the field stores. Here are the parameters:
- label: The label to be drawn inside the command node.
- tooltip: The tooltip which is shown when we hover the field.
- currentObject: The current object reference of the field.
- onObjectChanged: The callback that is invoked when the user changes the field. The callback requires 1 parameter which is the returned object that is selected by the user through the field.
- allowSceneObjects: Whether to allow choosing scene objects or not.
Notice that we set the allowSceneObjects
to true
. This is because we will try to get the GameObject without the Cross-Scene Binding first.
So, for now, make sure to create the command inside a Sequine Flow Component instead of Sequine Flow Asset or Sequine Flow Clip.
By now, you should've been able to simply set a GameObject from the hierarchy to the GameObject to Log
field. Try to set a GameObject, and play it.
Cross-Scene Components
Now let's say we use either Sequine Flow Asset or Sequine Flow Clip, then we can't simply access scene objects since they're not part of the scene.
We have to get the component object using a binder asset.
Creating a Cross-Scene Binder Asset
If you've been through Quick Start section, then you should've been familiar that we have a specific asset type called Cross Scene Binder Asset, even though a binder asset actually can be any kind of asset.
To create a Cross Scene Binder Asset, open the Assets menu and choose Create -> Sequine -> Cross Scene Binder Asset. Name the new file to preferably something that represents the object you're going to bind.
Binding a Component
From the hierarchy, select the GameObject you want to target. Add a Cross Scene Binder component from Inspector by clicking Add Component -> Sequine -> Cross Scene Binder.
Set the Binder Asset using the previously created binder asset.
A Cross Scene Binder can't get a GameObject, since it binds a Component instead. But that shouldn't be a problem since a Component can access its GameObject anyway.
Select a Component to Bind. In this case, we can just select any of the components.
Getting a Cross-Scene Component
Now let's get back to our LogGameObjectCommand.cs
script.
We can get our binded component using CrossSceneBindingUtility.GetObject
method, specifying the binder asset as the parameter. We can add a type parameter as well to specify to which type we should cast the object type.
Component bindedComponent = CrossSceneBindingUtility.GetObject<Component>(targetBinderAsset);
Here's how the full code would look like.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Calcatz.Sequine;
using Calcatz.CookieCutter;
[System.Serializable]
[RegisterCommand("Custom/LogGameObjectCommand", typeof(SequineFlowCommandData))]
public class LogGameObjectCommand : Command
{
public override float nodeWidth => 285;
public UnityEngine.Object targetBinderAsset;
public override void Execute(CommandExecutionFlow _flow)
{
if (targetBinderAsset != null)
{
Component bindedComponent = CrossSceneBindingUtility.GetObject<Component>(targetBinderAsset);
if (bindedComponent != null)
{
GameObject gameObjectToLog = bindedComponent.gameObject;
Debug.Log("The name is: " + gameObjectToLog.name);
}
}
Exit();
}
#if UNITY_EDITOR
public override void Editor_OnDrawContents(Vector2 _absPosition)
{
CommandGUI.DrawObjectField<UnityEngine.Object>(
"Target Binder",
"The GameObject in which we print the name",
targetBinderAsset,
newGameObjectToLog => {
targetBinderAsset = newGameObjectToLog;
},
false);
}
#endif
}
Notice that we changed the allowSceneObjects parameter of the CommandGUI.DrawObjectField
method to false
this time. This is because we want to intentionally prevent assigning a scene object to the Target Binder.
Since we've modified the type parameter of CommandGUI.DrawObjectField
to UnityEngine.Object
as well, it will also allows us to assign any kind of asset as the binder asset.
Lastly, using UnityEngine.Object
type to draw the Object Field might looks rough when we open the Select Object dialog. It will lists basically all assets that you have in your project. In that case, instead of UnityEngine.Object
, you can replace it with CrossSceneBinderAsset
type. That will also limit us to only be able to assign a Cross Scene Binder Asset as the Target Binder.
...
public class LogGameObjectCommand : Command
{
...
public CrossSceneBinderAsset targetBinderAsset;
...
public override void Editor_OnDrawContents(Vector2 _absPosition)
{
CommandGUI.DrawObjectField<CrossSceneBinderAsset>(
"Target Binder",
"The GameObject in which we print the name",
targetBinderAsset,
newGameObjectToLog => {
targetBinderAsset = newGameObjectToLog;
},
true);
}
...
}
Play It
We can setup the command simply by assigning our previously created binder asset to the Target Binder
field.
And now let's try to play it.
We see that we've successfully get the cross-scene binded object, and printed its name.
- You can alternatively use Singleton to access a scene object. This is more practical in certain cases since it doesn't require a setup for Cross-Scene Binding.
- Instead of using DrawObjectField, you can also use DrawBinderField to draw an Object Field that specifically made for Binder Asset so that we can directly drag and drop a GameObject from the scene, which will automatically get the Binder Asset from the Cross Scene Binder component.