Mono Node

An extension of the Node Framework that seamlessly integrates with Unity's GameObject hierarchy system.

Overview

MonoNode allows any MonoBehaviour to become a node in your hierarchy by inheriting from MonoNode<T>. It maintains synchronization between the GameObject hierarchy and the node structure.

Key Features

  • Automatic GameObject hierarchy synchronization

  • Inspector-based node structure management

  • Safe node registration system

  • Flexible parent-child relationship handling

  • Container nodes for structural organization


Why Use It

Mono Node Framework bridges Unity's Component system with our powerful Node Framework. It transforms individual Components into nodes while respecting Unity's hierarchical structure.

Key Features:

  • Component Integration: Turn any MonoBehaviour into a powerful node

  • Hierarchy Respect: Maintains Unity's natural GameObject relationships

  • Extended Functionality: Access both Node Framework features and Mono-specific extensions

  • Natural Workflow: Feels native to Unity while providing node capabilities

  • Performance Optimized: Designed for efficient operation within Unity's component system

Perfect for developers who want node-based architecture while leveraging Unity's component system to its fullest.


Creating a MonoNode

// Define your MonoNode component
public class MyGameNode : MonoNode<MyGameNode>
{
    protected override void Awake()
    {
        base.Awake();    // => NodeAwake by Root Node only
        
        // normal Awake process
    }
        
    protected override void NodeAwake()
    {
        base.NodeAwake();
        
        // Called when node structure is ready
        // Put your initial codes here that required the node structure
        // NodeReady will be true after invoked
    }
}

Inspector Controls

Inspector of a MonoNode
  • Node ID

    • Optional unique identifier for the node

    • Leave empty if the node type is unique in your scene or will never be lookup

    • Set an ID when you have multiple nodes of the same type

    • Used for specific node lookup and reference

  • Auto Registry

    • Controls automatic node registration during Awake

    • When true: Node automatically registers to the node system

    • When false: Manual registration required


MonoNode Structure

Building MonoNode<T> structure is not required any manual process.

When a GameObject nested with MonoNode<T> components without gap, the whole structure will be built on Awake() automatically.

For non-functional GameObject, you may add ContainerNode to fill the gap.


Auto Register for MonoNode

According to construction of GameObject and Component in Unity, the handle of Auto Register of Node is different from pure Node.

Basic rules are:

  • GameObject exists in Hierarchy - Auto Registry is recommended unless you want to handle yourself.

  • GameObject will be Instantiated by code (pool object) - Auto Registry should be off because related node data is not ready.

  • Other case - It's not neccessary to get the nodes thought Node<T>.Get(), you can turn off Auto Registry.

By right-clicking on GameObject or Prefab, you can choose in menu item Node to Enable or Disable Auto Registry of all Nodes under the game object.


Manual Register

// for instantiating object by code, such as pool item.
public class YourComponent : MonoNode<YourComponent>, IPoolItem
{
    public void OnTakeFromPool()
    {
        // Register this Node
        this.Register();
    }

    public void OnReturnToPool()
    {
        // Unregister this Node
        this.Unregister();
    }
}

Please read Pool for details of IPoolItem.


Accessing Nodes

// Get parent of specific type
MyGameNode parent = node.MonoParent<MyGameNode>();

// Get child of specific type
MyGameNode firstChild = node.MonoChild<MyGameNode>();
MyGameNode namedChild = node.MonoChild<MyGameNode>("specificId");

// Get all children of specific type
IEnumerable<MyGameNode> children = node.MonoChildren<MyGameNode>();
IEnumerable<MyGameNode> allLevelChildren = node.MonoChildrenInAllLevel<MyGameNode>();

// Single instance - ID can be empty
public class PlayerNode : MonoNode<PlayerNode> { }
PlayerNode player = PlayerNode.Get();  // Works fine with single instance
PlayerNode.GetAsync()                  // Get the PlayerNode that may not ready now
    .Then(node => player = node)
    .Catch(Debug.LogError);

// Multiple instances - requires ID
public class EnemyNode : MonoNode<EnemyNode> { }
nodeId = "Boss"
EnemyNode boss = EnemyNode.Get("Boss");  // Get specific enemy
EnemyNode.GetAsync("Boss")               // Get the EnemyNode that may not ready now
    .Then(node => boss = node)
    .Catch(Debug.LogError);

About use of GetAsync(), please visit Task Utils for details of Promise.


Managing Relationships

// Set parent
node.SetParent(parentNode);

// Set as root
node.SetAsRoot();

// Add child
node.AddChild(childNode);
node.AddChildren(childNode1, childNode2);

// Remove relationships
node.RemoveChild(childNode);
node.RemoveChildren();

Container Nodes

Use ContainerNode to maintain node hierarchy when dealing with non-functional GameObjects.


More Node Initial States

In some case, action need to rely on other node that is already completed NodeAwake process.

public class YourNode : MonoNode<YourNode>
{
    protected override void NodeAwake()
    {
        base.NodeAwake();

        // run stuff after target node is awaken
        this.MonoChild<OtherNode>();
            .OnNodeReadyAction(() => Debug.Log("childNode is awaken"));
        
        // run with the node parameter
        this.MonoChild<OtherNode>();
            .OnNodeReadyAction(node => Debug.Log($"childNode {node.Id} is awaken"));
    }
}

Important Notes

  • Node registration occurs during Awake (if autoRegisterToNodeTree is true)

  • Node structure built during Awake

  • Custom initialization code should be placed in NodeAwake()


Best Practices

  • Always override StartAfterNodeBuilt() for initialization that requires node structure

  • Leave ID empty for singleton-like nodes

  • Use meaningful IDs for multiple instances (e.g., "BossEnemy", "MiniBoss")

  • Consistent ID naming helps with node retrieval

  • Consider using enums or constants for frequently used IDs

  • Regularly update node structure when modifying GameObject hierarchy

  • Consider disabling autoRegisterToNodeTree if manual control is needed

Last updated