{"id":13661768,"url":"https://github.com/Qriva/MonoBehaviourTree","last_synced_at":"2025-04-25T03:31:15.400Z","repository":{"id":52309380,"uuid":"253262868","full_name":"Qriva/MonoBehaviourTree","owner":"Qriva","description":"Simple event driven Behaviour tree for Unity projects","archived":false,"fork":false,"pushed_at":"2024-08-26T09:26:17.000Z","size":609,"stargazers_count":228,"open_issues_count":4,"forks_count":17,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-08-26T20:22:40.801Z","etag":null,"topics":["ai","behaviour-tree","unity"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Qriva.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-05T15:08:19.000Z","updated_at":"2024-08-26T19:32:10.000Z","dependencies_parsed_at":"2024-01-14T14:31:29.756Z","dependency_job_id":"c3e2c1c7-1436-45a2-bd03-4e8c3af40507","html_url":"https://github.com/Qriva/MonoBehaviourTree","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Qriva%2FMonoBehaviourTree","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Qriva%2FMonoBehaviourTree/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Qriva%2FMonoBehaviourTree/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Qriva%2FMonoBehaviourTree/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Qriva","download_url":"https://codeload.github.com/Qriva/MonoBehaviourTree/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223979781,"owners_count":17235463,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","behaviour-tree","unity"],"created_at":"2024-08-02T05:01:41.235Z","updated_at":"2024-11-10T16:31:57.621Z","avatar_url":"https://github.com/Qriva.png","language":"C#","readme":"# MonoBehaviourTree — Simple behaviour tree for Unity\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"readme-image.png\" alt=\"Screenshot\"/\u003e\n\u003c/p\u003e\nThis project is simple event driven behaviour tree based on Unity engine component system. This asset comes with minimal node library and tree visual editor.\n\n**Important:** This is not fully fledged visual scripting tool. Package has its own visual editor, however requires you to implement your own nodes.\n\n## Contribute\nContribution in any form is very welcome. Bugs, feature requests or feedback can be reported in form of Issues.\n\n## Getting started\nThe latest version can be installed via [package manager](https://docs.unity3d.com/Manual/upm-ui-giturl.html) using following git URL:\u003cbr\u003e ```https://github.com/Qriva/MonoBehaviourTree.git#upm``` \n\u003cbr\u003eAlternatively you can copy the `Assets/MonoBehaviourTree` folder to your project or download from [Unity Asset Store](https://assetstore.unity.com/packages/slug/213452).\n\nExamples of usage are available in package manager or in folder **Samples** containing demo scenes. If you copy assets manually you might want to delete `Samples` directory to get rid of redundant files.\n\nThis documentation assumes you have basic knowledge about behaviour trees. If you don't have it, you should check some online resources like this \n[Game Developer article](https://www.gamedeveloper.com/programming/behavior-trees-for-ai-how-they-work)\nor [Unreal Engine documentation](https://docs.unrealengine.com/en-US/Engine/ArtificialIntelligence/BehaviorTrees/BehaviorTreesOverview/index.html).\n\n## Event Driven Behaviour Tree Overview\nStandard behaviour tree design assumes three types of nodes: composites, decorators and leafs. Composites are used to define the flow in the tree, decorators can modify node results and leafs perform tasks or check conditions. This design has one major flaw - tree must be traversed from the beginning every single tick, otherwise it will not be possible to react to changes in state or data. Event driven tree is the fix to that problem. When tree gets update it continues from the last executed running node. Normally it would mean, that executed higher priority nodes will not be reevaluated immediately, but event driven BT introduces **abort system** to give possibility to reset tree to previous state, when certain event occur. Implementation used in this project is very similar to the one used in Unreal engine - leaf nodes are not used as conditions, instead they are in form of decorators. Additionally it is possible to create Service nodes which can perform task periodically.\n\n### Node Abort\nWhen the tree is updated, the first evaluated thing are aborting nodes. If there is any aborting node, the tree will be reset to that position and execution will be continued from this node.\nIn case there are multiple aborting nodes, the one closest to root will be selected.\nThere are four abort types:\n- **None** - don't do anything when change occurs\n- **Self** - abort children running below\n- **Lower Priority** - abort running nodes with lower priority (nodes to the right)\n- **Both** - abort self and lower priority nodes\n\n\u003eExecution order (priority) of nodes with common ancestor is defined by position on X axis, nodes to the left has higher priority.\n\nAborts can be performed only by ```Decorator``` nodes. See example abort implementation in [Decorator](#custom-decorator--condition) section.\n\n## Basic Usage\nThe main core of behaviour tree is **MonoBehaviourTree** component. It contains most of tree state during runtime. It is important to note, that tree does not run automatically and must be updated by other script. This design gives you possibility to tick the tree in Update, FixedUpdate or custom interval. However, most of the time Update event will be used, so you can use component **MBT Executor** to do that.\n\nIn most of cases you will need some place to store shared data for nodes. You could implement your own component to do that, but instead it's better to use built in **Blackboard** component. Blackboard allows you to create observable variables of predefined types that are compatible with default nodes.\n\n## Node editor\nTo open tree editor window click \"Open editor\" button of MonoBehaviourTree component or click Unity menu: Window / Mono Behaviour Tree. In visual editor you can create, connect, delete and setup nodes. \n\nEvery behaviour tree needs an entry point called **Root**. To add it right click on empty canvas to open node popup, then select Root. Execution of BT starts here and goes from top to down, left to right.\n\n\u003e **Implementation note:** All nodes and variables are in fact components, but they are invisible in inspector window.\n\u003e It is recommended to use separate empty game object to build the tree - this make it easier to create prefabs and avoid unnecessary unknown problems.\n\nMost of nodes has additional properties that you can change. To do this select the node and list of options will show up in **MonoBehaviourTree component inspector** section (standard component inspector). When node setup is not valid, error icon will be shown next to the node. By default error is displayed if one of variable references is set to \"None\". You can create custom validation rules in your own nodes, see [Node API section](#node-api).\n\n### Editor Window Features\nRight click on empty space to create new node. To connect nodes click on in/out handler (black dot on top and bottom of node), then drag and drop it above another node. In case node cannot have more than one child (decorator) the connection will be overridden by the new one.\nTo delete, duplicate or disconnect nodes right click on node to open context menu and select the appropriate option.\nUse left mouse button to drag workspace or nodes. You can drag whole branch of nodes when CTRL key is pressed.\n\n## Component Reference\n\n### MonoBehaviourTree component\nMain component used as hub of behaviour tree.\n\n**Properties**\n- **Description** - optional user description.\n- **Repeat OnFinish** - whether the tree should be executed again when finished.\n- **Max Executions Per Tick** - how many nodes should be executed during single update.\n- **Parent** - parent reference if this tree is subtree. Read more in [Subtree node section](#subtree).\n\n**Node Inspector** - Inspector of node selected in Behaviour Tree editor window.\n\n### Blackboard component\nComponent used to provide and manage observable variables.\nTo add variable fill the **Key** text field, select it's type and press \"Add\" button. Key is used as identifier to get or set variable value, this can be done by VariableReference or blackboard method: ```public T GetVariable\u003cT\u003e(string key)```.\nBlackboard component displays all available variables in list and allows to set initial value for each of them.\n\u003e **Implementation note:** Changing blackboard variables during playmode triggers change listeners, however old and new value  will be the same in this event, because it's called from  `OnValidate`. Displayed values are refreshed every half second.\n\n**Built In variable types:** Bool, Float, Int, Object, Quaternion, String, Transform, Vector2, Vector3. If you need to add your own custom type read [Custom Variable section](#custom-variable).\n\n**Master Blackboard** option allows to make synchronisation effect between variables. When set, blackboard will replace variables during initialization, but only when their keys match. Replacement is not hierarhical and only variables from given parent blackboard are matched. It is recommended to create one master blackboard on top of the tree and keep all other subtrees blackboards synchronized with the top one.\n\n## Variables and Events\nIn most of situations nodes need to share some state data between each other, it can be done by Blackboard, Variable and VariableReference system. Variables are observale data containers, that can be accesed via Blackboard. To get variable you need to know its key, but inputting key manually to every node is not handy and very error prone. \n\nTo avoid this you can use helper class VariableReference. \nThis class allows you to automaticaly get and cache reference to blackboard variable.\nVariableReference has also constant value mode in case you don't need to retrive values from blackboard. You can toggle VarRef mode in editor by clicking small button to the left. Keys displayed in dropdown will be loaded from blackboard on the same object or if there is none it will look upwards the hierarchy to find one.\n```csharp\n// Get variable from blackboard by key\nFloatVariable floatVar = blackboard.GetVariable\u003cFloatVariable\u003e(\"myKey\");\n\n// Attach listener to variable\nfloatVar.AddListener(MyVariableChangeListener);\n\n// Create float reference property with default constant value\npublic FloatReference floatRef = new FloatReference(1f);\n\n// Create int reference, but do not allow constant values\npublic IntReference intRef = new IntReference(VarRefMode.DisableConstant);\n\n// Check if its in constant or reference mode\nbool constant = floatRef.isConstant;\n\n// Attach listener to variable reference\nif (!constant)\n{\n    // GetVariable will return null if floatRef is constant\n    floatRef.GetVariable().AddListener(MyVariableChangeListener);\n}\n\n// Get or set value of variable reference\nfloatRef.Value = 1.5f;\nfloat value = floatRef.Value;\n```\n\u003e **Important:** TransformVariable change listener will be called only when reference to object changes. Position or rotation changes do not trigger change listener.\n\n### Custom Variable\nIf built in variables are not enough, you can create your own.\nTo create new Variable and VariableReference you must extend Variable class and VariableReference class. Variable inheriths MonoBehaviour, so to work properly it must by placed in file of the same name as your custom type. VariableReference is normal serializable class and can be placed in the same file. Add ```[AddComponentMenu(\"\")]``` attribute to disallow adding variable component manually. \n\nAny variable must implement ValueEquals method which is used to detect change of value. This mechanism allows to correctly compare Unity objects in generic class, avoid boxing, plus gives the way to implement your own change detection logic when needed.\n```csharp\n[AddComponentMenu(\"\")]\npublic class CustomVariable : Variable\u003cCustomType\u003e\n{\n    protected override bool ValueEquals(CustomType val1, CustomType val2)\n    {\n        return val1 == val2;\n    }\n}\n\n[System.Serializable]\npublic class CustomReference : VariableReference\u003cCustomVariable, CustomType\u003e\n{\n    // You can create additional constructors and Value getter/setter\n    // See FloatVariable.cs as example\n\n    // If your variable is reference type you might want constant validation\n    // protected override bool isConstantValid\n    // {\n    //     get { return constantValue != null; }\n    // }\n}\n```\n\n## Node Reference\n\n### Root\nEntry node of behaviour tree.\n### Sequence\nExecutes children from left to right as long as each subsequent child returns success. Returns success when all children succeeded, or failure if one of them failed. When Random option is enabled, then execution goes in random order.\n### Selector\nExecutes children from left to right until one of their children succeeds. Returns success if any children succeed, or failure if all of them failed. When Random option is enabled, then execution goes in random order.\n### Is Set Condition\nChecks if blackboard variable is set. Node supports Bollean, Object and Transform variables. Selecting Invert option will produce \"If not set\" effect.\n### Number Condition\nChecks if blackboard number variable meets requirement. Node supports Float and Int variables.\n### Distance Condition\nChecks distance between two transforms and returns success when given distance condition is met.\n### Cooldown\nBlocks execition until the specified amount of time has elapsed.\nTime starts counting after branch is exited. If abort is enabled, the execution will be moved back to this node after time has elapsed.\n### Force Result\nForces success or failure.\n### Inverter\nInverts node result. Failure becomes Success and vice versa.\n### Invoke Unity Event\nTriggers Unity Event with one parameter of selected type\n### Random Chance\nThere is fixed chance that node will be executed. Returns Failure if roll is not favorable.\n### Random Float\nGenerates random float in provided range.\n### Random Integer\nGenerates random integer in provided range.\n### Repeat Until Fail\nRepeats branch as long as Success is returned from the child. Use Loop node to create a more advanced flow.\n### Repeater\nRepeats branch specified amount of times or infinitely. Use Loop node to create a more advanced flow.\n### Loop\nRepeats branch specified amount of times, infinitely or until selected result is returned. Results and flow can be fully customized.\n### Set Boolean\nSets blackboard bool variable\n### Set Number\nSets blackboard int or float variable\n### Set Object\nSets blackboard Transform or GameObject variable\n### Set Vector\nSets blackboard Vector3 or Vector2 variable\n### Succeeder\nAlways returns Success.\n### Time Limit\nDetermines how long branch can be executed. After given time elapses branch is aborted and Failure is returned.\n### Calculate Distance Service\nCalculates distance between two transforms and updates blackboard float variable with the result.\n### Update Position Service\nUpdates blackboard Vector3 variable with position of given source transform.\n### Set Number\nSets blackboard Float or Int variable.\n### Wait\nWaits specific amount of time, then returns Success.\n### Subtree\nSubtree node allows connection of other behaviour tree as child, this gives you possibility to create reusable blocks of nodes. Such a tree must be created in separate game object and attached as children. Child tree is updated by its parent. **Parent of subtree must be specified in MonoBehaviourTree component to work properly.** \n\n## Creating custom nodes\nIt is possible to create custom nodes by extending one of base classes provided by library. Each node **must** be in separate file with the name corresponding to class name. MBTNode attribute is required to register node in editor finder, it accepts two parameters: name and order. Name allows use of up to one folder, so \"Custom Node\" and \"Example/Custom Node\" is valid, but \"Fruits/Bananas/Custom Node\" is not.\nOrder parameter is used to position node higher in finder. Nodes are sorted first by order and then by name. Default order is 1000 and lower values get higher priority. For example Selector, Sequence, Root and SubTree nodes have following values: 100, 150, 200, 250.\n\n### Node API\nThere are several event methods that can be implemented to control Node execution flow, but the only required one is ```Execute``` used to return state when node is running. \n```OnEnter``` and ```OnExit``` primary function is to setup before or cleanup after execution.\n```OnAllowInterrupt``` and ```OnDisallowInterrupt``` can be used to detect when its allowed to abort or listen to some events. \nAdditionally there is ```IsValid``` method used in editor window to determine if Node setup is correct. By default it uses reflection to find variable references with empty keys and in most of cases there is no need to override this method, unless you want to include other fields during validation or custom setup requires it.\n\n### Execution Flow\nDuring runtime node can be in one of following states:\n- **Ready** - Default state \n- **Running** - Node is currently executed or one of its successors\n- **Success** - Node finished execution and returned success\n- **Failure** - Node finished execution and returned failure\n\nWhen node is ready and parent decide to \"enter\" the node, then ```OnAllowInterrupt``` and ```OnEnter``` is called. After that ```Execute``` method is called which always must return some state. \nIf running state is returned, then execution will be paused and resumed in next tick, but if running with children node is returned, then execution is \"passed down\" and continued in that node. \nWhen success or failure is returned, then this result is passed to the parent and ```OnExit``` is called. ```OnDisallowInterrupt``` is not called until the cycle ends or tree is aborted to higher priority node.\n\n### Custom Leaf\nLeaf nodes are used to do designated task. It can be something simple as setting variable or very complex like enemy navigation along the path.\n```csharp\nusing UnityEngine;\nusing MBT;\n\n// Empty Menu attribute prevents Node to show up in \"Add Component\" menu.\n[AddComponentMenu(\"\")]\n// Register node in visual editor node finder\n[MBTNode(name = \"Example/Custom Task\")]\npublic class CustomTask : Leaf\n{\n    public BoolReference somePropertyRef = new BoolReference();\n    \n    // These two methods are optional, override only when needed\n    // public override void OnAllowInterrupt() {}\n    // public override void OnEnter() {}\n\n    // This is called every tick as long as node is executed\n    public override NodeResult Execute()\n    {\n        if (somePropertyRef.Value == true)\n        {\n            return NodeResult.success;\n        }\n        return NodeResult.failure;\n    }\n\n    // These two methods are optional, override only when needed\n    // public override void OnExit() {}\n    // public override void OnDisallowInterrupt() {}\n\n    // Usually there is no needed to override this method\n    public override bool IsValid()\n    {\n        // You can do some custom validation here\n        return !somePropertyRef.isInvalid;\n    }\n}\n```\n### Custom Decorator / Condition\nDecorator nodes are mainy used to change flow of the tree. It has single child and must always return either success or failure. You can implement your own subclass by implementing ```Decorator``` class, however in most of cases you might want to create condition - in such a case use ```Condition``` subclass. Implement condition evaluation in ```Check()``` method and node will return success if condition is met.\n\nIf you need to implement abort system in your condition node, then below you can find a simple example.\n```csharp\n[AddComponentMenu(\"\")]\n[MBTNode(name = \"Example/Custom Condition\")]\npublic class CustomCondition : Condition\n{\n    public Abort abort;\n    public BoolReference somePropertyRef = new BoolReference(VarRefMode.DisableConstant);\n\n    public override bool Check()\n    {\n        // Evaluate your custom condition\n        return somePropertyRef.Value == true;\n    }\n\n    public override void OnAllowInterrupt()\n    {\n        // Do not listen any changes if abort is disabled\n        if (abort != Abort.None)\n        {\n            // This method cache current tree state used later by abort system\n            ObtainTreeSnapshot();\n            // If somePropertyRef is constant, then null exception will be thrown.\n            // Use somePropertyRef.isConstant in case you need constant enabled.\n            // Constant variable is disabled here, so it is safe to do this.\n            somePropertyRef.GetVariable().AddListener(OnVariableChange);\n        }\n    }\n\n    public override void OnDisallowInterrupt()\n    {\n        if (abort != Abort.None)\n        {\n            // Remove listener\n            somePropertyRef.GetVariable().RemoveListener(OnVariableChange);\n        }\n    }\n\n    private void OnVariableChange(bool oldValue, bool newValue)\n    {\n        // Reevaluate Check() and abort tree when needed\n        EvaluateConditionAndTryAbort(abort);\n    }\n}\n```\n### Custom Service\nService is a special decorator that performs the task as long as its branch is executed. This way you can periodically execute some task needed only by the ancestors. Additionally you can fully encapsulate your system into single behaviour tree without need of external scripts running on other game objects.\n\n```csharp\n[AddComponentMenu(\"\")]\n[MBTNode(\"Example/Custom Service\")]\npublic class CustomService : Service\n{\n    public Vector3Reference position = new Vector3Reference(VarRefMode.DisableConstant);\n\n    public override void Task()\n    {\n        // Reset variable to zero every X amount of time\n        position.Value = Vector3.zero;\n    }\n}\n```\n\n## Debugging\nDuring playmode you can preview tree execution flow in editor window. Nodes are marked with the appropriate color corresponding to their state:\n- Ready - none (default)\n- Success - green\n- Failure - orange\n- Running - purple\n\nWhen the node is invalid, an error icon will be displayed in the upper right corner. You should not run the tree when there are any errors in connected nodes.\n\nExcept that, you can set breakpoints on multiple nodes. Breakpoint will stop execution and pause play mode after node is entered, but before it get executed. Nodes with breakpoint enabled will have red node names.\n\n## Known Issues\n- All nodes should be removed before deleting their script. When the missing script is restored and children of this node were connected to other parent, it will break the tree. Additionaly nodes with missing script remain hidden in the inspector and it is hard to remove them.\n- When tree is turned into prefab, all their instances should not change connections between nodes. Sometimes connections are desynchronized and the tree does not work properly.","funding_links":[],"categories":["C\\#","Open Source Repositories"],"sub_categories":["AI"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FQriva%2FMonoBehaviourTree","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FQriva%2FMonoBehaviourTree","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FQriva%2FMonoBehaviourTree/lists"}