├── Images ├── 20220115_163620.gif └── 20220115_163620.gif.meta ├── Core ├── Interfaces │ ├── ITask.cs.meta │ ├── IUpdateTask.cs.meta │ ├── ITask.cs │ └── IUpdateTask.cs ├── ViewModel │ ├── TaskState.cs.meta │ ├── TaskProcessor.cs.meta │ ├── ActionTaskProcessor.cs.meta │ ├── CompsiteTaskProcessor.cs.meta │ ├── ContainerTaskProcessor.cs.meta │ ├── DecoratorTaskProcessor.cs.meta │ ├── TaskState.cs │ ├── ActionTaskProcessor.cs │ ├── CompsiteTaskProcessor.cs │ ├── DecoratorTaskProcessor.cs │ ├── ContainerTaskProcessor.cs │ └── TaskProcessor.cs ├── Model.meta ├── Tasks.meta ├── ViewModel.meta ├── Interfaces.meta ├── Tasks │ ├── Actions.meta │ ├── Composites.meta │ ├── Decorators.meta │ ├── Entry.cs.meta │ ├── Actions │ │ ├── FailureTask.cs.meta │ │ ├── SuccessTask.cs.meta │ │ ├── FailureTask.cs │ │ └── SuccessTask.cs │ ├── Composites │ │ ├── Selector.cs.meta │ │ ├── Sequence.cs.meta │ │ ├── RandomSelector.cs.meta │ │ ├── RandomSequence.cs.meta │ │ ├── ParallelSelector.cs.meta │ │ ├── ParallelSequence.cs.meta │ │ ├── Selector.cs │ │ ├── ParallelSelector.cs │ │ ├── Sequence.cs │ │ ├── ParallelSequence.cs │ │ ├── RandomSelector.cs │ │ └── RandomSequence.cs │ ├── Decorators │ │ ├── Failure.cs.meta │ │ ├── Inverter.cs.meta │ │ ├── Repeater.cs.meta │ │ ├── Success.cs.meta │ │ ├── Success.cs │ │ ├── Failure.cs │ │ ├── Inverter.cs │ │ └── Repeater.cs │ └── Entry.cs ├── Model │ ├── Task.cs.meta │ ├── ActionTask.cs.meta │ ├── Compsite.cs.meta │ ├── Decorator.cs.meta │ ├── Compsite.cs │ ├── ActionTask.cs │ ├── Decorator.cs │ └── Task.cs ├── BehaviorTree.cs.meta └── BehaviorTree.cs ├── UnityEX ├── Editor │ ├── Resources │ │ ├── BehaviorTree │ │ │ ├── Icons │ │ │ │ ├── Debug.png │ │ │ │ ├── Entry.png │ │ │ │ ├── Default.png │ │ │ │ ├── Parallel.png │ │ │ │ ├── Repeater.png │ │ │ │ ├── Selector.png │ │ │ │ ├── Sequence.png │ │ │ │ ├── Conditional.png │ │ │ │ ├── RandomSequence.png │ │ │ │ ├── Default.png.meta │ │ │ │ ├── Entry.png.meta │ │ │ │ ├── Selector.png.meta │ │ │ │ ├── Sequence.png.meta │ │ │ │ ├── Conditional.png.meta │ │ │ │ ├── Debug.png.meta │ │ │ │ ├── Parallel.png.meta │ │ │ │ ├── Repeater.png.meta │ │ │ │ └── RandomSequence.png.meta │ │ │ ├── Icons.meta │ │ │ ├── Uss.meta │ │ │ └── Uss │ │ │ │ ├── Task.uss.meta │ │ │ │ └── Task.uss │ │ └── BehaviorTree.meta │ ├── Resources.meta │ ├── EntryView.cs.meta │ ├── TaskView.cs.meta │ ├── BehaviorTreeGraphView.cs.meta │ ├── BehaviorTreeGraphWindow.cs.meta │ ├── EntryView.cs │ ├── BehaviorTreeGraphView.cs │ ├── TaskView.cs │ └── BehaviorTreeGraphWindow.cs ├── Editor.meta ├── Runtime.meta └── Runtime │ ├── Tasks.meta │ ├── Tasks │ ├── Actions.meta │ └── Actions │ │ ├── Wait.cs.meta │ │ ├── LogTask.cs.meta │ │ ├── LogTask.cs │ │ └── Wait.cs │ ├── BehaviorTreeAsset.cs.meta │ ├── TaskIconAttribute.cs.meta │ ├── TaskIconAttribute.cs │ └── BehaviorTreeAsset.cs ├── LICENSE.meta ├── README.md.meta ├── Core.meta ├── Example ├── Example.unity.meta ├── New Behavior Tree Asset.asset.meta ├── SeekAction.cs.meta ├── WanderAction.cs.meta ├── BehaviorTreeTest.cs.meta ├── BehaviorTreeTest.cs ├── SeekAction.cs ├── WanderAction.cs ├── New Behavior Tree Asset.asset └── Example.unity ├── Example.meta ├── Images.meta ├── UnityEX.meta ├── Atom.BehaviorTree.asmdef.meta ├── README.md ├── Atom.BehaviorTree.asmdef ├── LICENSE └── .gitignore /Images/20220115_163620.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haloman9527/3.3_BehaviorTree/HEAD/Images/20220115_163620.gif -------------------------------------------------------------------------------- /Core/Interfaces/ITask.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3361547e9b844100a2d821ca2656dc6c 3 | timeCreated: 1671337886 -------------------------------------------------------------------------------- /Core/ViewModel/TaskState.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 94a1da8f94524fe8a5868919e1874b6e 3 | timeCreated: 1671338285 -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haloman9527/3.3_BehaviorTree/HEAD/UnityEX/Editor/Resources/BehaviorTree/Icons/Debug.png -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haloman9527/3.3_BehaviorTree/HEAD/UnityEX/Editor/Resources/BehaviorTree/Icons/Entry.png -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haloman9527/3.3_BehaviorTree/HEAD/UnityEX/Editor/Resources/BehaviorTree/Icons/Default.png -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Parallel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haloman9527/3.3_BehaviorTree/HEAD/UnityEX/Editor/Resources/BehaviorTree/Icons/Parallel.png -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Repeater.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haloman9527/3.3_BehaviorTree/HEAD/UnityEX/Editor/Resources/BehaviorTree/Icons/Repeater.png -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Selector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haloman9527/3.3_BehaviorTree/HEAD/UnityEX/Editor/Resources/BehaviorTree/Icons/Selector.png -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haloman9527/3.3_BehaviorTree/HEAD/UnityEX/Editor/Resources/BehaviorTree/Icons/Sequence.png -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Conditional.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haloman9527/3.3_BehaviorTree/HEAD/UnityEX/Editor/Resources/BehaviorTree/Icons/Conditional.png -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/RandomSequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haloman9527/3.3_BehaviorTree/HEAD/UnityEX/Editor/Resources/BehaviorTree/Icons/RandomSequence.png -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0c648c5a8fe15594f865149d6ccb1ea6 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 92452c41ec5c21940b3f254e5b8eba55 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Core.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3c0ac8b5685b78f4a96f5763b490953e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/Example.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4e4d66b6cb11f5f4191449a0c5163148 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Example.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b1d68a77275c5474186aad180906797a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Images.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2b8863eb62cd6ad4cb672070132a572a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /UnityEX.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8427dd0cdf36ad843a7db1f534e21e6c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Atom.BehaviorTree.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cfa3cc2099e3f3a42878f1ad32e10715 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Core/Model.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8e2a61cfe14ed144db6c2d58f527bc2f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Core/Tasks.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ede6d9580e962ae47942cabc859bf64a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Core/ViewModel.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0272869f8ac5e12418d6d18b34e94499 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /UnityEX/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9bcac60e572faac4da0dcd62c6ed61e6 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Core/Interfaces.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3b5d12f1413f2614ab0b4ff686b2e164 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Core/Tasks/Actions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e7eca747012002e428d07316f6869499 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /UnityEX/Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 614abc4644909754d8ddbfefafe7cbad 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Core/Tasks/Composites.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3d5f4df49fa3e5a4f85013bf77887135 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Core/Tasks/Decorators.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c9961359123634a41891d5f59fdf8d5f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0677ba63246ec5b4faf2cece6d4e015b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /UnityEX/Runtime/Tasks.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6b43994e6875a10429173baceb1346c8 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /UnityEX/Runtime/Tasks/Actions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e3f2b259d2380b94bbdcd25c3ef0e5a3 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: abb2def679fedd044b8c0ab921f2beb2 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ef44405c2ffde8743ae6cab5b7a37ef5 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Uss.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d86f9c638b0d5474a9f947f1b8d37991 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Example/New Behavior Tree Asset.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7ce38845b77af33449d3d52f03737add 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Core/Model/Task.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7b8341b8eafa49842bbe16080848ee80 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Entry.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3c8928e972a8d76479eba6523b13b252 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/BehaviorTree.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cad4ca6e965e2ea4490ee2fbd4be1520 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Model/ActionTask.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 113a388084a5a954ba9d30c06c40a59d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Model/Compsite.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ec4a9bf8722a37545bda8a558b6beea0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Model/Decorator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 45698a21e2c9f8240beb98ec0da63b95 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/SeekAction.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 73f7bb9c398e6054face2b5a4882b425 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/WanderAction.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f22835f3ebf7a9449a12e942e2faf31e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Example/BehaviorTreeTest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 914a8c2649986da458d5883776035e54 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /UnityEX/Editor/EntryView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f890876b480567f439503c891ec437c4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /UnityEX/Editor/TaskView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f518a56a10802fb4ea71fbca95e13b30 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Interfaces/IUpdateTask.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8f307fbf3ef1e294a8136e5310a8352e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Actions/FailureTask.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a99a4ea691997d446a5be7eae3c0ce36 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Actions/SuccessTask.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: be68be87e2833a34b936c9cd27a19d87 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Composites/Selector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7df86de00369e4542b396ee823fa07e1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Composites/Sequence.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1bdbfcbb1011f0e4892aa470918e499f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Decorators/Failure.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 38ee9bfb1be422f4dbede77678107c11 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Decorators/Inverter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cac767316fcbfcd479afe0774b29ecf9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Decorators/Repeater.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f1a54a124db8eb94d987627cc9756a68 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Decorators/Success.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 746c6154967e67f4399459389c23e6a0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/ViewModel/TaskProcessor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5744194b88f4a1f4e85f825de98e90ad 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Composites/RandomSelector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: aa8bd3d3bebbc9e46b087db4df04ea07 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Composites/RandomSequence.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 07c60ab3c0ca0d849964388156eeaa92 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/ViewModel/ActionTaskProcessor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 23d427d64d054da44a8c078686bcdc20 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/ViewModel/CompsiteTaskProcessor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f726ab3c12eb283459e16db303b6461e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /UnityEX/Editor/BehaviorTreeGraphView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ad8471d35dde1044489cbb119a9fa5d5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /UnityEX/Runtime/BehaviorTreeAsset.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 35d5fd334e30ba047b2e4ab52e51f858 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /UnityEX/Runtime/TaskIconAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7644c5004f6318f44a34e4c00b20ccc7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /UnityEX/Runtime/Tasks/Actions/Wait.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9feb3f30dd2349f4d96c5d94dcc0a837 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/ViewModel/ContainerTaskProcessor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d82810cf160f40a47abffae1166cba76 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/ViewModel/DecoratorTaskProcessor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bf92883a2ec106345bfa1d852116b6f2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 3.3_BehaviorTree 2 | 行为树 3 | 4 | 5 | 依赖[0.0_Common](https://github.com/HalfLobsterMan/0.0_Common.git) 6 | 7 | 依赖[3.0_GraphProcessor](https://github.com/HalfLobsterMan/3.0_GraphProcessor.git) 8 | 9 | 依赖[OdinSerializer](https://github.com/TeamSirenix/odin-serializer.git) 10 | 11 | ![预览](./Images/20220115_163620.gif) 12 | -------------------------------------------------------------------------------- /UnityEX/Editor/BehaviorTreeGraphWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b27f138362e8da441bdfe745158b159a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Composites/ParallelSelector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d09352a639ca753499341df70211d23e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Tasks/Composites/ParallelSequence.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0219e9c25ecfaae49b0136abe9e69079 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /UnityEX/Runtime/Tasks/Actions/LogTask.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9eddbfe513ad13243afb9978eb6dc954 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Core/Model/Compsite.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | namespace Atom.BehaviorTree 18 | { 19 | public abstract class Composite : Task { } 20 | } -------------------------------------------------------------------------------- /Core/Model/ActionTask.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | namespace Atom.BehaviorTree 18 | { 19 | public abstract partial class ActionTask : Task { } 20 | } -------------------------------------------------------------------------------- /Core/Model/Decorator.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | namespace Atom.BehaviorTree 18 | { 19 | public abstract partial class Decorator : Task { } 20 | } 21 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Uss/Task.uss.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9baed5a397a1318489c6d795076e16b8 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} 11 | disableValidation: 0 12 | -------------------------------------------------------------------------------- /Core/Interfaces/ITask.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | namespace Atom.BehaviorTree 18 | { 19 | public interface ITask 20 | { 21 | TaskState CurrentState { get; } 22 | } 23 | } -------------------------------------------------------------------------------- /Core/Interfaces/IUpdateTask.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | namespace Atom.BehaviorTree 20 | { 21 | public interface IUpdateTask : ITask 22 | { 23 | void Update(); 24 | } 25 | } -------------------------------------------------------------------------------- /Core/Model/Task.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | using Atom.GraphProcessor; 18 | 19 | namespace Atom.BehaviorTree 20 | { 21 | [TaskIcon("BehaviorTree/Icons/Default")] 22 | public abstract class Task : BaseNode { } 23 | } 24 | -------------------------------------------------------------------------------- /Core/ViewModel/TaskState.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.GraphProcessor; 20 | using System; 21 | 22 | namespace Atom.BehaviorTree 23 | { 24 | public enum TaskState 25 | { 26 | InActive, 27 | Active, 28 | } 29 | } -------------------------------------------------------------------------------- /Atom.BehaviorTree.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Atom.BehaviorTree", 3 | "rootNamespace": "", 4 | "references": [ 5 | "Atom.Lib", 6 | "Atom.GraphProcessor", 7 | "Atom.ECS" 8 | ], 9 | "includePlatforms": [], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": true, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /UnityEX/Runtime/TaskIconAttribute.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | using System; 17 | 18 | namespace Atom.BehaviorTree 19 | { 20 | public class TaskIconAttribute : Attribute 21 | { 22 | public readonly string path; 23 | public TaskIconAttribute(string path) 24 | { 25 | this.path = path; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /UnityEX/Editor/EntryView.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | #if UNITY_EDITOR 18 | using Atom.GraphProcessor.Editors; 19 | 20 | namespace Atom.BehaviorTree.Editors 21 | { 22 | [CustomView(typeof(Entry))] 23 | public class EntryView : TaskView 24 | { 25 | protected override void DoInit() 26 | { 27 | base.DoInit(); 28 | this.Deletable = false; 29 | this.Movable = false; 30 | } 31 | } 32 | } 33 | #endif 34 | -------------------------------------------------------------------------------- /Core/ViewModel/ActionTaskProcessor.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | using Atom.GraphProcessor; 18 | 19 | namespace Atom.BehaviorTree 20 | { 21 | public abstract class ActionTaskProcessor : TaskProcessor 22 | { 23 | protected ActionTaskProcessor(Task model) : base(model) 24 | { 25 | AddPort(new PortProcessor(TaskProcessor.ParentPortName, BasePort.Direction.Top, BasePort.Capacity.Single, typeof(ContainerTaskProcessor))); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /UnityEX/Runtime/BehaviorTreeAsset.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using System; 20 | using Atom.GraphProcessor; 21 | using UnityEngine; 22 | using UnityEngine.Serialization; 23 | 24 | namespace Atom.BehaviorTree 25 | { 26 | [CreateAssetMenu] 27 | public class BehaviorTreeAsset : ScriptableObject, IGraphAsset 28 | { 29 | [FormerlySerializedAs("graph")] [SerializeField] private BehaviorTree data; 30 | 31 | public Type GraphType => typeof(BehaviorTree); 32 | 33 | public void SaveGraph(BaseGraph graph) => this.data = (BehaviorTree)graph; 34 | 35 | public BaseGraph LoadGraph() => data; 36 | } 37 | } -------------------------------------------------------------------------------- /Core/ViewModel/CompsiteTaskProcessor.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using System.Collections.Generic; 20 | using Atom.GraphProcessor; 21 | 22 | namespace Atom.BehaviorTree 23 | { 24 | public abstract class CompositeTaskProcessor : ContainerTaskProcessor 25 | { 26 | protected CompositeTaskProcessor(Task model) : base(model) 27 | { 28 | AddPort(new PortProcessor(TaskProcessor.ParentPortName, BasePort.Direction.Top, BasePort.Capacity.Single, typeof(ContainerTaskProcessor))); 29 | AddPort(new PortProcessor(TaskProcessor.ChildrenPortName, BasePort.Direction.Bottom, BasePort.Capacity.Multi, typeof(TaskProcessor))); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Core/Tasks/Decorators/Success.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | using Atom.GraphProcessor; 18 | using Atom; 19 | 20 | namespace Atom.BehaviorTree 21 | { 22 | [NodeTooltip("始终返回Success")] 23 | [NodeMenu("Decorator/Success")] 24 | public class Success : Task { } 25 | 26 | [ViewModel(typeof(Success))] 27 | public class SuccessProcessor : DecoratorTaskProcessor 28 | { 29 | public SuccessProcessor(Success model) : base(model) { } 30 | 31 | protected override void DoStart() 32 | { 33 | Child.Start(); 34 | } 35 | 36 | protected override void OnChildStopped(TaskProcessor child, bool result) 37 | { 38 | SelfStop(true); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Core/Tasks/Decorators/Failure.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | using Atom.GraphProcessor; 18 | using Atom; 19 | 20 | namespace Atom.BehaviorTree 21 | { 22 | [NodeTooltip("始终返回Failure")] 23 | [NodeMenu("Decorator/Failure")] 24 | public class Failure : Task { } 25 | 26 | [ViewModel(typeof(Failure))] 27 | public class FailureProcessor : DecoratorTaskProcessor 28 | { 29 | public FailureProcessor(Failure model) : base(model) { } 30 | 31 | protected override void DoStart() 32 | { 33 | Child.Start(); 34 | } 35 | 36 | protected override void OnChildStopped(TaskProcessor child, bool succeeded) 37 | { 38 | SelfStop(false); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Core/Tasks/Decorators/Inverter.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | using Atom.GraphProcessor; 18 | using Atom; 19 | 20 | namespace Atom.BehaviorTree 21 | { 22 | [NodeTooltip("始终返回相反的结果")] 23 | [NodeMenu("Decorator/Inverter")] 24 | public class Inverter : Task { } 25 | 26 | [ViewModel(typeof(Inverter))] 27 | public class InverterProcessor : DecoratorTaskProcessor 28 | { 29 | public InverterProcessor(Inverter model) : base(model) { } 30 | 31 | protected override void DoStart() 32 | { 33 | Child.Start(); 34 | } 35 | 36 | protected override void OnChildStopped(TaskProcessor child, bool result) 37 | { 38 | SelfStop(!result); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Core/ViewModel/DecoratorTaskProcessor.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.GraphProcessor; 20 | 21 | namespace Atom.BehaviorTree 22 | { 23 | public abstract class DecoratorTaskProcessor : ContainerTaskProcessor 24 | { 25 | protected TaskProcessor Child 26 | { 27 | get { return Children.Count == 0 ? null : Children[0]; } 28 | } 29 | 30 | protected DecoratorTaskProcessor(Task model) : base(model) 31 | { 32 | AddPort(new PortProcessor(TaskProcessor.ParentPortName, BasePort.Direction.Top, BasePort.Capacity.Single, typeof(ContainerTaskProcessor))); 33 | AddPort(new PortProcessor(TaskProcessor.ChildrenPortName, BasePort.Direction.Bottom, BasePort.Capacity.Single, typeof(TaskProcessor))); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /Core/Tasks/Actions/FailureTask.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | using Atom.GraphProcessor; 18 | 19 | namespace Atom.BehaviorTree 20 | { 21 | [TaskIcon("BehaviorTree/Icons/Debug")] 22 | [NodeMenu("Action/Failure")] 23 | public class FailureTask : Task 24 | { 25 | 26 | } 27 | 28 | [ViewModel(typeof(FailureTask))] 29 | public class FailureTaskProcessor : ActionTaskProcessor 30 | { 31 | public FailureTaskProcessor(FailureTask model) : base(model) 32 | { 33 | 34 | } 35 | 36 | protected override void DoStart() 37 | { 38 | SelfStop(false); 39 | } 40 | 41 | protected override void DoStop() 42 | { 43 | SelfStop(false); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Core/Tasks/Actions/SuccessTask.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | using Atom.GraphProcessor; 18 | 19 | namespace Atom.BehaviorTree 20 | { 21 | [TaskIcon("BehaviorTree/Icons/Debug")] 22 | [NodeMenu("Action/Success")] 23 | public class SuccessTask : Task 24 | { 25 | 26 | } 27 | 28 | [ViewModel(typeof(SuccessTask))] 29 | public class SuccessTaskProcessor : ActionTaskProcessor 30 | { 31 | public SuccessTaskProcessor(SuccessTask model) : base(model) 32 | { 33 | 34 | } 35 | 36 | protected override void DoStart() 37 | { 38 | SelfStop(true); 39 | } 40 | 41 | protected override void DoStop() 42 | { 43 | SelfStop(false); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 半只龙虾人 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Asset meta data should only be ignored when the corresponding asset is also ignored 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | *.mdb 43 | *.opendb 44 | *.VC.db 45 | 46 | # Unity3D generated meta files 47 | *.pidb.meta 48 | *.pdb.meta 49 | *.mdb.meta 50 | 51 | # Unity3D generated file on crash reports 52 | sysinfo.txt 53 | 54 | # Builds 55 | *.apk 56 | *.unitypackage 57 | 58 | # Crashlytics generated file 59 | crashlytics-build.properties 60 | 61 | -------------------------------------------------------------------------------- /UnityEX/Runtime/Tasks/Actions/LogTask.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.GraphProcessor; 20 | using Atom; 21 | using UnityEngine; 22 | 23 | namespace Atom.BehaviorTree 24 | { 25 | [TaskIcon("BehaviorTree/Icons/Debug")] 26 | [NodeMenu("Action/Log")] 27 | public class LogTask : Task 28 | { 29 | public string text; 30 | } 31 | 32 | [ViewModel(typeof(LogTask))] 33 | public class LogTaskProcessor : ActionTaskProcessor 34 | { 35 | public string Text 36 | { 37 | get => this.ModelAs().text; 38 | set => SetFieldValue(ref this.ModelAs().text, value, nameof(LogTask.text)); 39 | } 40 | 41 | public LogTaskProcessor(LogTask model) : base(model) 42 | { 43 | } 44 | 45 | protected override void DoStart() 46 | { 47 | Debug.Log(Text); 48 | SelfStop(true); 49 | } 50 | 51 | protected override void DoStop() 52 | { 53 | SelfStop(false); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /UnityEX/Runtime/Tasks/Actions/Wait.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.GraphProcessor; 20 | using Atom; 21 | using UnityEngine; 22 | 23 | namespace Atom.BehaviorTree 24 | { 25 | [NodeMenu("Action/Wait")] 26 | public class Wait : Task 27 | { 28 | public float interval; 29 | } 30 | 31 | [ViewModel(typeof(Wait))] 32 | public class WaitProcessor : ActionTaskProcessor, IUpdateTask 33 | { 34 | float startTime; 35 | 36 | public float Interval 37 | { 38 | get => (Model as Wait).interval; 39 | set => SetFieldValue(ref (Model as Wait).interval, value, nameof(Wait.interval)); 40 | } 41 | 42 | public WaitProcessor(Wait model) : base(model) 43 | { 44 | 45 | } 46 | 47 | protected override void DoStart() 48 | { 49 | startTime = Time.time; 50 | } 51 | 52 | protected override void DoStop() 53 | { 54 | SelfStop(false); 55 | } 56 | 57 | public void Update() 58 | { 59 | var t_model = Model as Wait; 60 | if (Time.time - startTime > t_model.interval) 61 | SelfStop(true); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /Example/BehaviorTreeTest.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.BehaviorTree; 20 | using Atom.GraphProcessor; 21 | using UnityEngine; 22 | 23 | public class BehaviorTreeTest : MonoBehaviour, IGraphAssetOwner 24 | { 25 | public BehaviorTreeAsset behaviorTreeAsset; 26 | 27 | private BehaviorTreeProcessor behaviorTree; 28 | 29 | public IGraphAsset GraphAsset 30 | { 31 | get { return behaviorTreeAsset; } 32 | } 33 | 34 | public BaseGraphProcessor Graph 35 | { 36 | get 37 | { 38 | if (behaviorTree == null) 39 | behaviorTree = new BehaviorTreeProcessor(behaviorTreeAsset.LoadGraph() as BehaviorTree); 40 | return behaviorTree; 41 | } 42 | } 43 | 44 | public BehaviorTreeProcessor BehaviorTree 45 | { 46 | get 47 | { 48 | if (behaviorTree == null) 49 | behaviorTree = new BehaviorTreeProcessor(behaviorTreeAsset.LoadGraph() as BehaviorTree); 50 | return behaviorTree; 51 | } 52 | } 53 | 54 | private void Start() 55 | { 56 | BehaviorTree.Blackboard.Set("Owner", this); 57 | BehaviorTree.Start(); 58 | } 59 | 60 | private void Update() 61 | { 62 | behaviorTree.Update(); 63 | } 64 | } -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Uss/Task.uss: -------------------------------------------------------------------------------- 1 | #node-border { 2 | border-width: 0; 3 | border-radius: 3px; 4 | min-width: 100px; 5 | } 6 | 7 | #node-border > #title { 8 | height: 30px; 9 | min-height: 30px; 10 | } 11 | 12 | #node-border > #title > #title-label { 13 | -unity-text-align: middle-center; 14 | font-size: 16px; 15 | color: rgb(40, 40, 40); 16 | } 17 | 18 | .Entry > #node-border { 19 | background-color: rgba(0, 178, 0, 1); 20 | } 21 | 22 | .action-task > #node-border { 23 | background-color: rgba(10, 157, 0, 0.4); 24 | } 25 | 26 | .composite-task > #node-border { 27 | background-color: rgba(255, 143, 0, 0.4); 28 | } 29 | 30 | .decorator-task > #node-border { 31 | background-color: rgba(0, 214, 255, 0.4); 32 | } 33 | 34 | #node-border > #contents { 35 | display: none; 36 | } 37 | 38 | #node-border > #contents > #controls > #icon { 39 | max-height: 40px; 40 | height: 40px; 41 | -unity-background-scale-mode: scale-to-fit; 42 | margin-left: 20px; 43 | margin-right: 20px; 44 | margin-top: 3px; 45 | margin-bottom: 3px; 46 | -unity-background-image-tint-color: rgba(1, 1, 1, 0.7); 47 | } 48 | 49 | #state-border { 50 | border-width: 2px; 51 | border-radius: 4px; 52 | } 53 | 54 | .success { 55 | border-color: rgba(0, 255, 0, 0.5); 56 | background-color: rgba(0, 255, 0, 0.5); 57 | } 58 | 59 | .failure { 60 | border-color: rgba(255, 0, 0, 0.5); 61 | background-color: rgba(255, 0, 0, 0.5); 62 | } 63 | 64 | .running { 65 | border-color: rgba(255, 255, 0, 0.5); 66 | background-color: rgba(255, 255, 0, 0.5); 67 | } -------------------------------------------------------------------------------- /Core/Tasks/Composites/Selector.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.GraphProcessor; 20 | using Atom; 21 | 22 | namespace Atom.BehaviorTree 23 | { 24 | [TaskIcon("BehaviorTree/Icons/Selector")] 25 | [NodeTitle("选择执行")] 26 | [NodeTooltip("依次执行,直到某一行为成功,则返回成功,若所有行为都失败,则返回失败")] 27 | [NodeMenu("Composite/Selector")] 28 | public class Selector : Task 29 | { 30 | } 31 | 32 | [ViewModel(typeof(Selector))] 33 | public class SelectorProcessor : CompositeTaskProcessor 34 | { 35 | private int currentIndex; 36 | 37 | public SelectorProcessor(Selector model) : base(model) 38 | { 39 | } 40 | 41 | protected override void DoStart() 42 | { 43 | if (Children.Count == 0) 44 | SelfStop(true); 45 | else 46 | { 47 | currentIndex = 0; 48 | Children[currentIndex].Start(); 49 | } 50 | } 51 | 52 | protected override void OnChildStopped(TaskProcessor child, bool result) 53 | { 54 | if (result) 55 | SelfStop(true); 56 | else if (currentIndex + 1 < Children.Count) 57 | Continue(); 58 | else 59 | SelfStop(false); 60 | } 61 | 62 | private void Continue() 63 | { 64 | Children[++currentIndex].Start(); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /Core/Tasks/Composites/ParallelSelector.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.GraphProcessor; 20 | using Atom; 21 | 22 | namespace Atom.BehaviorTree 23 | { 24 | [NodeTitle("并行选择")] 25 | [NodeTooltip("同时开始所有行为,直到所有行为完成,如果有一个行为返回Success,则返回Success,否则返回Failure")] 26 | [NodeMenu("Composite/Parallel Selector")] 27 | public class ParallelSelector : Task 28 | { 29 | } 30 | 31 | [ViewModel(typeof(ParallelSelector))] 32 | public class ParallelSelectorProcessor : CompositeTaskProcessor 33 | { 34 | private int failedCount = 0; 35 | 36 | public ParallelSelectorProcessor(ParallelSelector model) : base(model) 37 | { 38 | } 39 | 40 | protected override void DoStart() 41 | { 42 | failedCount = 0; 43 | if (Children.Count == 0) 44 | { 45 | SelfStop(true); 46 | return; 47 | } 48 | 49 | foreach (var child in Children) 50 | { 51 | child.Start(); 52 | } 53 | } 54 | 55 | protected override void OnChildStopped(TaskProcessor child, bool result) 56 | { 57 | if (result) 58 | { 59 | SelfStop(true); 60 | return; 61 | } 62 | 63 | failedCount++; 64 | if (failedCount == Children.Count) 65 | SelfStop(false); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /Core/Tasks/Composites/Sequence.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.GraphProcessor; 20 | using Atom; 21 | 22 | namespace Atom.BehaviorTree 23 | { 24 | [TaskIcon("BehaviorTree/Icons/Sequence")] 25 | [NodeTitle("顺序执行")] 26 | [NodeTooltip("依次执行,直到某一行为失败,则返回失败,若所有行为都成功,则返回成功")] 27 | [NodeMenu("Composite/Sequence")] 28 | public class Sequence : Task 29 | { 30 | } 31 | 32 | [ViewModel(typeof(Sequence))] 33 | public class SequenceProcessor : CompositeTaskProcessor 34 | { 35 | private int currentIndex; 36 | 37 | public SequenceProcessor(Sequence model) : base(model) 38 | { 39 | } 40 | 41 | protected override void DoStart() 42 | { 43 | if (Children.Count == 0) 44 | { 45 | SelfStop(true); 46 | } 47 | else 48 | { 49 | currentIndex = 0; 50 | Children[currentIndex].Start(); 51 | } 52 | } 53 | 54 | protected override void OnChildStopped(TaskProcessor child, bool result) 55 | { 56 | if (!result) 57 | SelfStop(false); 58 | else if (currentIndex + 1 < Children.Count) 59 | Continue(); 60 | else 61 | SelfStop(true); 62 | } 63 | 64 | private void Continue() 65 | { 66 | Children[++currentIndex].Start(); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /Core/Tasks/Composites/ParallelSequence.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.GraphProcessor; 20 | using Atom; 21 | 22 | namespace Atom.BehaviorTree 23 | { 24 | [NodeTitle("并行顺序")] 25 | [NodeTooltip("同时执行所有行为,直到所有行为完成,若全部成功,则返回成功,否则返回失败")] 26 | [NodeMenu("Composite/Parallel Sequence")] 27 | public class ParallelSequence : Task 28 | { 29 | } 30 | 31 | [ViewModel(typeof(ParallelSequence))] 32 | public class ParallelSequenceProcessor : CompositeTaskProcessor 33 | { 34 | private int successedCount = 0; 35 | private int failedCount = 0; 36 | 37 | public ParallelSequenceProcessor(ParallelSequence model) : base(model) 38 | { 39 | } 40 | 41 | protected override void DoStart() 42 | { 43 | successedCount = 0; 44 | failedCount = 0; 45 | if (Children.Count == 0) 46 | { 47 | SelfStop(true); 48 | return; 49 | } 50 | 51 | foreach (var child in Children) 52 | { 53 | child.Start(); 54 | } 55 | } 56 | 57 | protected override void OnChildStopped(TaskProcessor child, bool childSuccess) 58 | { 59 | if (childSuccess) 60 | successedCount++; 61 | else 62 | failedCount++; 63 | if (successedCount + failedCount >= Children.Count) 64 | SelfStop(failedCount == 0); 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /Core/Tasks/Entry.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.GraphProcessor; 20 | using Atom; 21 | 22 | namespace Atom.BehaviorTree 23 | { 24 | [NodeMenu("Entry", hidden = true)] 25 | [TaskIcon("BehaviorTree/Icons/Entry")] 26 | [NodeTitleColor(0, 0.7f, 0)] 27 | [NodeTooltip("入口节点,不可移动,不可删除,自动生成")] 28 | public class Entry : Task 29 | { 30 | } 31 | 32 | [ViewModel(typeof(Entry))] 33 | public class EntryProcessor : ContainerTaskProcessor 34 | { 35 | public EntryProcessor(Entry model) : base(model) 36 | { 37 | AddPort(new PortProcessor(TaskProcessor.ChildrenPortName, BasePort.Direction.Bottom, BasePort.Capacity.Single, typeof(TaskProcessor))); 38 | } 39 | 40 | public TaskProcessor GetFirstChild() 41 | { 42 | var port = Ports[TaskProcessor.ChildrenPortName]; 43 | if (port.Connections.Count == 0) 44 | return null; 45 | return port.Connections[0].ToNode as TaskProcessor; 46 | } 47 | 48 | protected override void DoStart() 49 | { 50 | var child = GetFirstChild(); 51 | if (child == null) 52 | { 53 | SelfStop(true); 54 | } 55 | else 56 | { 57 | child.Start(); 58 | } 59 | } 60 | 61 | protected override void DoStop() 62 | { 63 | var child = GetFirstChild(); 64 | child?.Stop(); 65 | } 66 | 67 | protected override void OnChildStopped(TaskProcessor child, bool result) 68 | { 69 | SelfStop(result); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /Core/Tasks/Decorators/Repeater.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.GraphProcessor; 20 | using Atom; 21 | 22 | namespace Atom.BehaviorTree 23 | { 24 | [TaskIcon("BehaviorTree/Icons/Repeater")] 25 | [NodeMenu("Decorator/Repeater")] 26 | public class Repeater : Task 27 | { 28 | public bool ignoreFaild; 29 | public int loopCount; 30 | } 31 | 32 | [ViewModel(typeof(Repeater))] 33 | public class RepeaterProcessor : DecoratorTaskProcessor, IUpdateTask 34 | { 35 | private Repeater model; 36 | private int counter; 37 | private bool childRunning; 38 | 39 | public RepeaterProcessor(Repeater model) : base(model) 40 | { 41 | this.model = model; 42 | } 43 | 44 | protected override void DoStart() 45 | { 46 | if (model.loopCount != 0) 47 | { 48 | counter = 0; 49 | childRunning = true; 50 | Child.Start(); 51 | } 52 | else 53 | SelfStop(true); 54 | } 55 | 56 | public void Update() 57 | { 58 | if (childRunning) 59 | return; 60 | 61 | childRunning = true; 62 | Child.Start(); 63 | } 64 | 65 | protected override void OnChildStopped(TaskProcessor child, bool result) 66 | { 67 | this.childRunning = false; 68 | if (model.ignoreFaild || result) 69 | { 70 | if (model.loopCount > 0 && ++counter >= model.loopCount) 71 | SelfStop(true); 72 | } 73 | else 74 | SelfStop(false); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /UnityEX/Editor/BehaviorTreeGraphView.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | #if UNITY_EDITOR 20 | using Atom.GraphProcessor; 21 | using Atom.GraphProcessor.Editors; 22 | using UnityEditor.Experimental.GraphView; 23 | 24 | namespace Atom.BehaviorTree.Editors 25 | { 26 | public class BehaviorTreeGraphView : BaseGraphView 27 | { 28 | protected override void OnCreated() 29 | { 30 | base.OnCreated(); 31 | schedule.Execute(UpdateState).Every(100); 32 | } 33 | 34 | private void UpdateState() 35 | { 36 | foreach (var node in NodeViews.Values) 37 | { 38 | if (node is TaskView taskView) 39 | { 40 | taskView.UpdateState(); 41 | } 42 | } 43 | } 44 | 45 | protected override void BuildNodeMenu(NodeMenuWindow nodeMenu) 46 | { 47 | foreach (var nodeInfo in GraphProcessorUtil.GetNodeStaticInfos()) 48 | { 49 | if (!typeof(Task).IsAssignableFrom(nodeInfo.NodeType)) 50 | continue; 51 | 52 | if (nodeInfo.Hidden) 53 | continue; 54 | 55 | nodeMenu.entries.Add(new NodeMenuWindow.NodeEntry(nodeInfo.Path, nodeInfo.Menu, nodeInfo.NodeType)); 56 | } 57 | } 58 | 59 | protected override bool IsCompatible(BasePortView fromPortView, BasePortView toPortView, NodeAdapter nodeAdapter) 60 | { 61 | if (fromPortView.node == toPortView.node) 62 | return false; 63 | if (fromPortView.ViewModel.Owner == toPortView.ViewModel.Owner) 64 | return false; 65 | return base.IsCompatible(fromPortView, toPortView, nodeAdapter); 66 | } 67 | } 68 | } 69 | #endif -------------------------------------------------------------------------------- /Core/BehaviorTree.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using Atom.GraphProcessor; 23 | 24 | namespace Atom.BehaviorTree 25 | { 26 | [Serializable] 27 | public class BehaviorTree : BaseGraph 28 | { 29 | public long entryID; 30 | } 31 | 32 | [ViewModel(typeof(BehaviorTree))] 33 | public class BehaviorTreeProcessor : BaseGraphProcessor 34 | { 35 | private EntryProcessor entry; 36 | private Queue updateTasks; 37 | 38 | public TaskState RootState => entry.CurrentState; 39 | 40 | public BehaviorTreeProcessor(BehaviorTree model) : base(model) 41 | { 42 | if (model.entryID != 0 && !Nodes.ContainsKey(model.entryID)) 43 | model.entryID = 0; 44 | if (model.entryID == 0 && model.nodes.FirstOrDefault(node => node is Entry) is Entry e) 45 | model.entryID = e.id; 46 | if (model.entryID == 0) 47 | model.entryID = AddNode(InternalVector2Int.zero).ID; 48 | entry = Nodes[model.entryID] as EntryProcessor; 49 | updateTasks = new Queue(16); 50 | } 51 | 52 | public void Start() 53 | { 54 | entry.Start(); 55 | } 56 | 57 | public void Update() 58 | { 59 | var counter = updateTasks.Count; 60 | while (counter-- > 0) 61 | { 62 | var task = updateTasks.Dequeue(); 63 | if (task.CurrentState == TaskState.Active) 64 | { 65 | task.Update(); 66 | updateTasks.Enqueue(task); 67 | } 68 | } 69 | } 70 | 71 | public void Stop() 72 | { 73 | entry.Stop(); 74 | } 75 | 76 | internal void RegisterUpdateTask(IUpdateTask updateTask) 77 | { 78 | updateTasks.Enqueue(updateTask); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /Core/Tasks/Composites/RandomSelector.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using System; 20 | using Atom.GraphProcessor; 21 | using Atom; 22 | 23 | namespace Atom.BehaviorTree 24 | { 25 | [NodeTitle("随机选择")] 26 | [NodeTooltip("随机顺序执行,直到某一行为成功,则返回成功,若所有行为都失败,则返回失败")] 27 | [NodeMenu("Composite/Random Selector")] 28 | public class RandomSelector : Task 29 | { 30 | public int randomSeed; 31 | } 32 | 33 | [ViewModel(typeof(RandomSelector))] 34 | public class RandomSelectorProcessor : CompositeTaskProcessor 35 | { 36 | private int currentIndex; 37 | private Random random; 38 | 39 | public int RandomSeed 40 | { 41 | get => (Model as RandomSelector).randomSeed; 42 | set => SetFieldValue(ref (Model as RandomSelector).randomSeed, value, nameof(RandomSelector.randomSeed)); 43 | } 44 | 45 | public RandomSelectorProcessor(RandomSelector model) : base(model) 46 | { 47 | random = new Random(model.randomSeed); 48 | } 49 | 50 | protected override void DoStart() 51 | { 52 | if (Children.Count == 0) 53 | SelfStop(true); 54 | else 55 | { 56 | for (int i = Children.Count - 1; i >= 0; i--) 57 | { 58 | var index = random.Next(0, i + 1); 59 | var temp = Children[i]; 60 | Children[i] = Children[index]; 61 | Children[index] = temp; 62 | } 63 | 64 | currentIndex = 0; 65 | Children[currentIndex].Start(); 66 | } 67 | } 68 | 69 | protected override void OnChildStopped(TaskProcessor child, bool result) 70 | { 71 | if (result) 72 | SelfStop(true); 73 | else if (currentIndex + 1 < Children.Count) 74 | Continue(); 75 | else 76 | SelfStop(false); 77 | } 78 | 79 | private void Continue() 80 | { 81 | Children[++currentIndex].Start(); 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /Images/20220115_163620.gif.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d06256fd66bb7da448b7119c0eb43764 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: 1 35 | aniso: 1 36 | mipBias: 0 37 | wrapU: 0 38 | wrapV: 0 39 | wrapW: 0 40 | nPOTScale: 1 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 0 53 | spriteTessellationDetail: -1 54 | textureType: 0 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | applyGammaDecoding: 0 61 | platformSettings: 62 | - serializedVersion: 3 63 | buildTarget: DefaultTexturePlatform 64 | maxTextureSize: 2048 65 | resizeAlgorithm: 0 66 | textureFormat: -1 67 | textureCompression: 1 68 | compressionQuality: 50 69 | crunchedCompression: 0 70 | allowsAlphaSplitting: 0 71 | overridden: 0 72 | androidETC2FallbackOverride: 0 73 | forceMaximumCompressionQuality_BC6H_BC7: 0 74 | spriteSheet: 75 | serializedVersion: 2 76 | sprites: [] 77 | outline: [] 78 | physicsShape: [] 79 | bones: [] 80 | spriteID: 81 | internalID: 0 82 | vertices: [] 83 | indices: 84 | edges: [] 85 | weights: [] 86 | secondaryTextures: [] 87 | spritePackingTag: 88 | pSDRemoveMatte: 0 89 | pSDShowRemoveMatteOption: 0 90 | userData: 91 | assetBundleName: 92 | assetBundleVariant: 93 | -------------------------------------------------------------------------------- /Core/Tasks/Composites/RandomSequence.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using System; 20 | using Atom.GraphProcessor; 21 | using Atom; 22 | 23 | namespace Atom.BehaviorTree 24 | { 25 | [TaskIcon("BehaviorTree/Icons/RandomSequence")] 26 | [NodeTitle("随机顺序")] 27 | [NodeTooltip("随机顺序执行,直到某一行为失败,则返回失败,若所有行为都成功,则返回成功")] 28 | [NodeMenu("Composite/Random Sequence")] 29 | public class RandomSequence : Task 30 | { 31 | public int randomSeed; 32 | } 33 | 34 | [ViewModel(typeof(RandomSequence))] 35 | public class RandomSequenceProcessor : CompositeTaskProcessor 36 | { 37 | private int currentIndex; 38 | private Random random; 39 | 40 | public int RandomSeed 41 | { 42 | get => (Model as RandomSequence).randomSeed; 43 | set => SetFieldValue(ref (Model as RandomSequence).randomSeed, value, nameof(RandomSequence.randomSeed)); 44 | } 45 | 46 | public RandomSequenceProcessor(RandomSequence model) : base(model) 47 | { 48 | random = new Random(model.randomSeed); 49 | } 50 | 51 | protected override void DoStart() 52 | { 53 | if (Children.Count == 0) 54 | SelfStop(true); 55 | else 56 | { 57 | for (int i = Children.Count - 1; i >= 0; i--) 58 | { 59 | var index = random.Next(0, i + 1); 60 | var temp = Children[i]; 61 | Children[i] = Children[index]; 62 | Children[index] = temp; 63 | } 64 | 65 | currentIndex = 0; 66 | Children[currentIndex].Start(); 67 | } 68 | } 69 | 70 | protected override void OnChildStopped(TaskProcessor child, bool result) 71 | { 72 | if (!result) 73 | SelfStop(false); 74 | else if (currentIndex + 1 < Children.Count) 75 | Continue(); 76 | else 77 | SelfStop(true); 78 | } 79 | 80 | private void Continue() 81 | { 82 | currentIndex++; 83 | Children[currentIndex].Start(); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Core/ViewModel/ContainerTaskProcessor.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using System.Collections.Generic; 20 | using Atom.GraphProcessor; 21 | 22 | namespace Atom.BehaviorTree 23 | { 24 | public abstract class ContainerTaskProcessor : TaskProcessor 25 | { 26 | private List children; 27 | 28 | protected List Children 29 | { 30 | get { return children; } 31 | } 32 | 33 | protected ContainerTaskProcessor(Task model) : base(model) 34 | { 35 | } 36 | 37 | protected override void OnEnabled() 38 | { 39 | base.OnEnabled(); 40 | RefreshChildren(null); 41 | Ports[TaskProcessor.ChildrenPortName].OnConnected += RefreshChildren; 42 | Ports[TaskProcessor.ChildrenPortName].onDisconnected += RefreshChildren; 43 | } 44 | 45 | protected override void OnDisabled() 46 | { 47 | base.OnDisabled(); 48 | Ports[TaskProcessor.ChildrenPortName].OnConnected -= RefreshChildren; 49 | Ports[TaskProcessor.ChildrenPortName].onDisconnected -= RefreshChildren; 50 | } 51 | 52 | protected override void DoStop() 53 | { 54 | if (Children != null && Children.Count != 0) 55 | { 56 | foreach (var child in Children) 57 | { 58 | child.Stop(); 59 | } 60 | } 61 | } 62 | 63 | public void ChildStopped(TaskProcessor child, bool childSuccess) 64 | { 65 | this.OnChildStopped(child, childSuccess); 66 | } 67 | 68 | protected abstract void OnChildStopped(TaskProcessor child, bool childSuccess); 69 | 70 | protected virtual void RefreshChildren(BaseConnectionProcessor connection) 71 | { 72 | if (children == null) 73 | children = new List(GetChildren()); 74 | else 75 | { 76 | children.Clear(); 77 | children.AddRange(GetChildren()); 78 | } 79 | 80 | IEnumerable GetChildren() 81 | { 82 | foreach (var node in GetPortConnections(TaskProcessor.ChildrenPortName)) 83 | { 84 | yield return (TaskProcessor)node; 85 | } 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /Example/SeekAction.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom; 20 | using System; 21 | using Atom.GraphProcessor; 22 | using UnityEngine; 23 | using UnityEngine.AI; 24 | 25 | namespace Atom.BehaviorTree 26 | { 27 | [NodeTooltip("追逐敌人到一定距离后停下")] 28 | [NodeMenu("Seek")] 29 | public class SeekAction : ActionTask 30 | { 31 | public float stopDistance = 2; 32 | [Header("超时")] [Tooltip("超时将不再追击敌人")] public float timeout = 10; 33 | } 34 | 35 | [ViewModel(typeof(SeekAction))] 36 | public class SeekActionProcessor : ActionTaskProcessor, IUpdateTask 37 | { 38 | public SeekActionProcessor(SeekAction model) : base(model) 39 | { 40 | Title = "追逐"; 41 | } 42 | 43 | [NonSerialized] GameObject target; 44 | [NonSerialized] NavMeshAgent navMeshAgent; 45 | 46 | private float startTime; 47 | 48 | protected override void DoStart() 49 | { 50 | base.DoStart(); 51 | var t_model = Model as SeekAction; 52 | Owner.Blackboard.TryGet("Target", out target); 53 | startTime = Time.time; 54 | navMeshAgent.stoppingDistance = t_model.stopDistance; 55 | navMeshAgent.updateRotation = true; 56 | navMeshAgent.isStopped = false; 57 | Debug.Log("追逐"); 58 | } 59 | 60 | public void Update() 61 | { 62 | var t_model = Model as SeekAction; 63 | var navMeshAgent = Owner.Blackboard.Get("NavMeshAgent"); 64 | 65 | if (target == null || !target.activeSelf || Time.time - startTime > t_model.timeout) 66 | { 67 | Owner.Blackboard.Set("Target", null); 68 | navMeshAgent.isStopped = true; 69 | Debug.Log("追不上"); 70 | SelfStop(false); 71 | } 72 | 73 | if (Vector3.Distance(navMeshAgent.transform.position, target.transform.position) <= t_model.stopDistance) 74 | { 75 | Owner.Blackboard.Set("Target", null); 76 | navMeshAgent.isStopped = true; 77 | SelfStop(true); 78 | } 79 | 80 | navMeshAgent.destination = target.transform.position; 81 | } 82 | 83 | protected override void DoStop() 84 | { 85 | Owner.Blackboard.Set("Target", null); 86 | navMeshAgent.isStopped = true; 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Default.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 45ee5e7995c11914a8602400dc6af29b 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | externalObjects: {} 6 | serializedVersion: 5 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | grayScaleToAlpha: 0 25 | generateCubemap: 6 26 | cubemapConvolution: 0 27 | seamlessCubemap: 0 28 | textureFormat: 1 29 | maxTextureSize: 2048 30 | textureSettings: 31 | serializedVersion: 2 32 | filterMode: -1 33 | aniso: -1 34 | mipBias: -1 35 | wrapU: 1 36 | wrapV: 1 37 | wrapW: -1 38 | nPOTScale: 0 39 | lightmap: 0 40 | compressionQuality: 50 41 | spriteMode: 1 42 | spriteExtrude: 1 43 | spriteMeshType: 1 44 | alignment: 0 45 | spritePivot: {x: 0.5, y: 0.5} 46 | spritePixelsToUnits: 100 47 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 48 | spriteGenerateFallbackPhysicsShape: 1 49 | alphaUsage: 1 50 | alphaIsTransparency: 1 51 | spriteTessellationDetail: -1 52 | textureType: 8 53 | textureShape: 1 54 | singleChannelComponent: 0 55 | maxTextureSizeSet: 0 56 | compressionQualitySet: 0 57 | textureFormatSet: 0 58 | platformSettings: 59 | - serializedVersion: 2 60 | buildTarget: DefaultTexturePlatform 61 | maxTextureSize: 256 62 | resizeAlgorithm: 0 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | androidETC2FallbackOverride: 0 70 | - serializedVersion: 2 71 | buildTarget: Standalone 72 | maxTextureSize: 256 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | androidETC2FallbackOverride: 0 81 | - serializedVersion: 2 82 | buildTarget: Android 83 | maxTextureSize: 256 84 | resizeAlgorithm: 0 85 | textureFormat: -1 86 | textureCompression: 1 87 | compressionQuality: 50 88 | crunchedCompression: 0 89 | allowsAlphaSplitting: 0 90 | overridden: 0 91 | androidETC2FallbackOverride: 0 92 | spriteSheet: 93 | serializedVersion: 2 94 | sprites: [] 95 | outline: [] 96 | physicsShape: [] 97 | bones: [] 98 | spriteID: 8d5bfbad85d45454bbdc7873842154cf 99 | vertices: [] 100 | indices: 101 | edges: [] 102 | weights: [] 103 | spritePackingTag: 104 | userData: 105 | assetBundleName: 106 | assetBundleVariant: 107 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Entry.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f886ab9e150bbb24c8ae9ccba19be53b 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | externalObjects: {} 6 | serializedVersion: 5 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | grayScaleToAlpha: 0 25 | generateCubemap: 6 26 | cubemapConvolution: 0 27 | seamlessCubemap: 0 28 | textureFormat: 1 29 | maxTextureSize: 2048 30 | textureSettings: 31 | serializedVersion: 2 32 | filterMode: -1 33 | aniso: -1 34 | mipBias: -1 35 | wrapU: 1 36 | wrapV: 1 37 | wrapW: -1 38 | nPOTScale: 0 39 | lightmap: 0 40 | compressionQuality: 50 41 | spriteMode: 1 42 | spriteExtrude: 1 43 | spriteMeshType: 1 44 | alignment: 0 45 | spritePivot: {x: 0.5, y: 0.5} 46 | spritePixelsToUnits: 100 47 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 48 | spriteGenerateFallbackPhysicsShape: 1 49 | alphaUsage: 1 50 | alphaIsTransparency: 1 51 | spriteTessellationDetail: -1 52 | textureType: 8 53 | textureShape: 1 54 | singleChannelComponent: 0 55 | maxTextureSizeSet: 0 56 | compressionQualitySet: 0 57 | textureFormatSet: 0 58 | platformSettings: 59 | - serializedVersion: 2 60 | buildTarget: DefaultTexturePlatform 61 | maxTextureSize: 256 62 | resizeAlgorithm: 0 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | androidETC2FallbackOverride: 0 70 | - serializedVersion: 2 71 | buildTarget: Standalone 72 | maxTextureSize: 256 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | androidETC2FallbackOverride: 0 81 | - serializedVersion: 2 82 | buildTarget: Android 83 | maxTextureSize: 256 84 | resizeAlgorithm: 0 85 | textureFormat: -1 86 | textureCompression: 1 87 | compressionQuality: 50 88 | crunchedCompression: 0 89 | allowsAlphaSplitting: 0 90 | overridden: 0 91 | androidETC2FallbackOverride: 0 92 | spriteSheet: 93 | serializedVersion: 2 94 | sprites: [] 95 | outline: [] 96 | physicsShape: [] 97 | bones: [] 98 | spriteID: 286878cc45c410d4dbabbbe596a7a2a1 99 | vertices: [] 100 | indices: 101 | edges: [] 102 | weights: [] 103 | spritePackingTag: 104 | userData: 105 | assetBundleName: 106 | assetBundleVariant: 107 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Selector.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 014b832d3b389ac4e8608f08054a7745 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | externalObjects: {} 6 | serializedVersion: 5 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | grayScaleToAlpha: 0 25 | generateCubemap: 6 26 | cubemapConvolution: 0 27 | seamlessCubemap: 0 28 | textureFormat: 1 29 | maxTextureSize: 2048 30 | textureSettings: 31 | serializedVersion: 2 32 | filterMode: -1 33 | aniso: -1 34 | mipBias: -1 35 | wrapU: 1 36 | wrapV: 1 37 | wrapW: -1 38 | nPOTScale: 0 39 | lightmap: 0 40 | compressionQuality: 50 41 | spriteMode: 1 42 | spriteExtrude: 1 43 | spriteMeshType: 1 44 | alignment: 0 45 | spritePivot: {x: 0.5, y: 0.5} 46 | spritePixelsToUnits: 100 47 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 48 | spriteGenerateFallbackPhysicsShape: 1 49 | alphaUsage: 1 50 | alphaIsTransparency: 1 51 | spriteTessellationDetail: -1 52 | textureType: 8 53 | textureShape: 1 54 | singleChannelComponent: 0 55 | maxTextureSizeSet: 0 56 | compressionQualitySet: 0 57 | textureFormatSet: 0 58 | platformSettings: 59 | - serializedVersion: 2 60 | buildTarget: DefaultTexturePlatform 61 | maxTextureSize: 256 62 | resizeAlgorithm: 0 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | androidETC2FallbackOverride: 0 70 | - serializedVersion: 2 71 | buildTarget: Standalone 72 | maxTextureSize: 256 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | androidETC2FallbackOverride: 0 81 | - serializedVersion: 2 82 | buildTarget: Android 83 | maxTextureSize: 256 84 | resizeAlgorithm: 0 85 | textureFormat: -1 86 | textureCompression: 1 87 | compressionQuality: 50 88 | crunchedCompression: 0 89 | allowsAlphaSplitting: 0 90 | overridden: 0 91 | androidETC2FallbackOverride: 0 92 | spriteSheet: 93 | serializedVersion: 2 94 | sprites: [] 95 | outline: [] 96 | physicsShape: [] 97 | bones: [] 98 | spriteID: cfbae920834a45140bd0df209d30da24 99 | vertices: [] 100 | indices: 101 | edges: [] 102 | weights: [] 103 | spritePackingTag: 104 | userData: 105 | assetBundleName: 106 | assetBundleVariant: 107 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Sequence.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b85ed9fc47105454db16e108fa845264 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | externalObjects: {} 6 | serializedVersion: 5 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | grayScaleToAlpha: 0 25 | generateCubemap: 6 26 | cubemapConvolution: 0 27 | seamlessCubemap: 0 28 | textureFormat: 1 29 | maxTextureSize: 2048 30 | textureSettings: 31 | serializedVersion: 2 32 | filterMode: -1 33 | aniso: -1 34 | mipBias: -1 35 | wrapU: 1 36 | wrapV: 1 37 | wrapW: -1 38 | nPOTScale: 0 39 | lightmap: 0 40 | compressionQuality: 50 41 | spriteMode: 1 42 | spriteExtrude: 1 43 | spriteMeshType: 1 44 | alignment: 0 45 | spritePivot: {x: 0.5, y: 0.5} 46 | spritePixelsToUnits: 100 47 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 48 | spriteGenerateFallbackPhysicsShape: 1 49 | alphaUsage: 1 50 | alphaIsTransparency: 1 51 | spriteTessellationDetail: -1 52 | textureType: 8 53 | textureShape: 1 54 | singleChannelComponent: 0 55 | maxTextureSizeSet: 0 56 | compressionQualitySet: 0 57 | textureFormatSet: 0 58 | platformSettings: 59 | - serializedVersion: 2 60 | buildTarget: DefaultTexturePlatform 61 | maxTextureSize: 256 62 | resizeAlgorithm: 0 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | androidETC2FallbackOverride: 0 70 | - serializedVersion: 2 71 | buildTarget: Standalone 72 | maxTextureSize: 256 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | androidETC2FallbackOverride: 0 81 | - serializedVersion: 2 82 | buildTarget: Android 83 | maxTextureSize: 256 84 | resizeAlgorithm: 0 85 | textureFormat: -1 86 | textureCompression: 1 87 | compressionQuality: 50 88 | crunchedCompression: 0 89 | allowsAlphaSplitting: 0 90 | overridden: 0 91 | androidETC2FallbackOverride: 0 92 | spriteSheet: 93 | serializedVersion: 2 94 | sprites: [] 95 | outline: [] 96 | physicsShape: [] 97 | bones: [] 98 | spriteID: 9354d9b2710112746a57e5487f88b98d 99 | vertices: [] 100 | indices: 101 | edges: [] 102 | weights: [] 103 | spritePackingTag: 104 | userData: 105 | assetBundleName: 106 | assetBundleVariant: 107 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Conditional.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 93beff002b0c2054f87a1b1314221cd5 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | externalObjects: {} 6 | serializedVersion: 5 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | grayScaleToAlpha: 0 25 | generateCubemap: 6 26 | cubemapConvolution: 0 27 | seamlessCubemap: 0 28 | textureFormat: 1 29 | maxTextureSize: 2048 30 | textureSettings: 31 | serializedVersion: 2 32 | filterMode: -1 33 | aniso: -1 34 | mipBias: -1 35 | wrapU: 1 36 | wrapV: 1 37 | wrapW: -1 38 | nPOTScale: 0 39 | lightmap: 0 40 | compressionQuality: 50 41 | spriteMode: 1 42 | spriteExtrude: 1 43 | spriteMeshType: 1 44 | alignment: 0 45 | spritePivot: {x: 0.5, y: 0.5} 46 | spritePixelsToUnits: 100 47 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 48 | spriteGenerateFallbackPhysicsShape: 1 49 | alphaUsage: 1 50 | alphaIsTransparency: 1 51 | spriteTessellationDetail: -1 52 | textureType: 8 53 | textureShape: 1 54 | singleChannelComponent: 0 55 | maxTextureSizeSet: 0 56 | compressionQualitySet: 0 57 | textureFormatSet: 0 58 | platformSettings: 59 | - serializedVersion: 2 60 | buildTarget: DefaultTexturePlatform 61 | maxTextureSize: 256 62 | resizeAlgorithm: 0 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | androidETC2FallbackOverride: 0 70 | - serializedVersion: 2 71 | buildTarget: Standalone 72 | maxTextureSize: 256 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | androidETC2FallbackOverride: 0 81 | - serializedVersion: 2 82 | buildTarget: Android 83 | maxTextureSize: 256 84 | resizeAlgorithm: 0 85 | textureFormat: -1 86 | textureCompression: 1 87 | compressionQuality: 50 88 | crunchedCompression: 0 89 | allowsAlphaSplitting: 0 90 | overridden: 0 91 | androidETC2FallbackOverride: 0 92 | spriteSheet: 93 | serializedVersion: 2 94 | sprites: [] 95 | outline: [] 96 | physicsShape: [] 97 | bones: [] 98 | spriteID: 45d30a5bb4faaa44bb51159f18d3b077 99 | vertices: [] 100 | indices: 101 | edges: [] 102 | weights: [] 103 | spritePackingTag: 104 | userData: 105 | assetBundleName: 106 | assetBundleVariant: 107 | -------------------------------------------------------------------------------- /Example/WanderAction.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using Atom.GraphProcessor; 20 | using UnityEngine; 21 | using UnityEngine.AI; 22 | using Random = UnityEngine.Random; 23 | 24 | namespace Atom.BehaviorTree 25 | { 26 | [NodeMenu("Wander")] 27 | [NodeTooltip("在指定区域内徘徊,直到看到敌人")] 28 | public class WanderAction : ActionTask 29 | { 30 | [Header("巡逻范围")] public string center; 31 | public float range = 10; 32 | [Header("视野范围")] public float radius = 5; 33 | [Range(0, 360)] [Header("视野角度")] public float sector = 90; 34 | public LayerMask layer; 35 | } 36 | 37 | [ViewModel(typeof(WanderAction))] 38 | public class WanderActionProcessor : ActionTaskProcessor, IUpdateTask 39 | { 40 | public WanderActionProcessor(WanderAction model) : base(model) 41 | { 42 | Title = "徘徊"; 43 | } 44 | 45 | Vector3 targetPos; 46 | float stayTime; 47 | 48 | protected override void DoStart() 49 | { 50 | var navMeshAgent = Owner.Blackboard.Get("NavMeshAgent"); 51 | var t_model = Model as WanderAction; 52 | 53 | targetPos = Random.insideUnitSphere * t_model.range + Owner.Blackboard.Get(t_model.center).transform.position; 54 | targetPos.y = 0; 55 | stayTime = Random.Range(2, 5); 56 | navMeshAgent.stoppingDistance = 0; 57 | navMeshAgent.isStopped = false; 58 | Debug.Log("徘徊"); 59 | } 60 | 61 | public void Update() 62 | { 63 | var navMeshAgent = Owner.Blackboard.Get("NavMeshAgent"); 64 | var t_model = Model as WanderAction; 65 | if (Vector3.Distance(targetPos, navMeshAgent.transform.position) <= 2) 66 | { 67 | stayTime -= Time.deltaTime; 68 | if (stayTime <= 0) 69 | { 70 | targetPos = Random.insideUnitSphere * t_model.range + Owner.Blackboard.Get(t_model.center).transform.position; 71 | targetPos.y = 0; 72 | stayTime = Random.Range(2, 5); 73 | } 74 | } 75 | 76 | navMeshAgent.SetDestination(targetPos); 77 | 78 | Collider[] colliders = Physics.OverlapSphere(navMeshAgent.transform.position, t_model.radius, t_model.layer); 79 | if (colliders.Length > 0) 80 | { 81 | foreach (var item in colliders) 82 | { 83 | if (Vector3.Angle(navMeshAgent.transform.forward, item.transform.position - navMeshAgent.transform.position) <= t_model.sector / 2) 84 | { 85 | Owner.Blackboard.Set("Target", item.gameObject); 86 | SelfStop(true); 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Example/New Behavior Tree Asset.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 35d5fd334e30ba047b2e4ab52e51f858, type: 3} 13 | m_Name: New Behavior Tree Asset 14 | m_EditorClassIdentifier: 15 | data: 16 | zoom: 1 17 | pan: 18 | x: 635 19 | y: 198 20 | nodes: 21 | - rid: 1085762376050409936 22 | - rid: 1085762376050409937 23 | - rid: 1085762376050409938 24 | - rid: 1085762376050409939 25 | - rid: 1085762376050409940 26 | connections: 27 | - rid: 1085762376050409941 28 | - rid: 1085762376050409942 29 | - rid: 1085762376050409943 30 | - rid: 1085762376050409944 31 | groups: [] 32 | notes: [] 33 | entryID: 1 34 | references: 35 | version: 2 36 | RefIds: 37 | - rid: 1085762376050409936 38 | type: {class: Entry, ns: Atom.BehaviorTree, asm: Atom.BehaviorTree} 39 | data: 40 | id: 1 41 | position: 42 | x: 0 43 | y: 0 44 | - rid: 1085762376050409937 45 | type: {class: Repeater, ns: Atom.BehaviorTree, asm: Atom.BehaviorTree} 46 | data: 47 | id: 2 48 | position: 49 | x: 0 50 | y: 99 51 | ignoreFaild: 1 52 | loopCount: -1 53 | - rid: 1085762376050409938 54 | type: {class: Sequence, ns: Atom.BehaviorTree, asm: Atom.BehaviorTree} 55 | data: 56 | id: 4 57 | position: 58 | x: 0 59 | y: 212 60 | - rid: 1085762376050409939 61 | type: {class: Wait, ns: Atom.BehaviorTree, asm: Atom.BehaviorTree} 62 | data: 63 | id: 5 64 | position: 65 | x: -76 66 | y: 336 67 | interval: 1.38 68 | - rid: 1085762376050409940 69 | type: {class: LogTask, ns: Atom.BehaviorTree, asm: Atom.BehaviorTree} 70 | data: 71 | id: 6 72 | position: 73 | x: 106 74 | y: 336 75 | text: 1123 76 | - rid: 1085762376050409941 77 | type: {class: BaseConnection, ns: Atom.GraphProcessor, asm: Atom.GraphProcessor} 78 | data: 79 | fromNode: 1 80 | fromPort: Children 81 | toNode: 2 82 | toPort: Parent 83 | - rid: 1085762376050409942 84 | type: {class: BaseConnection, ns: Atom.GraphProcessor, asm: Atom.GraphProcessor} 85 | data: 86 | fromNode: 2 87 | fromPort: Children 88 | toNode: 4 89 | toPort: Parent 90 | - rid: 1085762376050409943 91 | type: {class: BaseConnection, ns: Atom.GraphProcessor, asm: Atom.GraphProcessor} 92 | data: 93 | fromNode: 4 94 | fromPort: Children 95 | toNode: 5 96 | toPort: Parent 97 | - rid: 1085762376050409944 98 | type: {class: BaseConnection, ns: Atom.GraphProcessor, asm: Atom.GraphProcessor} 99 | data: 100 | fromNode: 4 101 | fromPort: Children 102 | toNode: 6 103 | toPort: Parent 104 | -------------------------------------------------------------------------------- /Core/ViewModel/TaskProcessor.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | using System; 20 | using Atom.GraphProcessor; 21 | 22 | namespace Atom.BehaviorTree 23 | { 24 | public abstract class TaskProcessor : BaseNodeProcessor 25 | { 26 | #region Keyword 27 | 28 | public const string ParentPortName = "Parent"; 29 | public const string ChildrenPortName = "Children"; 30 | 31 | #endregion 32 | 33 | #region Fields 34 | 35 | private ContainerTaskProcessor parent; 36 | private TaskState currentState; 37 | 38 | #endregion 39 | 40 | #region Properties 41 | 42 | public event Action OnStart; 43 | public event Action OnStop; 44 | 45 | public TaskState CurrentState 46 | { 47 | get { return currentState; } 48 | } 49 | 50 | public ContainerTaskProcessor Parent 51 | { 52 | get { return parent; } 53 | } 54 | 55 | #endregion 56 | 57 | protected TaskProcessor(Task model) : base(model) 58 | { 59 | } 60 | 61 | protected override void OnEnabled() 62 | { 63 | base.OnEnabled(); 64 | if (Ports.TryGetValue(ParentPortName, out var parentPort)) 65 | { 66 | RefreshParent(); 67 | parentPort.OnConnectionChanged += RefreshParent; 68 | } 69 | } 70 | 71 | protected override void OnDisabled() 72 | { 73 | base.OnDisabled(); 74 | if (Ports.TryGetValue(ParentPortName, out var parentPort)) 75 | { 76 | parent = null; 77 | parentPort.OnConnectionChanged -= RefreshParent; 78 | } 79 | } 80 | 81 | public void Start() 82 | { 83 | currentState = TaskState.Active; 84 | OnStart?.Invoke(); 85 | DoStart(); 86 | if (CurrentState == TaskState.Active && this is IUpdateTask updateTask) 87 | (Owner as BehaviorTreeProcessor).RegisterUpdateTask(updateTask); 88 | } 89 | 90 | public void Stop() 91 | { 92 | DoStop(); 93 | currentState = TaskState.InActive; 94 | } 95 | 96 | protected void SelfStop(bool success) 97 | { 98 | currentState = TaskState.InActive; 99 | OnStop?.Invoke(success); 100 | Parent?.ChildStopped(this, success); 101 | } 102 | 103 | protected virtual void DoStart() 104 | { 105 | } 106 | 107 | protected virtual void DoStop() 108 | { 109 | } 110 | 111 | private void RefreshParent() 112 | { 113 | if (Ports.TryGetValue(ParentPortName, out var parentPort) && parentPort.Connections.Count > 0) 114 | parent = parentPort.Connections[0].FromNode as ContainerTaskProcessor; 115 | else 116 | parent = null; 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Debug.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c842f0c30ede3954c8bd4a40818530a1 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 1 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 8 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 3 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 256 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | forceMaximumCompressionQuality_BC6H_BC7: 1 73 | - serializedVersion: 3 74 | buildTarget: Standalone 75 | maxTextureSize: 256 76 | resizeAlgorithm: 0 77 | textureFormat: -1 78 | textureCompression: 1 79 | compressionQuality: 50 80 | crunchedCompression: 0 81 | allowsAlphaSplitting: 0 82 | overridden: 0 83 | androidETC2FallbackOverride: 0 84 | forceMaximumCompressionQuality_BC6H_BC7: 1 85 | - serializedVersion: 3 86 | buildTarget: Android 87 | maxTextureSize: 256 88 | resizeAlgorithm: 0 89 | textureFormat: -1 90 | textureCompression: 1 91 | compressionQuality: 50 92 | crunchedCompression: 0 93 | allowsAlphaSplitting: 0 94 | overridden: 0 95 | androidETC2FallbackOverride: 0 96 | forceMaximumCompressionQuality_BC6H_BC7: 1 97 | spriteSheet: 98 | serializedVersion: 2 99 | sprites: [] 100 | outline: [] 101 | physicsShape: [] 102 | bones: [] 103 | spriteID: 5e97eb03825dee720800000000000000 104 | internalID: 0 105 | vertices: [] 106 | indices: 107 | edges: [] 108 | weights: [] 109 | secondaryTextures: [] 110 | spritePackingTag: 111 | pSDRemoveMatte: 0 112 | pSDShowRemoveMatteOption: 0 113 | userData: 114 | assetBundleName: 115 | assetBundleVariant: 116 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Parallel.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3679f86354bde0144887e71a2be61ce4 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 1 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 8 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 3 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 256 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | forceMaximumCompressionQuality_BC6H_BC7: 1 73 | - serializedVersion: 3 74 | buildTarget: Standalone 75 | maxTextureSize: 256 76 | resizeAlgorithm: 0 77 | textureFormat: -1 78 | textureCompression: 1 79 | compressionQuality: 50 80 | crunchedCompression: 0 81 | allowsAlphaSplitting: 0 82 | overridden: 0 83 | androidETC2FallbackOverride: 0 84 | forceMaximumCompressionQuality_BC6H_BC7: 1 85 | - serializedVersion: 3 86 | buildTarget: Android 87 | maxTextureSize: 256 88 | resizeAlgorithm: 0 89 | textureFormat: -1 90 | textureCompression: 1 91 | compressionQuality: 50 92 | crunchedCompression: 0 93 | allowsAlphaSplitting: 0 94 | overridden: 0 95 | androidETC2FallbackOverride: 0 96 | forceMaximumCompressionQuality_BC6H_BC7: 1 97 | spriteSheet: 98 | serializedVersion: 2 99 | sprites: [] 100 | outline: [] 101 | physicsShape: [] 102 | bones: [] 103 | spriteID: 5e97eb03825dee720800000000000000 104 | internalID: 0 105 | vertices: [] 106 | indices: 107 | edges: [] 108 | weights: [] 109 | secondaryTextures: [] 110 | spritePackingTag: 111 | pSDRemoveMatte: 0 112 | pSDShowRemoveMatteOption: 0 113 | userData: 114 | assetBundleName: 115 | assetBundleVariant: 116 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/Repeater.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6197179f4ff5af544ac466bdbc9f6d02 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 1 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 8 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 3 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 256 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | forceMaximumCompressionQuality_BC6H_BC7: 1 73 | - serializedVersion: 3 74 | buildTarget: Standalone 75 | maxTextureSize: 256 76 | resizeAlgorithm: 0 77 | textureFormat: -1 78 | textureCompression: 1 79 | compressionQuality: 50 80 | crunchedCompression: 0 81 | allowsAlphaSplitting: 0 82 | overridden: 0 83 | androidETC2FallbackOverride: 0 84 | forceMaximumCompressionQuality_BC6H_BC7: 1 85 | - serializedVersion: 3 86 | buildTarget: Android 87 | maxTextureSize: 256 88 | resizeAlgorithm: 0 89 | textureFormat: -1 90 | textureCompression: 1 91 | compressionQuality: 50 92 | crunchedCompression: 0 93 | allowsAlphaSplitting: 0 94 | overridden: 0 95 | androidETC2FallbackOverride: 0 96 | forceMaximumCompressionQuality_BC6H_BC7: 1 97 | spriteSheet: 98 | serializedVersion: 2 99 | sprites: [] 100 | outline: [] 101 | physicsShape: [] 102 | bones: [] 103 | spriteID: 5e97eb03825dee720800000000000000 104 | internalID: 0 105 | vertices: [] 106 | indices: 107 | edges: [] 108 | weights: [] 109 | secondaryTextures: [] 110 | spritePackingTag: 111 | pSDRemoveMatte: 0 112 | pSDShowRemoveMatteOption: 0 113 | userData: 114 | assetBundleName: 115 | assetBundleVariant: 116 | -------------------------------------------------------------------------------- /UnityEX/Editor/Resources/BehaviorTree/Icons/RandomSequence.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b3f75b78f183f384d90e1c543cb5c689 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: -1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 1 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 8 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 3 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 256 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 1 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | forceMaximumCompressionQuality_BC6H_BC7: 1 73 | - serializedVersion: 3 74 | buildTarget: Standalone 75 | maxTextureSize: 256 76 | resizeAlgorithm: 0 77 | textureFormat: -1 78 | textureCompression: 1 79 | compressionQuality: 50 80 | crunchedCompression: 0 81 | allowsAlphaSplitting: 0 82 | overridden: 0 83 | androidETC2FallbackOverride: 0 84 | forceMaximumCompressionQuality_BC6H_BC7: 1 85 | - serializedVersion: 3 86 | buildTarget: Android 87 | maxTextureSize: 256 88 | resizeAlgorithm: 0 89 | textureFormat: -1 90 | textureCompression: 1 91 | compressionQuality: 50 92 | crunchedCompression: 0 93 | allowsAlphaSplitting: 0 94 | overridden: 0 95 | androidETC2FallbackOverride: 0 96 | forceMaximumCompressionQuality_BC6H_BC7: 1 97 | spriteSheet: 98 | serializedVersion: 2 99 | sprites: [] 100 | outline: [] 101 | physicsShape: [] 102 | bones: [] 103 | spriteID: 5e97eb03825dee720800000000000000 104 | internalID: 0 105 | vertices: [] 106 | indices: 107 | edges: [] 108 | weights: [] 109 | secondaryTextures: [] 110 | spritePackingTag: 111 | pSDRemoveMatte: 0 112 | pSDShowRemoveMatteOption: 0 113 | userData: 114 | assetBundleName: 115 | assetBundleVariant: 116 | -------------------------------------------------------------------------------- /UnityEX/Editor/TaskView.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | /*** 3 | * 4 | * Title: 5 | * 6 | * Description: 7 | * 8 | * Date: 9 | * Version: 10 | * Writer: 半只龙虾人 11 | * Github: https://github.com/haloman9527 12 | * Blog: https://www.haloman.net/ 13 | * 14 | */ 15 | #endregion 16 | 17 | #if UNITY_EDITOR 18 | using System.Reflection; 19 | using Atom.GraphProcessor.Editors; 20 | using UnityEditor; 21 | using UnityEditor.Experimental.GraphView; 22 | using UnityEngine; 23 | using UnityEngine.UIElements; 24 | 25 | namespace Atom.BehaviorTree.Editors 26 | { 27 | [CustomView(typeof(Task))] 28 | public class TaskView : BaseNodeView 29 | { 30 | Image icon; 31 | IconBadge badge; 32 | VisualElement stateBorder; 33 | float anim = 0; 34 | public TaskView() : base() 35 | { 36 | styleSheets.Add(Resources.Load("BehaviorTree/Uss/Task")); 37 | icon = new Image() { name = "icon" }; 38 | controls.Add(icon); 39 | 40 | stateBorder = new VisualElement(); 41 | stateBorder.name = "state-border"; 42 | stateBorder.StretchToParentSize(); 43 | stateBorder.pickingMode = PickingMode.Ignore; 44 | Insert(0, stateBorder); 45 | } 46 | 47 | public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) 48 | { 49 | base.BuildContextualMenu(evt); 50 | evt.menu.AppendAction($"Execute", _ => { T_ViewModel.Start(); }); 51 | evt.menu.AppendAction($"Stop", _ => { T_ViewModel.Stop(); }); 52 | } 53 | 54 | protected override void DoInit() 55 | { 56 | base.DoInit(); 57 | if (T_ViewModel.CurrentState == TaskState.Active) 58 | OnStart(); 59 | T_ViewModel.OnStart += OnStart; 60 | T_ViewModel.OnStop += OnStop; 61 | switch (ViewModel) 62 | { 63 | case ActionTaskProcessor: 64 | { 65 | this.AddToClassList("action-task"); 66 | break; 67 | } 68 | case DecoratorTaskProcessor: 69 | { 70 | this.AddToClassList("decorator-task"); 71 | break; 72 | } 73 | case CompositeTaskProcessor: 74 | { 75 | this.AddToClassList("composite-task"); 76 | break; 77 | } 78 | } 79 | var iconAttr = ViewModel.ModelType.GetCustomAttribute(true); 80 | if (iconAttr != null) 81 | { 82 | icon.style.backgroundImage = Resources.Load(iconAttr.path); 83 | } 84 | if (ViewModel.Ports.ContainsKey("Children")) 85 | { 86 | badge = IconBadge.CreateError("需要子节点"); 87 | RefreshBadge(); 88 | ViewModel.Ports["Children"].OnConnected += _ => 89 | { 90 | RefreshBadge(); 91 | }; 92 | ViewModel.Ports["Children"].onDisconnected += _ => 93 | { 94 | RefreshBadge(); 95 | }; 96 | } 97 | } 98 | 99 | protected override void DoUnInit() 100 | { 101 | base.DoUnInit(); 102 | T_ViewModel.OnStart -= OnStart; 103 | T_ViewModel.OnStop -= OnStop; 104 | } 105 | 106 | void RefreshBadge() 107 | { 108 | if (T_ViewModel.Ports["Children"].Connections.Count != 0) 109 | RemoveBadge(_ => _ == badge); 110 | else 111 | AddBadge(badge); 112 | } 113 | 114 | public void UpdateState() 115 | { 116 | if (!Application.isPlaying) 117 | return; 118 | anim = Mathf.Clamp01(anim - 0.2f); 119 | if (T_ViewModel.CurrentState == TaskState.Active) 120 | anim = 1; 121 | stateBorder.style.opacity = anim; 122 | } 123 | 124 | private void OnStart() 125 | { 126 | if (!Application.isPlaying) 127 | return; 128 | anim = 1; 129 | stateBorder.RemoveFromClassList("success"); 130 | stateBorder.RemoveFromClassList("failure"); 131 | stateBorder.RemoveFromClassList("running"); 132 | 133 | stateBorder.AddToClassList("running"); 134 | } 135 | 136 | private void OnStop(bool result) 137 | { 138 | if (!Application.isPlaying) 139 | return; 140 | anim = 1; 141 | stateBorder.RemoveFromClassList("success"); 142 | stateBorder.RemoveFromClassList("failure"); 143 | stateBorder.RemoveFromClassList("running"); 144 | 145 | if (result) 146 | stateBorder.AddToClassList("success"); 147 | else 148 | stateBorder.AddToClassList("failure"); 149 | } 150 | } 151 | } 152 | #endif -------------------------------------------------------------------------------- /UnityEX/Editor/BehaviorTreeGraphWindow.cs: -------------------------------------------------------------------------------- 1 | #region 注 释 2 | 3 | /*** 4 | * 5 | * Title: 6 | * 7 | * Description: 8 | * 9 | * Date: 10 | * Version: 11 | * Writer: 半只龙虾人 12 | * Github: https://github.com/haloman9527 13 | * Blog: https://www.haloman.net/ 14 | * 15 | */ 16 | 17 | #endregion 18 | 19 | #if UNITY_EDITOR 20 | using System.Collections.Generic; 21 | using Atom.GraphProcessor; 22 | using Atom.GraphProcessor.Editors; 23 | using Atom; 24 | using Sirenix.Serialization; 25 | using UnityEditor; 26 | using UnityEditor.Experimental.GraphView; 27 | using UnityEditor.UIElements; 28 | using UnityEngine; 29 | using UnityEngine.UIElements; 30 | using GraphProcessor_Group = Atom.GraphProcessor.Group; 31 | using Group = Atom.GraphProcessor.Group; 32 | using UnityObject = UnityEngine.Object; 33 | 34 | namespace Atom.BehaviorTree.Editors 35 | { 36 | [CustomView(typeof(BehaviorTree))] 37 | public class BehaviorTreeGraphWindow : BaseGraphWindow 38 | { 39 | protected override void OnEnable() 40 | { 41 | base.OnEnable(); 42 | titleContent = new GUIContent("Behavior Tree"); 43 | } 44 | 45 | private void OnSelectionChange() 46 | { 47 | if (Selection.activeTransform == null) 48 | return; 49 | var agent = Selection.activeTransform.GetComponent(); 50 | if (agent == null) 51 | return; 52 | if (agent.Graph == null) 53 | return; 54 | if (agent is IGraphAssetOwner graphAssetOwner) 55 | { 56 | if (graphAssetOwner.GraphAsset != null && (agent != GraphOwner || graphAssetOwner.GraphAsset != GraphAsset || agent.Graph != GraphOwner.Graph)) 57 | LoadFromGraphAssetOwner(graphAssetOwner); 58 | } 59 | else if (agent is IGraphOwner graphOwner) 60 | { 61 | if (agent != GraphOwner) 62 | LoadFromGraphOwner(graphOwner); 63 | } 64 | } 65 | 66 | protected override BaseGraphView NewGraphView() 67 | { 68 | return new BehaviorTreeGraphView(); 69 | } 70 | 71 | protected override void Save() 72 | { 73 | if (GraphAsset == null) 74 | { 75 | var path = EditorUtility.SaveFilePanelInProject("保存", "New BehavorTree", "asset", "Create BehaviorTree Asset"); 76 | if (string.IsNullOrEmpty(path)) 77 | return; 78 | var asset = ScriptableObject.CreateInstance(); 79 | AssetDatabase.CreateAsset(asset, path); 80 | this.LoadFromGraphAsset(asset); 81 | } 82 | base.Save(); 83 | } 84 | 85 | protected override void OnKeyDownCallback(KeyDownEvent evt) 86 | { 87 | base.OnKeyDownCallback(evt); 88 | if (evt.commandKey || evt.ctrlKey) 89 | { 90 | switch (evt.keyCode) 91 | { 92 | case KeyCode.D: 93 | Duplicate(); 94 | evt.StopImmediatePropagation(); 95 | break; 96 | } 97 | } 98 | } 99 | 100 | private void Duplicate() 101 | { 102 | if (GraphView == null) 103 | return; 104 | // 收集所有节点,连线 105 | Dictionary nodes = new Dictionary(); 106 | List connections = new List(); 107 | List groups = new List(); 108 | foreach (var item in GraphView.selection) 109 | { 110 | switch (item) 111 | { 112 | case BaseNodeView nodeView: 113 | nodes.Add(nodeView.ViewModel.ID, nodeView.ViewModel.Model); 114 | break; 115 | case BaseConnectionView connectionView: 116 | connections.Add(connectionView.ViewModel.Model); 117 | break; 118 | case GroupView groupView: 119 | groups.Add(groupView.ViewModel.Model); 120 | break; 121 | } 122 | } 123 | 124 | var nodesStr = Sirenix.Serialization.SerializationUtility.SerializeValue(nodes, DataFormat.Binary); 125 | var connectionsStr = Sirenix.Serialization.SerializationUtility.SerializeValue(connections, DataFormat.Binary); 126 | var groupsStr = Sirenix.Serialization.SerializationUtility.SerializeValue(groups, DataFormat.Binary); 127 | 128 | nodes = Sirenix.Serialization.SerializationUtility.DeserializeValue>(nodesStr, DataFormat.Binary); 129 | connections = Sirenix.Serialization.SerializationUtility.DeserializeValue>(connectionsStr, DataFormat.Binary); 130 | groups = Sirenix.Serialization.SerializationUtility.DeserializeValue>(groupsStr, DataFormat.Binary); 131 | 132 | var graph = GraphView.ViewModel; 133 | var nodeMaps = new Dictionary(); 134 | 135 | GraphView.ClearSelection(); 136 | var selectables = new List(32); 137 | 138 | foreach (var pair in nodes) 139 | { 140 | pair.Value.id = GraphProcessorUtil.GenerateId(); 141 | pair.Value.position += new InternalVector2Int(50, 50); 142 | var vm = ViewModelFactory.ProduceViewModel(pair.Value) as BaseNodeProcessor; 143 | GraphView.Context.Do(new AddNodeCommand(graph, vm)); 144 | nodeMaps[pair.Key] = vm; 145 | selectables.Add(GraphView.NodeViews[vm.ID]); 146 | } 147 | 148 | foreach (var connection in connections) 149 | { 150 | if (nodeMaps.TryGetValue(connection.fromNode, out var from)) 151 | connection.fromNode = from.ID; 152 | 153 | if (nodeMaps.TryGetValue(connection.toNode, out var to)) 154 | connection.toNode = to.ID; 155 | 156 | var vm = ViewModelFactory.ProduceViewModel(connection) as BaseConnectionProcessor; 157 | GraphView.Context.Do(new ConnectCommand(graph, vm)); 158 | selectables.Add(GraphView.ConnectionViews[vm]); 159 | } 160 | 161 | foreach (var group in groups) 162 | { 163 | for (int i = group.nodes.Count - 1; i >= 0; i--) 164 | { 165 | if (nodeMaps.TryGetValue(group.nodes[i], out var node)) 166 | group.nodes[i] = node.ID; 167 | else 168 | group.nodes.RemoveAt(i); 169 | } 170 | 171 | group.id = GraphProcessorUtil.GenerateId(); 172 | GraphView.Context.Do(new AddGroupCommand(graph, group)); 173 | selectables.Add(GraphView.GroupViews[group.id]); 174 | } 175 | 176 | GraphView.AddToSelection(selectables); 177 | } 178 | } 179 | } 180 | #endif -------------------------------------------------------------------------------- /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: 9 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_UseRadianceAmbientProbe: 0 42 | --- !u!157 &3 43 | LightmapSettings: 44 | m_ObjectHideFlags: 0 45 | serializedVersion: 12 46 | m_GIWorkflowMode: 1 47 | m_GISettings: 48 | serializedVersion: 2 49 | m_BounceScale: 1 50 | m_IndirectOutputScale: 1 51 | m_AlbedoBoost: 1 52 | m_EnvironmentLightingMode: 0 53 | m_EnableBakedLightmaps: 1 54 | m_EnableRealtimeLightmaps: 0 55 | m_LightmapEditorSettings: 56 | serializedVersion: 12 57 | m_Resolution: 2 58 | m_BakeResolution: 40 59 | m_AtlasSize: 1024 60 | m_AO: 0 61 | m_AOMaxDistance: 1 62 | m_CompAOExponent: 1 63 | m_CompAOExponentDirect: 0 64 | m_ExtractAmbientOcclusion: 0 65 | m_Padding: 2 66 | m_LightmapParameters: {fileID: 0} 67 | m_LightmapsBakeMode: 1 68 | m_TextureCompression: 1 69 | m_FinalGather: 0 70 | m_FinalGatherFiltering: 1 71 | m_FinalGatherRayCount: 256 72 | m_ReflectionCompression: 2 73 | m_MixedBakeMode: 2 74 | m_BakeBackend: 1 75 | m_PVRSampling: 1 76 | m_PVRDirectSampleCount: 32 77 | m_PVRSampleCount: 512 78 | m_PVRBounces: 2 79 | m_PVREnvironmentSampleCount: 256 80 | m_PVREnvironmentReferencePointCount: 2048 81 | m_PVRFilteringMode: 1 82 | m_PVRDenoiserTypeDirect: 1 83 | m_PVRDenoiserTypeIndirect: 1 84 | m_PVRDenoiserTypeAO: 1 85 | m_PVRFilterTypeDirect: 0 86 | m_PVRFilterTypeIndirect: 0 87 | m_PVRFilterTypeAO: 0 88 | m_PVREnvironmentMIS: 1 89 | m_PVRCulling: 1 90 | m_PVRFilteringGaussRadiusDirect: 1 91 | m_PVRFilteringGaussRadiusIndirect: 5 92 | m_PVRFilteringGaussRadiusAO: 2 93 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 94 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 95 | m_PVRFilteringAtrousPositionSigmaAO: 1 96 | m_ExportTrainingData: 0 97 | m_TrainingDataDestination: TrainingData 98 | m_LightProbeSampleCountMultiplier: 4 99 | m_LightingDataAsset: {fileID: 0} 100 | m_LightingSettings: {fileID: 0} 101 | --- !u!196 &4 102 | NavMeshSettings: 103 | serializedVersion: 2 104 | m_ObjectHideFlags: 0 105 | m_BuildSettings: 106 | serializedVersion: 3 107 | agentTypeID: 0 108 | agentRadius: 0.5 109 | agentHeight: 2 110 | agentSlope: 45 111 | agentClimb: 0.4 112 | ledgeDropHeight: 0 113 | maxJumpAcrossDistance: 0 114 | minRegionArea: 2 115 | manualCellSize: 0 116 | cellSize: 0.16666667 117 | manualTileSize: 0 118 | tileSize: 256 119 | buildHeightMesh: 0 120 | maxJobWorkers: 0 121 | preserveTilesOutsideBounds: 0 122 | debug: 123 | m_Flags: 0 124 | m_NavMeshData: {fileID: 0} 125 | --- !u!1 &776691972 126 | GameObject: 127 | m_ObjectHideFlags: 0 128 | m_CorrespondingSourceObject: {fileID: 0} 129 | m_PrefabInstance: {fileID: 0} 130 | m_PrefabAsset: {fileID: 0} 131 | serializedVersion: 6 132 | m_Component: 133 | - component: {fileID: 776691975} 134 | - component: {fileID: 776691974} 135 | - component: {fileID: 776691973} 136 | m_Layer: 0 137 | m_Name: Directional Light 138 | m_TagString: Untagged 139 | m_Icon: {fileID: 0} 140 | m_NavMeshLayer: 0 141 | m_StaticEditorFlags: 0 142 | m_IsActive: 1 143 | --- !u!114 &776691973 144 | MonoBehaviour: 145 | m_ObjectHideFlags: 0 146 | m_CorrespondingSourceObject: {fileID: 0} 147 | m_PrefabInstance: {fileID: 0} 148 | m_PrefabAsset: {fileID: 0} 149 | m_GameObject: {fileID: 776691972} 150 | m_Enabled: 1 151 | m_EditorHideFlags: 0 152 | m_Script: {fileID: 11500000, guid: 914a8c2649986da458d5883776035e54, type: 3} 153 | m_Name: 154 | m_EditorClassIdentifier: 155 | behaviorTreeAsset: {fileID: 11400000, guid: 7ce38845b77af33449d3d52f03737add, type: 2} 156 | --- !u!108 &776691974 157 | Light: 158 | m_ObjectHideFlags: 0 159 | m_CorrespondingSourceObject: {fileID: 0} 160 | m_PrefabInstance: {fileID: 0} 161 | m_PrefabAsset: {fileID: 0} 162 | m_GameObject: {fileID: 776691972} 163 | m_Enabled: 1 164 | serializedVersion: 10 165 | m_Type: 1 166 | m_Shape: 0 167 | m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} 168 | m_Intensity: 1 169 | m_Range: 10 170 | m_SpotAngle: 30 171 | m_InnerSpotAngle: 21.80208 172 | m_CookieSize: 10 173 | m_Shadows: 174 | m_Type: 2 175 | m_Resolution: -1 176 | m_CustomResolution: -1 177 | m_Strength: 1 178 | m_Bias: 0.05 179 | m_NormalBias: 0.4 180 | m_NearPlane: 0.2 181 | m_CullingMatrixOverride: 182 | e00: 1 183 | e01: 0 184 | e02: 0 185 | e03: 0 186 | e10: 0 187 | e11: 1 188 | e12: 0 189 | e13: 0 190 | e20: 0 191 | e21: 0 192 | e22: 1 193 | e23: 0 194 | e30: 0 195 | e31: 0 196 | e32: 0 197 | e33: 1 198 | m_UseCullingMatrixOverride: 0 199 | m_Cookie: {fileID: 0} 200 | m_DrawHalo: 0 201 | m_Flare: {fileID: 0} 202 | m_RenderMode: 0 203 | m_CullingMask: 204 | serializedVersion: 2 205 | m_Bits: 4294967295 206 | m_RenderingLayerMask: 1 207 | m_Lightmapping: 4 208 | m_LightShadowCasterMode: 0 209 | m_AreaSize: {x: 1, y: 1} 210 | m_BounceIntensity: 1 211 | m_ColorTemperature: 6570 212 | m_UseColorTemperature: 0 213 | m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} 214 | m_UseBoundingSphereOverride: 0 215 | m_UseViewFrustumForShadowCasterCull: 1 216 | m_ShadowRadius: 0 217 | m_ShadowAngle: 0 218 | --- !u!4 &776691975 219 | Transform: 220 | m_ObjectHideFlags: 0 221 | m_CorrespondingSourceObject: {fileID: 0} 222 | m_PrefabInstance: {fileID: 0} 223 | m_PrefabAsset: {fileID: 0} 224 | m_GameObject: {fileID: 776691972} 225 | serializedVersion: 2 226 | m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} 227 | m_LocalPosition: {x: 0, y: 3, z: 0} 228 | m_LocalScale: {x: 1, y: 1, z: 1} 229 | m_ConstrainProportionsScale: 0 230 | m_Children: [] 231 | m_Father: {fileID: 0} 232 | m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} 233 | --- !u!1 &869275108 234 | GameObject: 235 | m_ObjectHideFlags: 0 236 | m_CorrespondingSourceObject: {fileID: 0} 237 | m_PrefabInstance: {fileID: 0} 238 | m_PrefabAsset: {fileID: 0} 239 | serializedVersion: 6 240 | m_Component: 241 | - component: {fileID: 869275111} 242 | - component: {fileID: 869275110} 243 | - component: {fileID: 869275109} 244 | m_Layer: 0 245 | m_Name: Main Camera 246 | m_TagString: MainCamera 247 | m_Icon: {fileID: 0} 248 | m_NavMeshLayer: 0 249 | m_StaticEditorFlags: 0 250 | m_IsActive: 1 251 | --- !u!81 &869275109 252 | AudioListener: 253 | m_ObjectHideFlags: 0 254 | m_CorrespondingSourceObject: {fileID: 0} 255 | m_PrefabInstance: {fileID: 0} 256 | m_PrefabAsset: {fileID: 0} 257 | m_GameObject: {fileID: 869275108} 258 | m_Enabled: 1 259 | --- !u!20 &869275110 260 | Camera: 261 | m_ObjectHideFlags: 0 262 | m_CorrespondingSourceObject: {fileID: 0} 263 | m_PrefabInstance: {fileID: 0} 264 | m_PrefabAsset: {fileID: 0} 265 | m_GameObject: {fileID: 869275108} 266 | m_Enabled: 1 267 | serializedVersion: 2 268 | m_ClearFlags: 1 269 | m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} 270 | m_projectionMatrixMode: 1 271 | m_GateFitMode: 2 272 | m_FOVAxisMode: 0 273 | m_Iso: 200 274 | m_ShutterSpeed: 0.005 275 | m_Aperture: 16 276 | m_FocusDistance: 10 277 | m_FocalLength: 50 278 | m_BladeCount: 5 279 | m_Curvature: {x: 2, y: 11} 280 | m_BarrelClipping: 0.25 281 | m_Anamorphism: 0 282 | m_SensorSize: {x: 36, y: 24} 283 | m_LensShift: {x: 0, y: 0} 284 | m_NormalizedViewPortRect: 285 | serializedVersion: 2 286 | x: 0 287 | y: 0 288 | width: 1 289 | height: 1 290 | near clip plane: 0.3 291 | far clip plane: 1000 292 | field of view: 60 293 | orthographic: 0 294 | orthographic size: 5 295 | m_Depth: -1 296 | m_CullingMask: 297 | serializedVersion: 2 298 | m_Bits: 4294967295 299 | m_RenderingPath: -1 300 | m_TargetTexture: {fileID: 0} 301 | m_TargetDisplay: 0 302 | m_TargetEye: 3 303 | m_HDR: 1 304 | m_AllowMSAA: 1 305 | m_AllowDynamicResolution: 0 306 | m_ForceIntoRT: 0 307 | m_OcclusionCulling: 1 308 | m_StereoConvergence: 10 309 | m_StereoSeparation: 0.022 310 | --- !u!4 &869275111 311 | Transform: 312 | m_ObjectHideFlags: 0 313 | m_CorrespondingSourceObject: {fileID: 0} 314 | m_PrefabInstance: {fileID: 0} 315 | m_PrefabAsset: {fileID: 0} 316 | m_GameObject: {fileID: 869275108} 317 | serializedVersion: 2 318 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 319 | m_LocalPosition: {x: 0, y: 1, z: -10} 320 | m_LocalScale: {x: 1, y: 1, z: 1} 321 | m_ConstrainProportionsScale: 0 322 | m_Children: [] 323 | m_Father: {fileID: 0} 324 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 325 | --- !u!1660057539 &9223372036854775807 326 | SceneRoots: 327 | m_ObjectHideFlags: 0 328 | m_Roots: 329 | - {fileID: 869275111} 330 | - {fileID: 776691975} 331 | --------------------------------------------------------------------------------