Behaviour Graph Events to GameObjects without Behaviour Graphs

Hi there, I’ve been looking at Behaviour package with specific regard to events. I appreciate you can send events to other behaviours using ‘Send Event Message’, but is there a way for:

  • A Behaviour Graph to send a message to other gameObjects that do not use a behaviour graph (so just picked up in a monobehaviour)
  • And vice versa, gameObjects without behaviour graphs, sending events via a monobehaviour to other gameobject’s behaviour graphs

Thanks for any pointers!

Hi @AntLewis

Thank you for your interest!
This is an area we are aware is missing documentation at the moment. We currently working with the documentation team to fill that gap.

In the meantime here are 2 different approaches you could use to achieve communication between Behavior Graphs and C# systems/components.

C# binding to a particular instance of BehaviorGraphAgent

You can get a reference to a BlackboardVariable from a BehaviorGraphAgent using the BehaviorGraphReference API.
You can then subscribed to the BlackboardVariable.OnValueChanged event or in the case of an EventChannel, subscribe to BlackboardVariable.Value.Event event.

Sample code
[SerializeField] private BehaviorGraphAgent m_Agent;

// Agent state has changed to [value] (where value is of type StateExample)
private BlackboardVariable<StateEventChannel> m_stateEventChannelBBV;
private BlackboardVariable<StateExample> m_stateBBV;

private void OnEnable()
{
    if (m_Agent.BlackboardReference.GetVariable("StateEventChannel", out m_stateEventChannelBBV))
        m_stateEventChannelBBV.Value.Event += OnStateEvent;

    if (m_Agent.BlackboardReference.GetVariable("StateToReact", out m_stateBBV))
        m_stateBBV.OnValueChanged += OnStateValueChanged;
}

private void OnDisable()
{
    if (m_stateEventChannelBBV != null)
        m_stateEventChannelBBV.OnValueChanged -= OnStateChanged;
    if (m_stateBBV != null)
        m_stateBBV.OnValueChanged -= OnStateValueChanged;
}

private void Update()
{
    // your custom logic

    // Send event to the event channel of the referenced agent.
    // Only this instance of agent will receive it (except if the BlackboardVariable is 'Shared').
    m_stateEventChannelBBV.Value.SendEventMessage(StateExample.Alert);
}

private void OnStateEvent(StateExample value)
{
    // React to event
}

private void OnStateValueChanged()
{
    // React to state change
}

C# binding using Event Channel asset

It is also possible to generate an instance of an Event Channel that can be use to received or emit message from. This is useful in case you want a global event channel that should be the same accross several graphs. You can then reference this asset in C# systems or component to react or send event message.
To do so, once you have created a new Event Channel from a Blackboard wizard:

  1. Go to the project view
  2. Right click > Create > Behavior > Event Channel > %Name_of_Your_Event_Channel%
  3. This will create an instance of that Event Channel that can be assigned to Graph but also C# components.
  4. In C#, use the Event Channel API to listen or send new message.
Sample code
[SerializeField] private StateEventChannel m_EventChannel;

private void OnEnable()
{
    m_EventChannel.Event += OnStateEvent;
}
private void OnDisable()
{
    m_EventChannel.Event -= OnStateEvent;
}

private void Update()
{
    // your custom logic

    // Send event to the event channel instance.
    // All graphs and C# systems on that same event channel instance will receive it.
    m_EventChannel.SendEventMessage(StateExample.Alert);
}

private void OnStateEvent(StateExample value)
{
    // React to event
}

I hope this will answer your question, and don’t hesitate to ask if you have any others :slightly_smiling_face:

5 Likes

I really like how much you go into detail here. I am using a similar approach, to the first one you provided - I just joinked it from your behavior demo from the asset store. I have an Interface per EventChannel and assign all child objects from a bootstrapper that inherit from that Interface:
Example - IRequireHealthChangedEventChannel

Then loop through all child’s of the Bootstrapper Component which is on the same level as the BehaviorGraphAgent Component and call the: InitializeEventChannel(HealthChangedEventChannel healthChangedEventChannel); Method from the Interface. In that way every Class has the correct reference to the behavior graph.

In my game I don’t have an Event Channel for each Attribute Type, but rather one Event Channel with multiple Variables. So EnergyChangedEventChannel, but multiple Variables in the Blackboard: HealthChangedEventChannel, StaminaChangedEventChannel, etc.
I then also only have one Interface: IRequireEnergyEventChannel. In my Bootstrapper, instead of looping through Children I have multiple Arrays, which are there for the different EnergyEventChannels. Example Health Channel: [SerializeField] MonoBehaviour[] healthRelatedChannels - On Start I validate the MonoBehaviours as IRequireEnergyEventChannel loop through them and assign the event channel ;)!
I find that solution pleasant.

2 Likes

Thanks so much for such a great explanation and the example code, precisely what I was looking for!

2 Likes

Not seeing this in unity 6.1? Did this move?
Looks like this is done now maybe from the blackboard adding variables?

I see now seems to be the missing step is you need to create it first in the blackboard then it shows up at a creatable asset.

Hello @daxiongmao,

Please refer to the documentation section about Creating An Event Channel.

For context, Create > Behavior > Event Channel > %Name_of_Your_Event_Channel% is only going to show if you already have an existing event channel class.

Hope this helps :slightly_smiling_face:

Just to clarify, on 1.0.11 if I want to send an event from C# to a SPECIFIC BG agent, i do this:

[SerializeField] private BehaviorGraphAgent _bgAgent;
private BlackboardVariable<GotHitEvent> _gotHitEvent;
//only set the Agent in Inspector, not the event

    private void Start() //havent tested Awake
    {
        _bgAgent.BlackboardReference.GetVariable("GotHitEvent", out _gotHitEvent);
    }

     //and when i need to send the event
     public void OnBeingAttacked()
    {
        _gotHitEvent.Value.SendEventMessage(//params);
    }

Would that be the correct way? It works, but I’m curious about the subscribing part.

Yes, it’s correct, you can also skip BlackboardReference and directly call agent.GetVariable:

Do you mean how to listen to the event from code or the graph?

Something that is not very explicit is the fact that if you don’t assign an event channel asset to a BlackboardVariable<EventChannel>, any agent running this graph will initialize a local event channel instance. So if you want the event channel to affect each individual instance of agent, you must not assign an event channel asset.

1 Like

I meant a graph listening from code. So far I didn’t need to listen from a graph.

yeah, it adds default event. It took me a while to figure that NEITHER graph or code must have a channel (i mean event) assigned.