Create a simple "IsVariableNull" condition in Behaviour 1.0.5

I’m trying to create a very simple “Is Variable Null” condition for use in my Behaviour Tree.

  1. In my Graph, I go to a Conditional Branch node, Assign Condition > Create New Condition…
  2. Name: “Is Variable Null”
  3. Description: Is Variable Null?", mapping the ‘Variable’ sting to type Variables (I can’t seem to pick a type of BlackboardVariable.
  4. In the new script, I add:
public override bool IsTrue()
{
    return ReferenceEquals(Variable.ObjectValue, null);
}

When debugging, this always returns “true”, even when the variable I pass in is not null. This is what the watch on Variable looks like:


I guess I’m doing something wrong in how I’m defining the Variable that’s passed into the condition? Or am I not reading the correct property to determine the value of the variable?

Thanks for any help!

EDIT: I guess it’s because I selected Variables, which is something from Visual Scripting, not from Behaviour. But there doesn’t appear to be a way to pick a BlackboardVariable as the type.

Hi @mroshaw,

I believe you should be able to check correctly using an if(Variable.ObjectValue is null) check.

We have one example of a similar node in the sample we created here:

You are looking for:

public override bool IsTrue()
{
    return ReferenceEquals(Variable.Value, null);
}

.Value is the generic type, that the Blackboardvariable represents. the nullcheck asks if the value itsself is null. Lets say there is nothing dragged in that field, your check returns TRUE, since the value is automatically null aswell. If there is something dragged in that field, but the value itsself is null, your check returns TRUE

Thank you kindly for the response and explanation!

The problem I have is that there is no way to pick BlackboardVariable as the type to use when I define my Condition:

Your BlackboardVariable has a generic it is representing

Example:

[SerializeReference] public BlackboardVariable<GameObject> Target;

So you would want to search GameObject for examle :wink:

I did the exact same node, heres mine :slight_smile:

[Serializable, Unity.Properties.GeneratePropertyBag]
    [Condition(name: "Entity Null Check", story: "[Entity] [NullComparison] null", category: "Variable Conditions", id: "28a70606683fa1e36a9a36db4e19cfc5")]
    public partial class NullCheckCondition : Condition {
        [SerializeReference] public BlackboardVariable<GameObject> Entity;
        [SerializeReference] public BlackboardVariable<Comparison> NullComparison;

        public override bool IsTrue() {
            return NullComparison.Value switch {
                Comparison.Is => Entity.Value == null,
                Comparison.IsNot => Entity.Value != null,
                _ => false
            };
        }

        public override void OnStart() { }

        public override void OnEnd() { }
    }
public enum Comparison {
        Is,
        IsNot
    }

I was able to manually create the script, rather than having to pick a type in the UI.

However, a check against Variable.ObjectValue is null is always returning false, even when the value of the passed in Variable is indeed null:


I must just be doing something really stupid!

Yes, I have noticed the same.

I have the problem that I one of my Nodes needs to have an OUT Variable, which can be null when the node is initialized, but it needs to be assigned.
Checking:

if (ReferenceEquals(Target.Value, null)) { }
will succeed, if no variable assigned, or the assigned variables value is null

Checking:
if (ReferenceEquals(Target.ObjectValue, null)) { }
Is never returning false as @mroshaw showed above

Checking:
if (ReferenceEquals(Target, null)) { }
Is never returning true.

Maybe @Darren_Kelly got any idea.

Yeah, I just fired up a new project with the Behaviour Sample, using Behaviour 1.0.5. The included example condition, NullCheckCondition, does exactly the same as mine does - returns false irrespective of whether the variable is indeed null or otherwise.

Interesting, let me bring it up with the team. I’ll get back to you!

Great!
Theres also this Node made by you guys, which has an OUT Variable.
In Code you guys tried to make the node fail, if the OUT is not assigned, but since the
if(Object == null) will never return null, this node can never fail

namespace Unity.Behavior
{
    [Serializable, GeneratePropertyBag]
    [NodeDescription(
        name: "Find With Tag",
        description: "Finds a GameObject with a tag.",
        story: "Find [Object] with tag: [Tag]",
        category: "Action/Find",
        id: "c83ba0235980a2a0ff12705e1f4fdcea")]
    internal partial class FindObjectWithTagAction : Action
    {
        [SerializeReference] public BlackboardVariable<GameObject> Object;
        [SerializeReference] public BlackboardVariable<string> Tag;

        protected override Status OnStart()
        {
            if (Object == null)
            {
                return Status.Failure;
            }

            Object.Value = GameObject.FindGameObjectWithTag(Tag.Value);
            return Object.Value == null ? Status.Failure : Status.Success;
        }
    }
}

Hi, thank you for bringing that issue to our attention.

Several users have been reporting issue around the null checking being an issue with our node. It seems like something is going wrong because of the additional logic those operators can have.

Can you try using ObjectValue.Equals(null)?:

if (Variable.Type.IsValueType)
{
    return false;
}

return Variable.ObjectValue.Equals(null);

We will look deeper into it.

Sorry for the inconvenience.

That works! Excellent, thank you!

Just to add, I’ve also created an Action to set a variable to null - for example, to clear out a target Transform when the AI loses sight of the player:

public partial class SetVariableNullAction : Action
{
  [SerializeReference] public BlackboardVariable Variable;
  protected override Status OnStart()
  {
    Variable.ObjectValue = null;
    return Status.Success;
  }
}

In order to get the Condition to work with this, I’ve had to amend it slightly:

public partial class VariableIsNullCondition : Condition
{
  [SerializeReference] public BlackboardVariable Variable;
  public override bool IsTrue()
  {
    if (Variable.Type.IsValueType)
    {
      return false;
    }
    return Variable.ObjectValue is null || Variable.ObjectValue.Equals(null);
  }
}

You can also set a Blackboard variable to null/default by using SetVariableVariable without passing a Value field.

Based on several users report and a quick internal investigation, it seems like Variable.ObjectValue is null or using the == operator is always returning false so you should only need Variable.ObjectValue.Equals(null).
You are actually right about checking is null first, for some reason the behavior change and cause nullreference on build player.

I believe this might be caused by the fact that BlackboardVariable are creating a default value to be serialized in blackboards. So even a Blackboard variable don’t have a value assigned don’t means it doesn’t have an object allocated in memory. Leading to a “null” value being different from the object itself not being allocated in memory and being null.

Sorry for the confusion this might cause.

Hi, related to all this, I got a situation

where that Branch on node always returns true, even if Target is null (which happens once the first branch completes).

I don’t know if I should use a simple Variable Comparison condition like that in the Branch on node, like I’m doing, and this is an error, or if I should use a custom condition to check for null. Any idea?

Hi @DiegoRuizValenciano

I’ve looked a little bit more in the area and it there is a bug in editor where null comparison of BlackboardVariable.ObjectValue is always returning true. This is not the case in Playber build, where the comparison is able to return false!

So for now I would recommend you to make a condition like mentioned above to make it behave the same in both editor and player build.

Sorry for the inconvenience.