├── .gitignore ├── Example ├── example.unity.meta ├── Waypoint │ ├── Waypoint.cs │ ├── WaypointHolder.cs │ ├── Waypoint.cs.meta │ └── WaypointHolder.cs.meta ├── Resources.meta ├── Waypoint.meta ├── RedSphereTree.cs ├── Resources │ ├── blue.mat.meta │ ├── redmetal.mat.meta │ ├── redmetal.mat │ └── blue.mat ├── MovementController.cs ├── PatrolWaypoints.cs.meta ├── RedSphereBehaviour.cs ├── RedSphereTree.cs.meta ├── MovementController.cs.meta ├── RedSphereBehaviour.cs.meta ├── PatrolWaypoints.cs └── example.unity ├── src ├── Node │ ├── LeafNodes │ │ └── EmptyNode.cs │ ├── DecoratorNode.cs │ ├── Node.cs │ ├── DecoratorNodes │ │ ├── SucceederNode.cs │ │ ├── RepeaterNode.cs │ │ ├── BreakpointNode.cs │ │ ├── InverterNode.cs │ │ └── RepeatUntilFailNode.cs │ ├── LeafNode.cs │ ├── ParentNode.cs │ ├── CompositeNodes │ │ ├── SelectorNode.cs │ │ ├── SequenceNode.cs │ │ └── ParallelNode.cs │ └── CompositeNode.cs ├── UtilityNodes │ └── TimedNoBehaviour.cs ├── BehaviourTree.cs └── Contexts │ └── Context.cs └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.meta -------------------------------------------------------------------------------- /Example/example.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8cdde4867416ac54dbdd27fadafb6158 3 | timeCreated: 1527055888 4 | licenseType: Free 5 | DefaultImporter: 6 | externalObjects: {} 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Example/Waypoint/Waypoint.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | /// 6 | /// Example class representing a waypoint in the world. 7 | /// 8 | public class Waypoint : MonoBehaviour { 9 | } 10 | -------------------------------------------------------------------------------- /Example/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b22d7b97ec43c9846908db5381b89f67 3 | folderAsset: yes 4 | timeCreated: 1527055546 5 | licenseType: Free 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Example/Waypoint.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 44979c67c6d7f8b4fbf27750e306b3f1 3 | folderAsset: yes 4 | timeCreated: 1527119529 5 | licenseType: Free 6 | DefaultImporter: 7 | externalObjects: {} 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Example/RedSphereTree.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class RedSphereTree : BehaviourTree { 6 | 7 | protected override Node DefineBehaviour() 8 | { 9 | return new RedSphereBehaviour(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Example/Resources/blue.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3aa0fa22682631942a3837e3d223b319 3 | timeCreated: 1527055554 4 | licenseType: Free 5 | NativeFormatImporter: 6 | externalObjects: {} 7 | mainObjectFileID: 2100000 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Example/Resources/redmetal.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f56bc685b518fd942a38e670388db070 3 | timeCreated: 1527055554 4 | licenseType: Free 5 | NativeFormatImporter: 6 | externalObjects: {} 7 | mainObjectFileID: 2100000 8 | userData: 9 | assetBundleName: 10 | assetBundleVariant: 11 | -------------------------------------------------------------------------------- /Example/MovementController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class MovementController : MonoBehaviour { 6 | 7 | // Use this for initialization 8 | void Start () { 9 | 10 | } 11 | 12 | // Update is called once per frame 13 | void Update () { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example/Waypoint/WaypointHolder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | /// 6 | /// Example class which allows for assignment of a set of waypoints in the inspector. 7 | /// 8 | public class WaypointHolder : MonoBehaviour 9 | { 10 | public Waypoint[] waypoints; 11 | } 12 | -------------------------------------------------------------------------------- /Example/PatrolWaypoints.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0c502d8587ff99e45b6e55117cba8f8b 3 | timeCreated: 1527125950 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Example/RedSphereBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class RedSphereBehaviour : ParentNode { 6 | 7 | protected override Node DefineBehaviour() 8 | { 9 | return new RepeaterNode( 10 | new SequenceNode(new TimedNoBehaviour(5f), new PatrolWaypoints()) 11 | ); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Example/RedSphereTree.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3f9d7d6484b685c4aaf20be9b7610268 3 | timeCreated: 1527128555 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Example/MovementController.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 89be78a03013e4a4f9310034014182ee 3 | timeCreated: 1527127678 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Example/RedSphereBehaviour.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 30353ac186c021e4fbf007fce82fdc82 3 | timeCreated: 1527128434 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /Example/Waypoint/Waypoint.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 55b1bdb9d4b2b0342b8fc84328b71c30 3 | timeCreated: 1527119524 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /src/Node/LeafNodes/EmptyNode.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | //This node runs for one tick and is always a success. 6 | public class EmptyNode : LeafNode 7 | { 8 | protected override NodeStatus OnTick(Context context) 9 | { 10 | return NodeStatus.Success; 11 | } 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Example/Waypoint/WaypointHolder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0a42377429ca0704eadf2a777daf71e4 3 | timeCreated: 1527119516 4 | licenseType: Free 5 | MonoImporter: 6 | externalObjects: {} 7 | serializedVersion: 2 8 | defaultReferences: [] 9 | executionOrder: 0 10 | icon: {instanceID: 0} 11 | userData: 12 | assetBundleName: 13 | assetBundleVariant: 14 | -------------------------------------------------------------------------------- /src/Node/DecoratorNode.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | /// 6 | /// A decorator node has a single child, and affects it's behaviour in some way. 7 | /// 8 | public abstract class DecoratorNode : Node { 9 | 10 | protected Node Child; 11 | 12 | protected DecoratorNode(Node child) 13 | { 14 | Child = child; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Node/Node.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | /// 6 | /// Parent class for all nodes. 7 | /// 8 | public abstract class Node 9 | { 10 | public enum NodeStatus {Running, Fail, Success} 11 | 12 | public abstract NodeStatus Tick(Context context); 13 | 14 | protected virtual void Init() {} 15 | 16 | public Node() 17 | { 18 | Init(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Node/DecoratorNodes/SucceederNode.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | /// 6 | /// This node always returns a success. 7 | /// 8 | public class SucceederNode : DecoratorNode { 9 | 10 | public SucceederNode(Node child) : base(child) 11 | { 12 | } 13 | 14 | public override NodeStatus Tick(Context context) 15 | { 16 | Child.Tick(context); 17 | return NodeStatus.Success; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/Node/LeafNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Runtime.CompilerServices; 5 | using UnityEngine; 6 | 7 | /// 8 | /// Leaf nodes have no children and are intended to hold behaviours. 9 | /// 10 | public abstract class LeafNode : Node 11 | { 12 | public sealed override NodeStatus Tick(Context context) 13 | { 14 | NodeStatus n = OnTick(context); 15 | return n; 16 | } 17 | 18 | protected abstract NodeStatus OnTick(Context context); 19 | } 20 | -------------------------------------------------------------------------------- /src/Node/DecoratorNodes/RepeaterNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | /// 7 | /// Repeats the child node on failure. 8 | /// Use sparingly as this can lead to undesirable behaviour loops. 9 | /// Should be the parent node of every behaviourTree. 10 | /// 11 | public class RepeaterNode : DecoratorNode { 12 | 13 | public RepeaterNode(Node child) : base(child) 14 | { 15 | } 16 | 17 | public override NodeStatus Tick(Context context) 18 | { 19 | Child.Tick(context); 20 | return NodeStatus.Running; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Node/ParentNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | /// 7 | /// A node with a function which allows it to define it's own child. 8 | /// Good for use as a starting node in a behaviourtree. 9 | /// 10 | public abstract class ParentNode : Node 11 | { 12 | protected Node Child; 13 | protected override void Init() 14 | { 15 | Child = DefineBehaviour(); 16 | } 17 | 18 | protected abstract Node DefineBehaviour(); 19 | 20 | public override NodeStatus Tick(Context context) 21 | { 22 | return Child.Tick(context); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/UtilityNodes/TimedNoBehaviour.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class TimedNoBehaviour : LeafNode 6 | { 7 | private Timer _timer; 8 | 9 | /// 10 | /// Returns success after a given time. 11 | /// 12 | /// How long to wait before returning success. 13 | public TimedNoBehaviour(float seconds) 14 | { 15 | _timer = new Timer(seconds); 16 | } 17 | protected override NodeStatus OnTick(Context context) 18 | { 19 | _timer.Update(); 20 | 21 | if (!_timer.IsComplete) 22 | { 23 | return NodeStatus.Running; 24 | } 25 | 26 | _timer.Reset(); 27 | return NodeStatus.Success; 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/Node/DecoratorNodes/BreakpointNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | /// 7 | /// Breakpoints will stop the execution of their child if their condition is not met. 8 | /// 9 | public abstract class BreakpointNode : DecoratorNode 10 | { 11 | protected BreakpointNode(Node child) : base(child) 12 | { 13 | } 14 | 15 | /// 16 | /// Checks a condition to decide whether to break or not. 17 | /// If the condition is met, return true. 18 | /// 19 | /// 20 | protected abstract bool CheckCondition(Context context); 21 | 22 | public override NodeStatus Tick(Context context) 23 | { 24 | return !CheckCondition(context) ? NodeStatus.Fail : Child.Tick(context); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/Node/DecoratorNodes/InverterNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | /// 7 | /// Inverter nodes return the opposite result of their child. 8 | /// 9 | public class InverterNode : DecoratorNode { 10 | 11 | public InverterNode(Node child) : base(child) 12 | { 13 | } 14 | 15 | public override NodeStatus Tick(Context context) 16 | { 17 | var status = Child.Tick(context); 18 | 19 | switch (status) { 20 | case NodeStatus.Running: 21 | return NodeStatus.Running; 22 | case NodeStatus.Fail: 23 | return NodeStatus.Success; 24 | case NodeStatus.Success: 25 | return NodeStatus.Fail; 26 | default: 27 | throw new ArgumentOutOfRangeException(); 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Node/DecoratorNodes/RepeatUntilFailNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | /// 7 | /// Node that repeats operation of the child until it fails. 8 | /// 9 | public class RepeatUntilFailNode : DecoratorNode { 10 | 11 | public RepeatUntilFailNode(Node child) : base(child) 12 | { 13 | } 14 | 15 | public override NodeStatus Tick(Context context) 16 | { 17 | var status = Child.Tick(context); 18 | 19 | switch (status) 20 | { 21 | case NodeStatus.Running: 22 | return NodeStatus.Running; 23 | case NodeStatus.Fail: 24 | return NodeStatus.Fail; 25 | case NodeStatus.Success: 26 | return NodeStatus.Running; 27 | default: 28 | throw new ArgumentOutOfRangeException(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/BehaviourTree.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public abstract class BehaviourTree : MonoBehaviour 6 | { 7 | protected Context Context; 8 | 9 | /// 10 | /// The starting node to ping. 11 | /// Usually, a Repeaternode. 12 | /// 13 | private Node _parentNode; 14 | 15 | private void Awake() 16 | { 17 | OnAwake(); 18 | } 19 | 20 | private void Start() 21 | { 22 | Context = new Context(gameObject); 23 | _parentNode = DefineBehaviour(); 24 | } 25 | 26 | protected virtual void OnAwake() 27 | { 28 | } 29 | 30 | /// 31 | /// Define the behavior in this method and return the parent node. 32 | /// 33 | /// 34 | protected abstract Node DefineBehaviour(); 35 | 36 | private void FixedUpdate() 37 | { 38 | _parentNode.Tick(Context); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Node/CompositeNodes/SelectorNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | /// 7 | /// Runs all children until a success is reached, and fails if each node has failed. 8 | /// 9 | public class SelectorNode : CompositeNode { 10 | 11 | public override NodeStatus Tick(Context context) 12 | { 13 | var status = Children[ActiveNodeIndex].Tick(context); 14 | 15 | switch (status) { 16 | case NodeStatus.Running: 17 | return NodeStatus.Running; 18 | case NodeStatus.Fail: 19 | var allNodesFailed = !TryMoveToNextNode(); 20 | return allNodesFailed ? NodeStatus.Fail : NodeStatus.Running; 21 | case NodeStatus.Success: 22 | return NodeStatus.Success; 23 | default: 24 | throw new ArgumentOutOfRangeException(); 25 | } 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Node/CompositeNode.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | 4 | /// 5 | /// Composite nodes have one or more children. 6 | /// 7 | public abstract class CompositeNode : Node 8 | { 9 | protected List Children = new List(); 10 | 11 | protected int ActiveNodeIndex; 12 | 13 | protected CompositeNode(params Node[] childNodes) 14 | { 15 | if (childNodes.Length <= 0) 16 | { 17 | Children.Add(new EmptyNode()); 18 | } 19 | 20 | foreach (var n in childNodes) 21 | { 22 | Children.Add(n); 23 | } 24 | } 25 | 26 | protected void Reset() 27 | { 28 | ActiveNodeIndex = 0; 29 | } 30 | 31 | protected bool TryMoveToNextNode() 32 | { 33 | if (ActiveNodeIndex < Children.Count - 1 ) 34 | { 35 | ActiveNodeIndex++; 36 | return true; 37 | } 38 | else 39 | { 40 | ActiveNodeIndex = 0; 41 | return false; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Node/CompositeNodes/SequenceNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | /// 7 | /// SequenceNodes have a "Complete" status when the sequence was successfully executed. 8 | /// 9 | public class SequenceNode : CompositeNode 10 | { 11 | public SequenceNode(params Node[] childNodes) : base(childNodes) 12 | { 13 | } 14 | 15 | public override NodeStatus Tick(Context context) 16 | { 17 | NodeStatus result = Children[ActiveNodeIndex].Tick(context); 18 | 19 | switch (result) 20 | { 21 | case NodeStatus.Running: 22 | return NodeStatus.Running; 23 | case NodeStatus.Fail: 24 | Reset(); 25 | return NodeStatus.Fail; 26 | case NodeStatus.Success: 27 | var sequenceComplete = !TryMoveToNextNode(); 28 | return sequenceComplete ? NodeStatus.Success : NodeStatus.Running; 29 | default: 30 | throw new ArgumentOutOfRangeException(); 31 | } 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Example/PatrolWaypoints.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | public class PatrolWaypoints : LeafNode 6 | { 7 | private int current_waypoint = 0; 8 | 9 | protected override NodeStatus OnTick(Context context) 10 | { 11 | Debug.Log(context); 12 | Debug.Log(context.agent); 13 | var wpholder = context.agent.GetComponent(); 14 | //If the agent has no WPholder, or if the wpholder is empty, return failure 15 | if (wpholder == null || wpholder.waypoints.Length == 0) 16 | { 17 | return NodeStatus.Fail; 18 | } 19 | 20 | //Translate towards waypoint 21 | context.agent.transform.position = 22 | Vector3.MoveTowards(context.agent.transform.position, 23 | wpholder.waypoints[current_waypoint].transform.position, .2f); 24 | 25 | //Measure how close the object is to it's destination 26 | var closeness = 27 | (context.agent.transform.position - wpholder.waypoints[current_waypoint].transform.position).magnitude; 28 | 29 | if (closeness > 1f) 30 | { 31 | return NodeStatus.Running; 32 | } 33 | 34 | //If we were close enough, move onto the next waypoint. 35 | current_waypoint += 1; 36 | if (current_waypoint < wpholder.waypoints.Length) 37 | { 38 | return NodeStatus.Running; 39 | } 40 | 41 | //We're done, reset the current wp and return a success 42 | current_waypoint = 0; 43 | return NodeStatus.Success; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Umbrella Tree 2 | 3 | 4 | Umbrella Tree is a skeletal, bare-bones implementation of an AI behaviour tree for your next Unity project. Umbrella Tree is designed to use no dependencies on other assets or code (and even limits it's interface with the Unity editor). The design of the tree is based on [this excellent blog post by Chris Simpson](https://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php), except it is written in C# and requires no XML. 5 | 6 | 7 | 8 | 9 | ## Installation 10 | 11 | 12 | Download and extract the files in SRC to your Unity project. You're done! 13 | 14 | 15 | 16 | ## Usage 17 | 18 | 19 | 1. Create a new Component that inherits from BehaviourTree. Also, create LeafNodes encapsulating individual behaviours. 20 | 21 | 2. Define your tree with your nodes.. Start with a ParentNode. For an example, see the RedSphereBehaviour node in /example. 22 | 23 | 3. Add the new Component to the object which you wish to behave. 24 | 25 | 4. You're done! The hard part is writing the LeafNode behaviours. 26 | 27 | 28 | 29 | ## Contexts 30 | 31 | 32 | Each of your nodes will have access to a Context object which is per-object. The Context object extends the functionality of the tree by adding access to semi-global context variables. You can add keyed data to the context with SetContextData and recover keyed data of an expected type by using GetContextData\. **Avoid using context variables unless it is really necessary. Abuse of context variables will invariably overcomplicate your tree.** 33 | 34 | 35 | 36 | ## Contact 37 | 38 | Please raise GitHub issues on this project if you feel like Umbrella Tree is missing a feature or has a bug. 39 | -------------------------------------------------------------------------------- /src/Node/CompositeNodes/ParallelNode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | /// 7 | /// A node which runs all children at the same time. The node decides it's state when the node success rate is either 8 | /// above (sucess) or below (fail) the supplied success rate. 9 | /// 10 | public class ParallelNode : CompositeNode 11 | { 12 | private readonly float _requiredSuccesses; 13 | 14 | /// 15 | /// Build a new ParallelNode. 16 | /// 17 | /// The required success rate as a percent (0-1f) 18 | /// The nodes to run in sequence. 19 | protected ParallelNode(float requiredSuccessRate, params Node[] childNodes) : base(childNodes) 20 | { 21 | requiredSuccessRate.ClampTo(new Range(0f, 1f)); 22 | _requiredSuccesses = (int)Math.Floor(Children.Count * requiredSuccessRate); 23 | } 24 | 25 | public override NodeStatus Tick(Context context) 26 | { 27 | var successes = 0; 28 | 29 | foreach (var n in Children) 30 | { 31 | var status = n.Tick(context); 32 | switch (status) 33 | { 34 | case NodeStatus.Running: 35 | break; 36 | case NodeStatus.Fail: 37 | break; 38 | case NodeStatus.Success: 39 | successes++; 40 | break; 41 | default: 42 | throw new ArgumentOutOfRangeException(); 43 | } 44 | } 45 | 46 | return successes >= _requiredSuccesses ? NodeStatus.Success : NodeStatus.Running; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Contexts/Context.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using NUnit.Framework; 6 | using UnityEditor; 7 | using UnityEngine; 8 | using UnityEngine.AI; 9 | 10 | public sealed class Context 11 | { 12 | public readonly GameObject agent; 13 | 14 | private readonly Dictionary contextData = new Dictionary(); 15 | 16 | public Context(GameObject agent) 17 | { 18 | this.agent = agent; 19 | } 20 | 21 | public void SetContextData(string name, object data) 22 | { 23 | contextData[name] = data; 24 | } 25 | 26 | /// 27 | /// Get data from the context. 28 | /// 29 | /// The expected name of the data. 30 | /// 31 | /// The data if it exists, and the default value if it does not. 32 | public T TryGetContextData(string name) 33 | { 34 | if (!dataExists(name)) 35 | { 36 | Debug.LogFormat("Tried to find a {0}-type object named '{1}', but it was either of the wrong type" + 37 | "or it did not exist.", name, typeof(T)); 38 | return default(T); 39 | } 40 | 41 | return (T) contextData[name]; 42 | } 43 | 44 | /// 45 | /// Does the data exist at this label? 46 | /// 47 | /// 48 | /// 49 | public bool dataExists(string label) 50 | { 51 | return contextData.Keys.Contains(label) && contextData["label"].GetType() == typeof(T); 52 | } 53 | 54 | /// 55 | /// Dumps the context's data including names. This allows for easy debugging. 56 | /// 57 | public void DumpData() 58 | { 59 | var result = string.Format("Context data members for {1}: "); 60 | foreach (var entry in contextData) 61 | { 62 | result += string.Format("{0}:{1} of type {2}", entry.Key, entry.Value, entry.Value.GetType()); 63 | } 64 | Debug.Log(result); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Example/Resources/redmetal.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: redmetal 10 | m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} 11 | m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 12 | m_LightmapFlags: 4 13 | m_EnableInstancingVariants: 0 14 | m_DoubleSidedGI: 0 15 | m_CustomRenderQueue: -1 16 | stringTagMap: {} 17 | disabledShaderPasses: [] 18 | m_SavedProperties: 19 | serializedVersion: 3 20 | m_TexEnvs: 21 | - _BumpMap: 22 | m_Texture: {fileID: 0} 23 | m_Scale: {x: 1, y: 1} 24 | m_Offset: {x: 0, y: 0} 25 | - _DetailAlbedoMap: 26 | m_Texture: {fileID: 0} 27 | m_Scale: {x: 1, y: 1} 28 | m_Offset: {x: 0, y: 0} 29 | - _DetailMask: 30 | m_Texture: {fileID: 0} 31 | m_Scale: {x: 1, y: 1} 32 | m_Offset: {x: 0, y: 0} 33 | - _DetailNormalMap: 34 | m_Texture: {fileID: 0} 35 | m_Scale: {x: 1, y: 1} 36 | m_Offset: {x: 0, y: 0} 37 | - _EmissionMap: 38 | m_Texture: {fileID: 0} 39 | m_Scale: {x: 1, y: 1} 40 | m_Offset: {x: 0, y: 0} 41 | - _MainTex: 42 | m_Texture: {fileID: 0} 43 | m_Scale: {x: 1, y: 1} 44 | m_Offset: {x: 0, y: 0} 45 | - _MetallicGlossMap: 46 | m_Texture: {fileID: 0} 47 | m_Scale: {x: 1, y: 1} 48 | m_Offset: {x: 0, y: 0} 49 | - _OcclusionMap: 50 | m_Texture: {fileID: 0} 51 | m_Scale: {x: 1, y: 1} 52 | m_Offset: {x: 0, y: 0} 53 | - _ParallaxMap: 54 | m_Texture: {fileID: 0} 55 | m_Scale: {x: 1, y: 1} 56 | m_Offset: {x: 0, y: 0} 57 | m_Floats: 58 | - _BumpScale: 1 59 | - _Cutoff: 0.5 60 | - _DetailNormalMapScale: 1 61 | - _DstBlend: 0 62 | - _GlossMapScale: 0.459 63 | - _Glossiness: 0.543 64 | - _GlossyReflections: 0 65 | - _Metallic: 0.635 66 | - _Mode: 0 67 | - _OcclusionStrength: 1 68 | - _Parallax: 0.02 69 | - _SmoothnessTextureChannel: 1 70 | - _SpecularHighlights: 1 71 | - _SrcBlend: 1 72 | - _UVSec: 0 73 | - _ZWrite: 1 74 | m_Colors: 75 | - _Color: {r: 1, g: 0.27205884, b: 0.27205884, a: 0.822} 76 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 77 | -------------------------------------------------------------------------------- /Example/Resources/blue.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_PrefabParentObject: {fileID: 0} 8 | m_PrefabInternal: {fileID: 0} 9 | m_Name: blue 10 | m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} 11 | m_ShaderKeywords: _EMISSION _GLOSSYREFLECTIONS_OFF _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A 12 | m_LightmapFlags: 1 13 | m_EnableInstancingVariants: 0 14 | m_DoubleSidedGI: 0 15 | m_CustomRenderQueue: -1 16 | stringTagMap: {} 17 | disabledShaderPasses: [] 18 | m_SavedProperties: 19 | serializedVersion: 3 20 | m_TexEnvs: 21 | - _BumpMap: 22 | m_Texture: {fileID: 0} 23 | m_Scale: {x: 1, y: 1} 24 | m_Offset: {x: 0, y: 0} 25 | - _DetailAlbedoMap: 26 | m_Texture: {fileID: 0} 27 | m_Scale: {x: 1, y: 1} 28 | m_Offset: {x: 0, y: 0} 29 | - _DetailMask: 30 | m_Texture: {fileID: 0} 31 | m_Scale: {x: 1, y: 1} 32 | m_Offset: {x: 0, y: 0} 33 | - _DetailNormalMap: 34 | m_Texture: {fileID: 0} 35 | m_Scale: {x: 1, y: 1} 36 | m_Offset: {x: 0, y: 0} 37 | - _EmissionMap: 38 | m_Texture: {fileID: 0} 39 | m_Scale: {x: 1, y: 1} 40 | m_Offset: {x: 0, y: 0} 41 | - _MainTex: 42 | m_Texture: {fileID: 0} 43 | m_Scale: {x: 1, y: 1} 44 | m_Offset: {x: 0, y: 0} 45 | - _MetallicGlossMap: 46 | m_Texture: {fileID: 0} 47 | m_Scale: {x: 1, y: 1} 48 | m_Offset: {x: 0, y: 0} 49 | - _OcclusionMap: 50 | m_Texture: {fileID: 0} 51 | m_Scale: {x: 1, y: 1} 52 | m_Offset: {x: 0, y: 0} 53 | - _ParallaxMap: 54 | m_Texture: {fileID: 0} 55 | m_Scale: {x: 1, y: 1} 56 | m_Offset: {x: 0, y: 0} 57 | - _SpecGlossMap: 58 | m_Texture: {fileID: 0} 59 | m_Scale: {x: 1, y: 1} 60 | m_Offset: {x: 0, y: 0} 61 | m_Floats: 62 | - _BumpScale: 1 63 | - _Cutoff: 0.5 64 | - _DetailNormalMapScale: 1 65 | - _DstBlend: 0 66 | - _GlossMapScale: 0.459 67 | - _Glossiness: 0 68 | - _GlossyReflections: 0 69 | - _Metallic: 0 70 | - _Mode: 0 71 | - _OcclusionStrength: 1 72 | - _Parallax: 0.02 73 | - _SmoothnessTextureChannel: 1 74 | - _SpecularHighlights: 1 75 | - _SrcBlend: 1 76 | - _UVSec: 0 77 | - _ZWrite: 1 78 | m_Colors: 79 | - _Color: {r: 0.26275954, g: 0.66176474, b: 0.6122331, a: 0.822} 80 | - _EmissionColor: {r: 0.08616177, g: 0.41960663, b: 0.434, a: 1} 81 | - _SpecColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} 82 | -------------------------------------------------------------------------------- /Example/example.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 8 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 0 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1} 42 | --- !u!157 &3 43 | LightmapSettings: 44 | m_ObjectHideFlags: 0 45 | serializedVersion: 11 46 | m_GIWorkflowMode: 0 47 | m_GISettings: 48 | serializedVersion: 2 49 | m_BounceScale: 1 50 | m_IndirectOutputScale: 1 51 | m_AlbedoBoost: 1 52 | m_TemporalCoherenceThreshold: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 1 55 | m_EnableRealtimeLightmaps: 1 56 | m_LightmapEditorSettings: 57 | serializedVersion: 9 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_TextureWidth: 1024 61 | m_TextureHeight: 1024 62 | m_AO: 0 63 | m_AOMaxDistance: 1 64 | m_CompAOExponent: 1 65 | m_CompAOExponentDirect: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 256 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 2 75 | m_BakeBackend: 0 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 500 79 | m_PVRBounces: 2 80 | m_PVRFilterTypeDirect: 0 81 | m_PVRFilterTypeIndirect: 0 82 | m_PVRFilterTypeAO: 0 83 | m_PVRFilteringMode: 1 84 | m_PVRCulling: 1 85 | m_PVRFilteringGaussRadiusDirect: 1 86 | m_PVRFilteringGaussRadiusIndirect: 5 87 | m_PVRFilteringGaussRadiusAO: 2 88 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 89 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 90 | m_PVRFilteringAtrousPositionSigmaAO: 1 91 | m_ShowResolutionOverlay: 1 92 | m_LightingDataAsset: {fileID: 0} 93 | m_UseShadowmask: 1 94 | --- !u!196 &4 95 | NavMeshSettings: 96 | serializedVersion: 2 97 | m_ObjectHideFlags: 0 98 | m_BuildSettings: 99 | serializedVersion: 2 100 | agentTypeID: 0 101 | agentRadius: 0.5 102 | agentHeight: 2 103 | agentSlope: 45 104 | agentClimb: 0.4 105 | ledgeDropHeight: 0 106 | maxJumpAcrossDistance: 0 107 | minRegionArea: 2 108 | manualCellSize: 0 109 | cellSize: 0.16666667 110 | manualTileSize: 0 111 | tileSize: 256 112 | accuratePlacement: 0 113 | debug: 114 | m_Flags: 0 115 | m_NavMeshData: {fileID: 0} 116 | --- !u!1 &79645593 117 | GameObject: 118 | m_ObjectHideFlags: 0 119 | m_PrefabParentObject: {fileID: 0} 120 | m_PrefabInternal: {fileID: 0} 121 | serializedVersion: 5 122 | m_Component: 123 | - component: {fileID: 79645598} 124 | - component: {fileID: 79645597} 125 | - component: {fileID: 79645596} 126 | - component: {fileID: 79645595} 127 | - component: {fileID: 79645594} 128 | m_Layer: 0 129 | m_Name: wp2 130 | m_TagString: Untagged 131 | m_Icon: {fileID: 0} 132 | m_NavMeshLayer: 0 133 | m_StaticEditorFlags: 0 134 | m_IsActive: 1 135 | --- !u!114 &79645594 136 | MonoBehaviour: 137 | m_ObjectHideFlags: 0 138 | m_PrefabParentObject: {fileID: 0} 139 | m_PrefabInternal: {fileID: 0} 140 | m_GameObject: {fileID: 79645593} 141 | m_Enabled: 1 142 | m_EditorHideFlags: 0 143 | m_Script: {fileID: 11500000, guid: 55b1bdb9d4b2b0342b8fc84328b71c30, type: 3} 144 | m_Name: 145 | m_EditorClassIdentifier: 146 | --- !u!23 &79645595 147 | MeshRenderer: 148 | m_ObjectHideFlags: 0 149 | m_PrefabParentObject: {fileID: 0} 150 | m_PrefabInternal: {fileID: 0} 151 | m_GameObject: {fileID: 79645593} 152 | m_Enabled: 1 153 | m_CastShadows: 1 154 | m_ReceiveShadows: 1 155 | m_DynamicOccludee: 1 156 | m_MotionVectors: 1 157 | m_LightProbeUsage: 1 158 | m_ReflectionProbeUsage: 1 159 | m_Materials: 160 | - {fileID: 2100000, guid: 3aa0fa22682631942a3837e3d223b319, type: 2} 161 | m_StaticBatchInfo: 162 | firstSubMesh: 0 163 | subMeshCount: 0 164 | m_StaticBatchRoot: {fileID: 0} 165 | m_ProbeAnchor: {fileID: 0} 166 | m_LightProbeVolumeOverride: {fileID: 0} 167 | m_ScaleInLightmap: 1 168 | m_PreserveUVs: 1 169 | m_IgnoreNormalsForChartDetection: 0 170 | m_ImportantGI: 0 171 | m_StitchLightmapSeams: 0 172 | m_SelectedEditorRenderState: 3 173 | m_MinimumChartSize: 4 174 | m_AutoUVMaxDistance: 0.5 175 | m_AutoUVMaxAngle: 89 176 | m_LightmapParameters: {fileID: 0} 177 | m_SortingLayerID: 0 178 | m_SortingLayer: 0 179 | m_SortingOrder: 0 180 | --- !u!65 &79645596 181 | BoxCollider: 182 | m_ObjectHideFlags: 0 183 | m_PrefabParentObject: {fileID: 0} 184 | m_PrefabInternal: {fileID: 0} 185 | m_GameObject: {fileID: 79645593} 186 | m_Material: {fileID: 0} 187 | m_IsTrigger: 0 188 | m_Enabled: 1 189 | serializedVersion: 2 190 | m_Size: {x: 1, y: 1, z: 1} 191 | m_Center: {x: 0, y: 0, z: 0} 192 | --- !u!33 &79645597 193 | MeshFilter: 194 | m_ObjectHideFlags: 0 195 | m_PrefabParentObject: {fileID: 0} 196 | m_PrefabInternal: {fileID: 0} 197 | m_GameObject: {fileID: 79645593} 198 | m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} 199 | --- !u!4 &79645598 200 | Transform: 201 | m_ObjectHideFlags: 0 202 | m_PrefabParentObject: {fileID: 0} 203 | m_PrefabInternal: {fileID: 0} 204 | m_GameObject: {fileID: 79645593} 205 | m_LocalRotation: {x: 0.19493176, y: 0.17110382, z: -0.034557614, w: 0.9651585} 206 | m_LocalPosition: {x: 0, y: 4.18, z: 0} 207 | m_LocalScale: {x: 0.5, y: 0.5, z: 0.5} 208 | m_Children: [] 209 | m_Father: {fileID: 0} 210 | m_RootOrder: 4 211 | m_LocalEulerAnglesHint: {x: 22.837002, y: 20.106, z: 0} 212 | --- !u!1 &198375900 213 | GameObject: 214 | m_ObjectHideFlags: 0 215 | m_PrefabParentObject: {fileID: 0} 216 | m_PrefabInternal: {fileID: 0} 217 | serializedVersion: 5 218 | m_Component: 219 | - component: {fileID: 198375904} 220 | - component: {fileID: 198375903} 221 | - component: {fileID: 198375902} 222 | - component: {fileID: 198375901} 223 | - component: {fileID: 198375906} 224 | - component: {fileID: 198375905} 225 | m_Layer: 0 226 | m_Name: BehaviourSphere 227 | m_TagString: Untagged 228 | m_Icon: {fileID: 0} 229 | m_NavMeshLayer: 0 230 | m_StaticEditorFlags: 0 231 | m_IsActive: 1 232 | --- !u!23 &198375901 233 | MeshRenderer: 234 | m_ObjectHideFlags: 0 235 | m_PrefabParentObject: {fileID: 0} 236 | m_PrefabInternal: {fileID: 0} 237 | m_GameObject: {fileID: 198375900} 238 | m_Enabled: 1 239 | m_CastShadows: 1 240 | m_ReceiveShadows: 1 241 | m_DynamicOccludee: 1 242 | m_MotionVectors: 1 243 | m_LightProbeUsage: 1 244 | m_ReflectionProbeUsage: 1 245 | m_Materials: 246 | - {fileID: 2100000, guid: f56bc685b518fd942a38e670388db070, type: 2} 247 | m_StaticBatchInfo: 248 | firstSubMesh: 0 249 | subMeshCount: 0 250 | m_StaticBatchRoot: {fileID: 0} 251 | m_ProbeAnchor: {fileID: 0} 252 | m_LightProbeVolumeOverride: {fileID: 0} 253 | m_ScaleInLightmap: 1 254 | m_PreserveUVs: 1 255 | m_IgnoreNormalsForChartDetection: 0 256 | m_ImportantGI: 0 257 | m_StitchLightmapSeams: 0 258 | m_SelectedEditorRenderState: 3 259 | m_MinimumChartSize: 4 260 | m_AutoUVMaxDistance: 0.5 261 | m_AutoUVMaxAngle: 89 262 | m_LightmapParameters: {fileID: 0} 263 | m_SortingLayerID: 0 264 | m_SortingLayer: 0 265 | m_SortingOrder: 0 266 | --- !u!135 &198375902 267 | SphereCollider: 268 | m_ObjectHideFlags: 0 269 | m_PrefabParentObject: {fileID: 0} 270 | m_PrefabInternal: {fileID: 0} 271 | m_GameObject: {fileID: 198375900} 272 | m_Material: {fileID: 0} 273 | m_IsTrigger: 0 274 | m_Enabled: 1 275 | serializedVersion: 2 276 | m_Radius: 0.5 277 | m_Center: {x: 0, y: 0, z: 0} 278 | --- !u!33 &198375903 279 | MeshFilter: 280 | m_ObjectHideFlags: 0 281 | m_PrefabParentObject: {fileID: 0} 282 | m_PrefabInternal: {fileID: 0} 283 | m_GameObject: {fileID: 198375900} 284 | m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} 285 | --- !u!4 &198375904 286 | Transform: 287 | m_ObjectHideFlags: 0 288 | m_PrefabParentObject: {fileID: 0} 289 | m_PrefabInternal: {fileID: 0} 290 | m_GameObject: {fileID: 198375900} 291 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 292 | m_LocalPosition: {x: -2.53, y: 0, z: 0} 293 | m_LocalScale: {x: 1, y: 1, z: 1} 294 | m_Children: [] 295 | m_Father: {fileID: 0} 296 | m_RootOrder: 1 297 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 298 | --- !u!114 &198375905 299 | MonoBehaviour: 300 | m_ObjectHideFlags: 0 301 | m_PrefabParentObject: {fileID: 0} 302 | m_PrefabInternal: {fileID: 0} 303 | m_GameObject: {fileID: 198375900} 304 | m_Enabled: 1 305 | m_EditorHideFlags: 0 306 | m_Script: {fileID: 11500000, guid: 3f9d7d6484b685c4aaf20be9b7610268, type: 3} 307 | m_Name: 308 | m_EditorClassIdentifier: 309 | --- !u!114 &198375906 310 | MonoBehaviour: 311 | m_ObjectHideFlags: 0 312 | m_PrefabParentObject: {fileID: 0} 313 | m_PrefabInternal: {fileID: 0} 314 | m_GameObject: {fileID: 198375900} 315 | m_Enabled: 1 316 | m_EditorHideFlags: 0 317 | m_Script: {fileID: 11500000, guid: 0a42377429ca0704eadf2a777daf71e4, type: 3} 318 | m_Name: 319 | m_EditorClassIdentifier: 320 | waypoints: 321 | - {fileID: 1483189095} 322 | - {fileID: 79645594} 323 | - {fileID: 1967686624} 324 | --- !u!1 &1192597011 325 | GameObject: 326 | m_ObjectHideFlags: 0 327 | m_PrefabParentObject: {fileID: 0} 328 | m_PrefabInternal: {fileID: 0} 329 | serializedVersion: 5 330 | m_Component: 331 | - component: {fileID: 1192597013} 332 | - component: {fileID: 1192597012} 333 | m_Layer: 0 334 | m_Name: Point light 335 | m_TagString: Untagged 336 | m_Icon: {fileID: 0} 337 | m_NavMeshLayer: 0 338 | m_StaticEditorFlags: 0 339 | m_IsActive: 1 340 | --- !u!108 &1192597012 341 | Light: 342 | m_ObjectHideFlags: 0 343 | m_PrefabParentObject: {fileID: 0} 344 | m_PrefabInternal: {fileID: 0} 345 | m_GameObject: {fileID: 1192597011} 346 | m_Enabled: 1 347 | serializedVersion: 8 348 | m_Type: 2 349 | m_Color: {r: 1, g: 1, b: 1, a: 1} 350 | m_Intensity: 1 351 | m_Range: 10 352 | m_SpotAngle: 30 353 | m_CookieSize: 10 354 | m_Shadows: 355 | m_Type: 0 356 | m_Resolution: -1 357 | m_CustomResolution: -1 358 | m_Strength: 1 359 | m_Bias: 0.05 360 | m_NormalBias: 0.4 361 | m_NearPlane: 0.2 362 | m_Cookie: {fileID: 0} 363 | m_DrawHalo: 0 364 | m_Flare: {fileID: 0} 365 | m_RenderMode: 0 366 | m_CullingMask: 367 | serializedVersion: 2 368 | m_Bits: 4294967295 369 | m_Lightmapping: 4 370 | m_AreaSize: {x: 1, y: 1} 371 | m_BounceIntensity: 1 372 | m_ColorTemperature: 6570 373 | m_UseColorTemperature: 0 374 | m_ShadowRadius: 0 375 | m_ShadowAngle: 0 376 | --- !u!4 &1192597013 377 | Transform: 378 | m_ObjectHideFlags: 0 379 | m_PrefabParentObject: {fileID: 0} 380 | m_PrefabInternal: {fileID: 0} 381 | m_GameObject: {fileID: 1192597011} 382 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 383 | m_LocalPosition: {x: 0, y: 0, z: -1.97} 384 | m_LocalScale: {x: 1, y: 1, z: 1} 385 | m_Children: [] 386 | m_Father: {fileID: 0} 387 | m_RootOrder: 2 388 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 389 | --- !u!1 &1458245724 390 | GameObject: 391 | m_ObjectHideFlags: 0 392 | m_PrefabParentObject: {fileID: 0} 393 | m_PrefabInternal: {fileID: 0} 394 | serializedVersion: 5 395 | m_Component: 396 | - component: {fileID: 1458245728} 397 | - component: {fileID: 1458245727} 398 | - component: {fileID: 1458245726} 399 | - component: {fileID: 1458245725} 400 | m_Layer: 0 401 | m_Name: Main Camera 402 | m_TagString: MainCamera 403 | m_Icon: {fileID: 0} 404 | m_NavMeshLayer: 0 405 | m_StaticEditorFlags: 0 406 | m_IsActive: 1 407 | --- !u!81 &1458245725 408 | AudioListener: 409 | m_ObjectHideFlags: 0 410 | m_PrefabParentObject: {fileID: 0} 411 | m_PrefabInternal: {fileID: 0} 412 | m_GameObject: {fileID: 1458245724} 413 | m_Enabled: 1 414 | --- !u!124 &1458245726 415 | Behaviour: 416 | m_ObjectHideFlags: 0 417 | m_PrefabParentObject: {fileID: 0} 418 | m_PrefabInternal: {fileID: 0} 419 | m_GameObject: {fileID: 1458245724} 420 | m_Enabled: 1 421 | --- !u!20 &1458245727 422 | Camera: 423 | m_ObjectHideFlags: 0 424 | m_PrefabParentObject: {fileID: 0} 425 | m_PrefabInternal: {fileID: 0} 426 | m_GameObject: {fileID: 1458245724} 427 | m_Enabled: 1 428 | serializedVersion: 2 429 | m_ClearFlags: 2 430 | m_BackGroundColor: {r: 0.6002864, g: 0.39987025, b: 0.63235295, a: 0} 431 | m_NormalizedViewPortRect: 432 | serializedVersion: 2 433 | x: 0 434 | y: 0 435 | width: 1 436 | height: 1 437 | near clip plane: 0.3 438 | far clip plane: 1000 439 | field of view: 60 440 | orthographic: 0 441 | orthographic size: 5 442 | m_Depth: -1 443 | m_CullingMask: 444 | serializedVersion: 2 445 | m_Bits: 4294967295 446 | m_RenderingPath: -1 447 | m_TargetTexture: {fileID: 0} 448 | m_TargetDisplay: 0 449 | m_TargetEye: 3 450 | m_HDR: 1 451 | m_AllowMSAA: 1 452 | m_AllowDynamicResolution: 0 453 | m_ForceIntoRT: 0 454 | m_OcclusionCulling: 1 455 | m_StereoConvergence: 10 456 | m_StereoSeparation: 0.022 457 | --- !u!4 &1458245728 458 | Transform: 459 | m_ObjectHideFlags: 0 460 | m_PrefabParentObject: {fileID: 0} 461 | m_PrefabInternal: {fileID: 0} 462 | m_GameObject: {fileID: 1458245724} 463 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 464 | m_LocalPosition: {x: 0, y: 0, z: -10} 465 | m_LocalScale: {x: 1, y: 1, z: 1} 466 | m_Children: [] 467 | m_Father: {fileID: 0} 468 | m_RootOrder: 0 469 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 470 | --- !u!1 &1483189094 471 | GameObject: 472 | m_ObjectHideFlags: 0 473 | m_PrefabParentObject: {fileID: 0} 474 | m_PrefabInternal: {fileID: 0} 475 | serializedVersion: 5 476 | m_Component: 477 | - component: {fileID: 1483189099} 478 | - component: {fileID: 1483189098} 479 | - component: {fileID: 1483189097} 480 | - component: {fileID: 1483189096} 481 | - component: {fileID: 1483189095} 482 | m_Layer: 0 483 | m_Name: wp1 484 | m_TagString: Untagged 485 | m_Icon: {fileID: 0} 486 | m_NavMeshLayer: 0 487 | m_StaticEditorFlags: 0 488 | m_IsActive: 1 489 | --- !u!114 &1483189095 490 | MonoBehaviour: 491 | m_ObjectHideFlags: 0 492 | m_PrefabParentObject: {fileID: 0} 493 | m_PrefabInternal: {fileID: 0} 494 | m_GameObject: {fileID: 1483189094} 495 | m_Enabled: 1 496 | m_EditorHideFlags: 0 497 | m_Script: {fileID: 11500000, guid: 55b1bdb9d4b2b0342b8fc84328b71c30, type: 3} 498 | m_Name: 499 | m_EditorClassIdentifier: 500 | --- !u!23 &1483189096 501 | MeshRenderer: 502 | m_ObjectHideFlags: 0 503 | m_PrefabParentObject: {fileID: 0} 504 | m_PrefabInternal: {fileID: 0} 505 | m_GameObject: {fileID: 1483189094} 506 | m_Enabled: 1 507 | m_CastShadows: 1 508 | m_ReceiveShadows: 1 509 | m_DynamicOccludee: 1 510 | m_MotionVectors: 1 511 | m_LightProbeUsage: 1 512 | m_ReflectionProbeUsage: 1 513 | m_Materials: 514 | - {fileID: 2100000, guid: 3aa0fa22682631942a3837e3d223b319, type: 2} 515 | m_StaticBatchInfo: 516 | firstSubMesh: 0 517 | subMeshCount: 0 518 | m_StaticBatchRoot: {fileID: 0} 519 | m_ProbeAnchor: {fileID: 0} 520 | m_LightProbeVolumeOverride: {fileID: 0} 521 | m_ScaleInLightmap: 1 522 | m_PreserveUVs: 1 523 | m_IgnoreNormalsForChartDetection: 0 524 | m_ImportantGI: 0 525 | m_StitchLightmapSeams: 0 526 | m_SelectedEditorRenderState: 3 527 | m_MinimumChartSize: 4 528 | m_AutoUVMaxDistance: 0.5 529 | m_AutoUVMaxAngle: 89 530 | m_LightmapParameters: {fileID: 0} 531 | m_SortingLayerID: 0 532 | m_SortingLayer: 0 533 | m_SortingOrder: 0 534 | --- !u!65 &1483189097 535 | BoxCollider: 536 | m_ObjectHideFlags: 0 537 | m_PrefabParentObject: {fileID: 0} 538 | m_PrefabInternal: {fileID: 0} 539 | m_GameObject: {fileID: 1483189094} 540 | m_Material: {fileID: 0} 541 | m_IsTrigger: 0 542 | m_Enabled: 1 543 | serializedVersion: 2 544 | m_Size: {x: 1, y: 1, z: 1} 545 | m_Center: {x: 0, y: 0, z: 0} 546 | --- !u!33 &1483189098 547 | MeshFilter: 548 | m_ObjectHideFlags: 0 549 | m_PrefabParentObject: {fileID: 0} 550 | m_PrefabInternal: {fileID: 0} 551 | m_GameObject: {fileID: 1483189094} 552 | m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} 553 | --- !u!4 &1483189099 554 | Transform: 555 | m_ObjectHideFlags: 0 556 | m_PrefabParentObject: {fileID: 0} 557 | m_PrefabInternal: {fileID: 0} 558 | m_GameObject: {fileID: 1483189094} 559 | m_LocalRotation: {x: -0.24435875, y: -0.2510821, z: -0.25440866, w: 0.90140045} 560 | m_LocalPosition: {x: 5.1, y: -1.42, z: 0} 561 | m_LocalScale: {x: 0.5, y: 0.5, z: 0.5} 562 | m_Children: [] 563 | m_Father: {fileID: 0} 564 | m_RootOrder: 3 565 | m_LocalEulerAnglesHint: {x: -34.631, y: -23.516, z: -24.096} 566 | --- !u!1 &1967686623 567 | GameObject: 568 | m_ObjectHideFlags: 0 569 | m_PrefabParentObject: {fileID: 0} 570 | m_PrefabInternal: {fileID: 0} 571 | serializedVersion: 5 572 | m_Component: 573 | - component: {fileID: 1967686628} 574 | - component: {fileID: 1967686627} 575 | - component: {fileID: 1967686626} 576 | - component: {fileID: 1967686625} 577 | - component: {fileID: 1967686624} 578 | m_Layer: 0 579 | m_Name: wp3 580 | m_TagString: Untagged 581 | m_Icon: {fileID: 0} 582 | m_NavMeshLayer: 0 583 | m_StaticEditorFlags: 0 584 | m_IsActive: 1 585 | --- !u!114 &1967686624 586 | MonoBehaviour: 587 | m_ObjectHideFlags: 0 588 | m_PrefabParentObject: {fileID: 0} 589 | m_PrefabInternal: {fileID: 0} 590 | m_GameObject: {fileID: 1967686623} 591 | m_Enabled: 1 592 | m_EditorHideFlags: 0 593 | m_Script: {fileID: 11500000, guid: 55b1bdb9d4b2b0342b8fc84328b71c30, type: 3} 594 | m_Name: 595 | m_EditorClassIdentifier: 596 | --- !u!23 &1967686625 597 | MeshRenderer: 598 | m_ObjectHideFlags: 0 599 | m_PrefabParentObject: {fileID: 0} 600 | m_PrefabInternal: {fileID: 0} 601 | m_GameObject: {fileID: 1967686623} 602 | m_Enabled: 1 603 | m_CastShadows: 1 604 | m_ReceiveShadows: 1 605 | m_DynamicOccludee: 1 606 | m_MotionVectors: 1 607 | m_LightProbeUsage: 1 608 | m_ReflectionProbeUsage: 1 609 | m_Materials: 610 | - {fileID: 2100000, guid: 3aa0fa22682631942a3837e3d223b319, type: 2} 611 | m_StaticBatchInfo: 612 | firstSubMesh: 0 613 | subMeshCount: 0 614 | m_StaticBatchRoot: {fileID: 0} 615 | m_ProbeAnchor: {fileID: 0} 616 | m_LightProbeVolumeOverride: {fileID: 0} 617 | m_ScaleInLightmap: 1 618 | m_PreserveUVs: 1 619 | m_IgnoreNormalsForChartDetection: 0 620 | m_ImportantGI: 0 621 | m_StitchLightmapSeams: 0 622 | m_SelectedEditorRenderState: 3 623 | m_MinimumChartSize: 4 624 | m_AutoUVMaxDistance: 0.5 625 | m_AutoUVMaxAngle: 89 626 | m_LightmapParameters: {fileID: 0} 627 | m_SortingLayerID: 0 628 | m_SortingLayer: 0 629 | m_SortingOrder: 0 630 | --- !u!65 &1967686626 631 | BoxCollider: 632 | m_ObjectHideFlags: 0 633 | m_PrefabParentObject: {fileID: 0} 634 | m_PrefabInternal: {fileID: 0} 635 | m_GameObject: {fileID: 1967686623} 636 | m_Material: {fileID: 0} 637 | m_IsTrigger: 0 638 | m_Enabled: 1 639 | serializedVersion: 2 640 | m_Size: {x: 1, y: 1, z: 1} 641 | m_Center: {x: 0, y: 0, z: 0} 642 | --- !u!33 &1967686627 643 | MeshFilter: 644 | m_ObjectHideFlags: 0 645 | m_PrefabParentObject: {fileID: 0} 646 | m_PrefabInternal: {fileID: 0} 647 | m_GameObject: {fileID: 1967686623} 648 | m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} 649 | --- !u!4 &1967686628 650 | Transform: 651 | m_ObjectHideFlags: 0 652 | m_PrefabParentObject: {fileID: 0} 653 | m_PrefabInternal: {fileID: 0} 654 | m_GameObject: {fileID: 1967686623} 655 | m_LocalRotation: {x: 0.47066876, y: 0.47551182, z: 0.10673601, w: 0.7355045} 656 | m_LocalPosition: {x: -4.34, y: -3.13, z: 0} 657 | m_LocalScale: {x: 0.5, y: 0.5, z: 0.5} 658 | m_Children: [] 659 | m_Father: {fileID: 0} 660 | m_RootOrder: 5 661 | m_LocalEulerAnglesHint: {x: 36.217003, y: 82.54201, z: 48.541004} 662 | --------------------------------------------------------------------------------