IN THIS ARTICLE
Implementing Node Behavior
Implementing Node Behavior
After you have defined the topology for the node, you can focus on implementing the behavior for the node.
Adding Slots
In addition to using AZ Code Generator to set up the node’s topology, it is also possible to manually add execution and/or data slots if preferred. The following example from the IsNull logic node adds a Reference input slot for data reference and an Is Null output slot. The output slot returns a Boolean value depending on the evaluation of the data that was input. The source code is in the location \dev\Gems\ScriptCanvas\Code\Include\ScriptCanvas\Libraries\Logic\IsNull.cpp
.
void IsNull::OnInit()
{
AZStd::vector<ContractDescriptor> contracts;
auto func = []() { return aznew IsReferenceTypeContract(); };
ContractDescriptor descriptor{ AZStd::move(func) };
contracts.emplace_back(descriptor);
AddInputDatumUntypedSlot("Reference", &contracts);
AddOutputTypeSlot("Is Null", "", AZStd::move(Data::Type::Boolean()), OutputStorage::Optional);
}
When the node is initialized, the added slots appear in the Script Canvas editor.
Receiving Input Signals
Nodes can receive input signals when a node’s execution slot is triggered. To detect which signal has been triggered, implement OnInputSignal
, as in the following example.
void OnInputSignal(const SlotId&) override;
To get the ID of the input signal, AZ Code Generator provides some convenient helper functions in a namespace that corresponds to the generated node. These helper functions make it easier to access the node’s properties and slot IDs.
As an example, in the Delay node two input slots can be signaled: In and Reset.
In the following code, the Delay node’s In and Reset slots use the generated helper functions CountdownProperty::GetInSlotId(this)
; and CountdownProperty::GetResetSlotId(this)
; to get their IDs. The source code is from dev\Gems\ScriptCanvas\Code\Include\ScriptCanvas\Libraries\Time\Countdown.cpp
.
void Countdown::OnInputSignal(const SlotId& slot)
{
const SlotId& inSlotId = CountdownProperty::GetInSlotId(this);
const SlotId& resetSlotId = CountdownProperty::GetResetSlotId(this);
if (slot == resetSlotId || (slot == inSlotId && !AZ::TickBus::Handler::BusIsConnected()))
{
// Disconnect required when resetting
AZ::TickBus::Handler::BusDisconnect();
m_countdownSeconds = CountdownProperty::GetTime(this);
m_looping = CountdownProperty::GetLoop(this);
m_holdTime = CountdownProperty::GetHold(this);
m_currentTime = m_countdownSeconds;
AZ::TickBus::Handler::BusConnect();
}
}
You can use these IDs to determine what action the node should take.
Sending Output Signals
After the Delay node is finished, it uses the SignalOutput(outSlot)
function to signal the output slot that execution is ready to continue.
To call the function, you must know the output slot ID to pass. The following example is from Duration.cpp
.
const SlotId doneSlot = DurationProperty::GetDoneSlotId(this);
[...]
SignalOutput(doneSlot);
Note
If your node is connected to one or more buses during its lifetime, ensure that it disconnects from those buses before it exits. Otherwise, your node might be handling events that it no longer should.
Querying Inbound Data
The Delay node example has the inbound data slots Time, Loop, and Hold.
Script Canvas properties that specify the ScriptCanvas_Property::Input
attribute can be queried by the node to do necessary processing. To do this, use the code-generated convenience helpers CountdownProperty::Get{PropertyName}(this);
. The following source code is in dev\Gems\ScriptCanvas\Code\Include\ScriptCanvas\Libraries\Time\Countdown.cpp
.
m_countdownSeconds = CountdownProperty::GetTime(this);
m_looping = CountdownProperty::GetLoop(this);
m_holdTime = CountdownProperty::GetHold(this);
You can often use these properties on the stack; you do not have to assign these properties to member variables. In the Delay node example, member variables are used to cache the values.
Sending Outbound Data
Many nodes might want to return a value or push forward data as a result of a computation. In the Delay node example, the Elapsed slot outputs the elapsed time.
To output the elapsed time, the node gets the ID of the Elapsed slot and then pushes a data value into it (dev\Gems\ScriptCanvas\Code\Include\ScriptCanvas\Libraries\Time\Countdown.cpp
).
const SlotId elapsedSlot = CountdownProperty::GetElapsedSlotId(this);
Datum o(Data::Type::Number(), Datum::eOriginality::Copy);
o.Set(m_elapsedTime);
if (auto* slot = GetSlot(elapsedSlot))
{
PushOutput(o, *slot);
}
Serializing “Hidden” Node Properties
In some cases you might want your node to serialize its properties but not expose them as slots on a node. In this case, the Property
and EditProperty
tags are useful.
You can use the Property
tag to serialize any property without exposing it to the node’s property grid. Because it is not exposed, it is not user configurable.
The EditProperty
tag both serializes and provides an EditContext
for the specified property. This makes the property user configurable through the node’s property grid.