├── README.md └── behaviortree-editor ├── panel ├── icon │ ├── root.svg │ ├── sequence.svg │ ├── succeeder.svg │ ├── mensequence.svg │ ├── repeatuntilfailure.svg │ ├── wait.svg │ ├── priority.svg │ ├── limit.svg │ ├── repeatuntilsuccess.svg │ ├── menpriority.svg │ ├── customaction.svg │ ├── inverter.svg │ ├── repeat.svg │ ├── customdecorator.svg │ ├── error.svg │ ├── maxtime.svg │ ├── customcondition.svg │ ├── failer.svg │ ├── base.svg │ ├── customcomposite.svg │ └── running.svg ├── node_modules │ └── gojs │ │ ├── bower.json │ │ ├── README.md │ │ └── package.json ├── index.html ├── jsoneditor.css └── img │ └── jsoneditor-icons.svg ├── bt-inspector.js ├── package.json ├── main.js └── b3core.0.1.0module.js /README.md: -------------------------------------------------------------------------------- 1 | # cocos-creator-behavior-tree-editor 2 | youtube: [cocos creator visual behavior tree editor package introduction ](https://www.youtube.com/watch?v=tNkTQk18YlU) 3 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/root.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/sequence.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/succeeder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/mensequence.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/bt-inspector.js: -------------------------------------------------------------------------------- 1 | Vue.component('foobar-inspector', { 2 | template: ` 3 | 编辑 4 | `, 5 | 6 | props: { 7 | target: { 8 | twoWay: true, 9 | type: Object, 10 | }, 11 | }, 12 | 13 | methods: { 14 | openBTEditor:function(){ 15 | Editor.Ipc.sendToMain('behaviortree-editor:re-open-by-comp',{uuid:this.target.__scriptAsset.value.uuid,name:this.target.name.value}); 16 | } 17 | } 18 | }); -------------------------------------------------------------------------------- /behaviortree-editor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "behaviortree-editor", 3 | "version": "0.0.1", 4 | "description": "行为树可视化编辑器", 5 | "author": "Cocos Creator", 6 | "main": "main.js", 7 | "main-menu": { 8 | "bt-editor/open": { 9 | "message": "behaviortree-editor:open" 10 | } 11 | }, 12 | "panel": { 13 | "main": "panel/index.html", 14 | "type": "simple", 15 | "title": "behaviortree-editor", 16 | "width": "100%", 17 | "height": "100%" 18 | } 19 | } -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/repeatuntilfailure.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/wait.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/priority.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/limit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/repeatuntilsuccess.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/menpriority.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/customaction.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/inverter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/repeat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/customdecorator.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/maxtime.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/customcondition.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/failer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/base.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/customcomposite.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/node_modules/gojs/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gojs", 3 | "description": "Interactive diagrams, charts, and graphs, such as trees, flowcharts, orgcharts, UML, BPMN, or business diagrams", 4 | "main": "release/go.js", 5 | "moduleType": [ "globals", "amd", "node" ], 6 | "license": "https://gojs.net/latest/doc/license.html", 7 | "ignore": [ "**/.*" ], 8 | "keywords": [ "diagram", "chart", "tree", "flowchart", "orgchart", "uml", "bpmn", "graphics", "editor", "inspector", "drawing", "canvas", "shape", "svg", "hierarchy", "node", "link", "group", "vertex", "edge", "connection", "port", "label", "arrowhead", "family-tree", "decision-tree", "mindmap", "tournament", "treeview", "pipe-tree", "genogram", "ivr-tree", "parse-tree", "concept-map", "euler", "visualization", "entity-relationship", "er-diagram", "friend-wheel", "radial", "graph-distances", "graph-paths", "sankey", "pert", "gantt", "timeline", "monitor", "layer", "swimlane", "spreadsheet", "virtualization", "flow", "process", "state", "sequential-function", "grafcet", "sequence", "circuit", "record", "field", "table", "dataflow", "data-flow", "planogram", "seating", "pipes", "overview", "palette", "comment", "layout", "grid-layout", "tree-layout", "force-directed", "layered", "hierarchical", "circular", "fishbone", "ishikawa", "parallel", "serpentine", "treemap", "tree-map", "freehand", "polygon", "polyline", "bezier", "panel", "view", "model", "databinding", "data-binding", "binding", "transaction", "coordinates", "subgraph", "selection", "highlight", "tooltip", "context-menu", "tool", "command", "validation", "button", "template", "legend", "grid", "printing" ], 9 | "authors": [ "Northwoods Software" ], 10 | "homepage": "https://gojs.net" 11 | } -------------------------------------------------------------------------------- /behaviortree-editor/panel/node_modules/gojs/README.md: -------------------------------------------------------------------------------- 1 | GoJS, a JavaScript Library for HTML Diagrams 2 | ============================================ 3 | 4 | 5 | 6 | [GoJS](https://gojs.net) is a JavaScript and HTML5 library for creating interactive diagrams, charts, and graphs. 7 | 8 | [See GoJS Samples](https://gojs.net/latest/samples). 9 | 10 | [Get Started with GoJS](https://gojs.net/latest/learn) 11 | 12 | Read more about GoJS at [gojs.net](https://gojs.net) 13 | 14 | This repository contains both the library and the sources for all samples, extensions, and documentation. 15 | You can use the GitHub repository to quickly [search through all of the sources](https://github.com/NorthwoodsSoftware/GoJS-Samples/search?q=setDataProperty&type=Code). 16 | 17 | 18 |

Support

19 | 20 | Northwoods Software offers a month of free developer-to-developer support for GoJS to help you get started on your project. 21 | 22 | Read and search the official GoJS forum for any topics related to your questions. 23 | 24 | Posting in the forum is the fastest and most effective way of obtaining support for any GoJS related inquiries. 25 | Please register for support at Northwoods Software's registration form before posting in the forum. 26 | 27 | For any nontechnical questions about GoJS, such as about sales or licensing, 28 | please visit Northwoods Software's contact form. 29 | 30 | 31 |

License

32 | 33 | The GoJS software license. 34 | 35 | Copyright (c) Northwoods Software Corporation -------------------------------------------------------------------------------- /behaviortree-editor/panel/icon/running.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/node_modules/gojs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_args": [ 3 | [ 4 | { 5 | "raw": "gojs", 6 | "scope": null, 7 | "escapedName": "gojs", 8 | "name": "gojs", 9 | "rawSpec": "", 10 | "spec": "latest", 11 | "type": "tag" 12 | }, 13 | "C:\\Users\\Administrator\\Desktop\\test_behaviour_tree" 14 | ] 15 | ], 16 | "_cnpm_publish_time": 1487779127170, 17 | "_from": "gojs@latest", 18 | "_id": "gojs@1.7.0", 19 | "_inCache": true, 20 | "_location": "/gojs", 21 | "_nodeVersion": "5.10.1", 22 | "_npmOperationalInternal": { 23 | "host": "packages-12-west.internal.npmjs.com", 24 | "tmp": "tmp/gojs-1.7.0.tgz_1487779123549_0.9793568486347795" 25 | }, 26 | "_npmUser": { 27 | "name": "gojs", 28 | "email": "gojs@nwoods.com" 29 | }, 30 | "_npmVersion": "3.8.3", 31 | "_phantomChildren": {}, 32 | "_requested": { 33 | "raw": "gojs", 34 | "scope": null, 35 | "escapedName": "gojs", 36 | "name": "gojs", 37 | "rawSpec": "", 38 | "spec": "latest", 39 | "type": "tag" 40 | }, 41 | "_requiredBy": [ 42 | "#USER" 43 | ], 44 | "_resolved": "https://registry.npm.taobao.org/gojs/download/gojs-1.7.0.tgz", 45 | "_shasum": "78a1b2de2978fe69afe16a369e1262692ead3393", 46 | "_shrinkwrap": null, 47 | "_spec": "gojs", 48 | "_where": "C:\\Users\\Administrator\\Desktop\\test_behaviour_tree", 49 | "author": { 50 | "name": "Northwoods Software" 51 | }, 52 | "bugs": { 53 | "url": "https://forum.nwoods.com/c/gojs", 54 | "email": "gojs@nwoods.com" 55 | }, 56 | "dependencies": {}, 57 | "description": "Interactive diagrams, charts, and graphs, such as trees, flowcharts, orgcharts, UML, BPMN, or business diagrams", 58 | "devDependencies": {}, 59 | "directories": {}, 60 | "dist": { 61 | "shasum": "78a1b2de2978fe69afe16a369e1262692ead3393", 62 | "size": 6631621, 63 | "noattachment": false, 64 | "tarball": "http://registry.npm.taobao.org/gojs/download/gojs-1.7.0.tgz" 65 | }, 66 | "files": [ 67 | "package.json", 68 | "bower.json", 69 | "index.html", 70 | "README.md", 71 | "api", 72 | "assets", 73 | "doc/changelog.html", 74 | "doc/download.html", 75 | "doc/license.html", 76 | "extensions", 77 | "intro", 78 | "learn", 79 | "projects", 80 | "release/go.js", 81 | "release/go-debug.js", 82 | "release/go.d.ts", 83 | "samples" 84 | ], 85 | "homepage": "https://gojs.net", 86 | "keywords": [ 87 | "diagram", 88 | "chart", 89 | "tree", 90 | "flowchart", 91 | "orgchart", 92 | "uml", 93 | "bpmn", 94 | "graphics", 95 | "editor", 96 | "inspector", 97 | "drawing", 98 | "canvas", 99 | "shape", 100 | "svg", 101 | "hierarchy", 102 | "node", 103 | "link", 104 | "group", 105 | "vertex", 106 | "edge", 107 | "connection", 108 | "port", 109 | "label", 110 | "arrowhead", 111 | "family-tree", 112 | "decision-tree", 113 | "mindmap", 114 | "tournament", 115 | "treeview", 116 | "pipe-tree", 117 | "genogram", 118 | "ivr-tree", 119 | "parse-tree", 120 | "concept-map", 121 | "euler", 122 | "visualization", 123 | "entity-relationship", 124 | "er-diagram", 125 | "friend-wheel", 126 | "radial", 127 | "graph-distances", 128 | "graph-paths", 129 | "sankey", 130 | "pert", 131 | "gantt", 132 | "timeline", 133 | "monitor", 134 | "layer", 135 | "swimlane", 136 | "spreadsheet", 137 | "virtualization", 138 | "flow", 139 | "process", 140 | "state", 141 | "sequential-function", 142 | "grafcet", 143 | "sequence", 144 | "circuit", 145 | "record", 146 | "field", 147 | "table", 148 | "dataflow", 149 | "data-flow", 150 | "planogram", 151 | "seating", 152 | "pipes", 153 | "overview", 154 | "palette", 155 | "comment", 156 | "layout", 157 | "grid-layout", 158 | "tree-layout", 159 | "force-directed", 160 | "layered", 161 | "hierarchical", 162 | "circular", 163 | "fishbone", 164 | "ishikawa", 165 | "parallel", 166 | "serpentine", 167 | "treemap", 168 | "tree-map", 169 | "freehand", 170 | "polygon", 171 | "polyline", 172 | "bezier", 173 | "panel", 174 | "view", 175 | "model", 176 | "databinding", 177 | "data-binding", 178 | "binding", 179 | "transaction", 180 | "coordinates", 181 | "subgraph", 182 | "selection", 183 | "highlight", 184 | "tooltip", 185 | "context-menu", 186 | "tool", 187 | "command", 188 | "validation", 189 | "button", 190 | "template", 191 | "legend", 192 | "grid", 193 | "printing" 194 | ], 195 | "license": "SEE LICENSE AT https://gojs.net/latest/doc/license.html", 196 | "main": "release/go.js", 197 | "maintainers": [ 198 | { 199 | "name": "gojs", 200 | "email": "gojs@nwoods.com" 201 | }, 202 | { 203 | "name": "simonsarris", 204 | "email": "simon@nwoods.com" 205 | } 206 | ], 207 | "name": "gojs", 208 | "optionalDependencies": {}, 209 | "publish_time": 1487779127170, 210 | "readme": "ERROR: No README data found!", 211 | "repository": { 212 | "type": "git", 213 | "url": "git+https://github.com/NorthwoodsSoftware/GoJS.git" 214 | }, 215 | "scripts": {}, 216 | "typings": "release/go.d.ts", 217 | "version": "1.7.0" 218 | } 219 | -------------------------------------------------------------------------------- /behaviortree-editor/panel/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

5 |
6 |
7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 | 17 | 18 | 19 | 269 | 270 | -------------------------------------------------------------------------------- /behaviortree-editor/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | let reEditing = false; 3 | let reSaving = false; 4 | let reEditingModelString = null; 5 | let reEditingUuid = null; 6 | let reEditingName = null; 7 | 8 | module.exports = { 9 | load () { 10 | // 当 package 被正确加载的时候执行 11 | //console.log("behaviortree-editor loaded"); 12 | }, 13 | 14 | unload () { 15 | // 当 package 被正确卸载的时候执行 16 | //console.log("behaviortree-editor unloaded"); 17 | }, 18 | 19 | messages: { 20 | 'test' (e,arg){ 21 | Editor.log(arg); 22 | Editor.log(Editor.metas); 23 | }, 24 | 25 | 're-open-by-comp' (e,arg) { 26 | if(reEditing){ 27 | Editor.Dialog.messageBox ({ 28 | type:"none", 29 | buttons: ["shut up"], 30 | title:"tips", 31 | message: "you are locked in re-editing mode.", 32 | detail:"leave the re-editing mode and try again. maybe you should save first." 33 | },function(){}); 34 | 35 | return}; 36 | reEditing = true; 37 | Editor.Panel.open("behaviortree-editor"); 38 | //Editor.Ipc.sendToPanel('behaviortree-editor','load-data',); 39 | //Editor.log(arg.uuid); 40 | Editor.Ipc.sendToMain("asset-db:query-path-by-uuid",arg.uuid,function(e,result){ 41 | //Editor.log(e); 42 | //Editor.log(result); 43 | let fs_handler = require('fs'); 44 | fs_handler.readFile(result, "utf-8", function(err, data) { 45 | //Editor.log(data); 46 | let modelString= data.match(/\/\/#########################################.*#############################################/)[0].replace(/#*/g,"").replace(/^\/\//,""); 47 | reEditingModelString = modelString; 48 | reEditingUuid = arg.uuid; 49 | reEditingName = arg.name; 50 | //Editor.log(reEditingName); 51 | //Editor.log(modelData); 52 | //Editor.Ipc.sendToPanel("behaviortree-editor","re-modify-by-comp",{modelString:modelString,uuid:arg.uuid}); 53 | //require('electron').ipcMain.send('behaviortree-editor:re-modify-by-comp',{modelString:modelString,uuid:arg.uuid}); 54 | //Editor.log(Editor.Ipc); 55 | }); 56 | }); 57 | }, 58 | 'load-data-of-comp' (e,arg){ 59 | if(!reEditing){Editor.Dialog.messageBox ({ 60 | type:"none", 61 | buttons: ["shut up"], 62 | title:"tips", 63 | message: "you are not in re-editing mode", 64 | detail:"you can enter the re-editing mode from behaviortree-Component." 65 | },function(){}); 66 | e.reply(null,{error: true}); 67 | }else{ 68 | if(reSaving){Editor.log(Editor.Dialog.messageBox ({ 69 | type:"none", 70 | buttons: ["shut up"], 71 | title:"tips", 72 | message: "please wait the temp saving", 73 | detail:"after saving, you can load from lasteat saved data if in re-editing mode." 74 | },function(){}));e.reply(null,{error:true})} 75 | else{ 76 | e.reply(null,{error: false, reEditingModelString:reEditingModelString, reEditingName: reEditingName}); 77 | } 78 | } 79 | 80 | }, 81 | 'leave-re-editing-mode' (e){ 82 | reEditing = false; 83 | Editor.log(Editor.Dialog.messageBox ({ 84 | type:"none", 85 | buttons: ["shut up"], 86 | title:"tips", 87 | message: "you leave re-editing mode", 88 | detail:"in new mode the file would saved as default way.and just close the edit-panel would not leave re-editing mode." 89 | },function(){}));e.reply(null,{error:true}) 90 | e.reply(null,{}); 91 | }, 92 | 93 | 'open' () { 94 | Editor.Panel.open("behaviortree-editor"); 95 | }, 96 | 'receive-json' (e,arg) { 97 | let modelAsObj = arg; 98 | //console.log(modelAsObj); 99 | let nodeDataArray = modelAsObj.nodeDataArray; 100 | 101 | let getNodeByType = function(type){ 102 | for(let node of nodeDataArray){ 103 | if(node.type == type){ 104 | return node; 105 | } 106 | } 107 | }; 108 | 109 | let getNodesByParentKey = function(key){ 110 | let nodes = []; 111 | for(let node of nodeDataArray){ 112 | if(node.parent!== undefined && node.parent == key){ 113 | nodes.push(node); 114 | } 115 | } 116 | return nodes; 117 | }; 118 | 119 | let orderFromTopToDown = function(a,b){ 120 | let ay = a.loc.split(" ")[1]; 121 | let by = b.loc.split(" ")[1]; 122 | //Editor.log(ay,by,(ay - by) | 0); 123 | return (ay - by) | 0; 124 | } 125 | 126 | let rootNode = getNodeByType("Root"); 127 | 128 | let generateTreeLayerString = function(parentNode,childNodes){ 129 | let children = []; 130 | for(let childNode of childNodes){ 131 | if(childNode.name == childNode.type){ 132 | children.push("new b3." + childNode.type + "(" + "##key" + childNode.key +"##" +")"); 133 | }else{ 134 | children.push("new " + childNode.name + "(" +"##key" + childNode.key +"##"+ ")"); 135 | } 136 | // if(childNode.parameter){ 137 | // console.log(childNode.parameter.replace(/\"/g,"'")); 138 | // } 139 | } 140 | let tempParameter = JSON.parse(parentNode.parameter); 141 | let resultObj = {}; 142 | resultObj.parameter = parentNode.parameter.replace(/"/g,"'"); 143 | switch(parentNode.type){ 144 | case 'Limiter': 145 | case 'RepeaterUntilFailure': 146 | case 'RepeaterUntilSuccess': 147 | case 'Repeater':{resultObj.maxLoop = tempParameter.maxLoop; break;} 148 | } 149 | switch(parentNode.type){ 150 | case 'MaxTime': {resultObj.maxTime = rtempParameter.maxTime; break;} 151 | } 152 | switch(parentNode.type){ 153 | case 'Wait': {resultObj.milliseconds = tempParameter.milliseconds; break;} 154 | } 155 | switch(parentNode.catagory){ 156 | case 'Composite': {resultObj.children = children; break;} 157 | } 158 | switch(parentNode.catagory){ 159 | case 'Decorator': {resultObj.child = children[0]; break;} 160 | } 161 | 162 | return JSON.stringify(resultObj); 163 | } 164 | 165 | 166 | 167 | let nodeQuene = []; 168 | nodeQuene.push(rootNode); 169 | let finalString = "new b3.Sequence(##key" + rootNode.key +"##)"; 170 | while(nodeQuene.length != 0){ 171 | let node = nodeQuene.shift(); 172 | let childNodes = getNodesByParentKey(node.key); 173 | let orderedChildNodes = childNodes.sort(orderFromTopToDown); 174 | nodeQuene = nodeQuene.concat(orderedChildNodes); 175 | let gString = generateTreeLayerString(node,orderedChildNodes); 176 | finalString = finalString.replace("##key"+node.key+"##",gString); 177 | } 178 | //console.log(finalString); 179 | 180 | let customNodeString = "let self = this;\n"; 181 | let hasGeneratedNodes = []; 182 | for(let node of nodeDataArray){ 183 | if(hasGeneratedNodes[node.name] != undefined){continue;} 184 | if(node.name != node.type || node.type == 'Action' || node.type == 'Condition' || node.type == 'Composite' || node.type == 'Decorator'){ 185 | hasGeneratedNodes[node.name] = true; 186 | customNodeString += "let "+node.name+" = b3.Class(b3."+node.type+");\n" + 187 | node.name+".prototype.name = '"+node.name+"';\n" + 188 | node.name+".prototype.__"+node.catagory+"_initialize = "+node.name+".prototype.initialize;\n" + 189 | node.name+".prototype.initialize = function(settings){\n" + 190 | " settings = settings || {};\n" + 191 | " this.__"+node.catagory+"_initialize();\n" + 192 | " this.parameter = settings.parameter;\n"; 193 | switch(node.type){ 194 | case 'Limiter': 195 | case 'RepeaterUntilFailure': 196 | case 'RepeaterUntilSuccess': 197 | case 'Repeater':{customNodeString += "this.maxLoop = settings.maxLoop;\n";break;} 198 | } 199 | switch(node.type){ 200 | case 'MaxTime': {customNodeString += "this.maxTime = settings.maxTime;\n";break;} 201 | } 202 | switch(node.type){ 203 | case 'Wait': {customNodeString += "this.milliseconds = settings.milliseconds;\n";break;} 204 | } 205 | switch(node.catagory){ 206 | case 'Composite': {customNodeString += "this.children = settings.children;\n";break;} 207 | } 208 | switch(node.catagory){ 209 | case 'Decorator': {customNodeString += "this.child = settings.child;\n";break;} 210 | } 211 | customNodeString += "}\n" + 212 | node.name+".prototype.enter = function(tick){\n" + 213 | " return self.getComponent('"+node.name+"').enter(tick,b3,this);\n" + 214 | "}\n" + 215 | node.name+".prototype.open = function(tick) {\n" + 216 | " return self.getComponent('"+node.name+"').open(tick,b3,this);\n" + 217 | "}\n" + 218 | node.name+".prototype.tick = function(tick) {\n" + 219 | " return self.getComponent('"+node.name+"').tick(tick,b3,this);\n" + 220 | "}\n" + 221 | node.name+".prototype.close = function(tick) {\n" + 222 | " return self.getComponent('"+node.name+"').close(tick,b3,this);\n" + 223 | "}\n" + 224 | node.name+".prototype.exit = function(tick) {\n" + 225 | " return self.getComponent('"+node.name+"').exit(tick,b3,this);\n" + 226 | "}\n"; 227 | } 228 | } 229 | let tipsString = "//Don't modify this if you want to re-modify the behaviortree in the future\n"; 230 | let modelString = "//#########################################" + JSON.stringify(modelAsObj) + "#############################################\n"; 231 | 232 | let mainString = tipsString + 233 | modelString + 234 | "\n" + 235 | "\n" + 236 | "cc.Class({\n" + 237 | "extends: cc.Component,\n" + 238 | "editor: {\n" + 239 | "inspector: 'packages://behaviortree-editor/bt-inspector.js'\n"+ 240 | "},\n" + 241 | "properties: {\n" + 242 | "},\n" + 243 | "onLoad: function () {\n" + 244 | "let b3 = require('b3core.0.1.0module');\n"+ 245 | customNodeString + 246 | "let tree = new b3.BehaviorTree();\n"+ 247 | "tree.root = " + finalString.replace(/"/g,"") + ";\n"+ 248 | "this.tree = tree;\n"+ 249 | "this.blackboard = new b3.Blackboard();\n" + 250 | "this.b3 = b3;\n" + 251 | "},\n" + 252 | "tick: function(target){\n"+ 253 | "let t = {};\n" + 254 | "if(target != undefined){t = target;}\n" + 255 | "this.tree.tick(t,this.blackboard)\n" + 256 | "}" + 257 | "});\n"; 258 | 259 | //console.log(mainString); 260 | let fs_handler = require("fs"); 261 | if(reEditing){ 262 | Editor.Ipc.sendToMain("asset-db:query-url-by-uuid",reEditingUuid,function(e,result){ 263 | fs_handler.writeFileSync(Editor.url(result),mainString); 264 | Editor.Ipc.sendToMain("asset-db:refresh",result,function(err,results){ 265 | reSaving = true; 266 | fs_handler.readFile(Editor.url(result), "utf-8", function(err, data) { 267 | 268 | let modelString= data.match(/\/\/#########################################.*#############################################/)[0].replace(/#*/g,"").replace(/^\/\//,""); 269 | reEditingModelString = modelString; 270 | reSaving = false; 271 | Editor.log(Editor.Dialog.messageBox ({ 272 | type:"none", 273 | buttons: ["shut up"], 274 | title:"tips", 275 | message: "file of re-edit saved", 276 | detail:"you could see something blink blink in assetdb. take care of the component name." 277 | },function(){})); 278 | }); 279 | }); 280 | }); 281 | } 282 | else{ 283 | //生成行为树组件脚本 284 | fs_handler.writeFileSync(Editor.url("db://assets/BehaviorTree.js"),mainString); 285 | Editor.Ipc.sendToMain("asset-db:refresh","db://assets/BehaviorTree.js",function(err,results){ 286 | Editor.log(Editor.Dialog.messageBox ({ 287 | type:"none", 288 | buttons: ["shut up"], 289 | title:"tips", 290 | message: "file of new saved", 291 | detail:"you could see something new(maybe) in assetdb. take care of the component name." 292 | },function(){})); 293 | }); 294 | } 295 | 296 | }, 297 | 298 | 'add-lib' () { 299 | let fs_handler = require("fs"); 300 | fs_handler.writeFileSync(Editor.url("db://assets/b3core.0.1.0module.js"), fs_handler.readFileSync(Editor.url("packages://behaviortree-editor/b3core.0.1.0module.js"))); 301 | Editor.Ipc.sendToMain("asset-db:refresh","db://assets/b3core.0.1.0module.js",function(err,results){ 302 | Editor.log(Editor.Dialog.messageBox ({ 303 | type:"none", 304 | buttons: ["shut up"], 305 | title:"tips", 306 | message: "behaviortree lib added", 307 | detail:"even though the lib name is ugly, but don't modify it please." 308 | },function(){})); 309 | }); 310 | }, 311 | 312 | 'generate-tree-node-template' (){ 313 | let mainString = "cc.Class({\n" + 314 | "extends: cc.Component,\n" + 315 | "\n" + 316 | "properties: {\n" + 317 | "\n" + 318 | "},\n" + 319 | "\n" + 320 | "\n" + 321 | "onLoad: function () {\n" + 322 | "\n" + 323 | "},\n" + 324 | "enter: function(tick,b3,treeNode){\n" + 325 | "\n" + 326 | "},\n"+ 327 | "open: function(tick,b3,treeNode){\n" + 328 | "\n"+ 329 | "},\n" + 330 | "tick: function(tick,b3,treeNode){\n" + 331 | "\n"+ 332 | "},\n" + 333 | "close: function(tick,b3,treeNode){\n" + 334 | "\n" + 335 | "},\n" + 336 | "exit: function(tick,b3,treeNode){\n" + 337 | "\n" + 338 | "},\n" + 339 | "\n" + 340 | "});\n"; 341 | 342 | let fs_handler = require("fs"); 343 | fs_handler.writeFileSync(Editor.url("db://assets/TreeNodeTemplate.js"), mainString); 344 | Editor.Ipc.sendToMain("asset-db:refresh","db://assets/TreeNodeTemplate.js",function(err,results){ 345 | Editor.log(Editor.Dialog.messageBox ({ 346 | type:"none", 347 | buttons: ["shut up"], 348 | title:"tips", 349 | message: "treenode code template generated", 350 | detail:"look more about the code and the src in behaviortree lib to get more tips" 351 | },function(){})); 352 | }); 353 | }, 354 | 355 | }, 356 | 357 | }; -------------------------------------------------------------------------------- /behaviortree-editor/panel/jsoneditor.css: -------------------------------------------------------------------------------- 1 | /* reset styling (prevent conflicts with bootstrap, materialize.css, etc.) */ 2 | 3 | div.jsoneditor .jsoneditor-search input { 4 | height: auto; 5 | border: inherit; 6 | } 7 | 8 | div.jsoneditor .jsoneditor-search input:focus { 9 | border: none !important; 10 | box-shadow: none !important; 11 | } 12 | 13 | div.jsoneditor table { 14 | border-collapse: collapse; 15 | width: auto; 16 | } 17 | 18 | div.jsoneditor td, 19 | div.jsoneditor th { 20 | padding: 0; 21 | display: table-cell; 22 | text-align: left; 23 | vertical-align: inherit; 24 | border-radius: inherit; 25 | } 26 | 27 | 28 | div.jsoneditor-field, 29 | div.jsoneditor-value, 30 | div.jsoneditor-readonly { 31 | border: 1px solid transparent; 32 | min-height: 16px; 33 | min-width: 32px; 34 | padding: 2px; 35 | margin: 1px; 36 | word-wrap: break-word; 37 | float: left; 38 | } 39 | 40 | /* adjust margin of p elements inside editable divs, needed for Opera, IE */ 41 | 42 | div.jsoneditor-field p, 43 | div.jsoneditor-value p { 44 | margin: 0; 45 | } 46 | 47 | div.jsoneditor-value { 48 | word-break: break-word; 49 | } 50 | 51 | div.jsoneditor-readonly { 52 | min-width: 16px; 53 | color: gray; 54 | } 55 | 56 | div.jsoneditor-empty { 57 | border-color: lightgray; 58 | border-style: dashed; 59 | border-radius: 2px; 60 | } 61 | 62 | div.jsoneditor-field.jsoneditor-empty::after, 63 | div.jsoneditor-value.jsoneditor-empty::after { 64 | pointer-events: none; 65 | color: lightgray; 66 | font-size: 8pt; 67 | } 68 | 69 | div.jsoneditor-field.jsoneditor-empty::after { 70 | content: "field"; 71 | } 72 | 73 | div.jsoneditor-value.jsoneditor-empty::after { 74 | content: "value"; 75 | } 76 | 77 | div.jsoneditor-value.jsoneditor-url, 78 | a.jsoneditor-value.jsoneditor-url { 79 | color: green; 80 | text-decoration: underline; 81 | } 82 | 83 | a.jsoneditor-value.jsoneditor-url { 84 | display: inline-block; 85 | padding: 2px; 86 | margin: 2px; 87 | } 88 | 89 | a.jsoneditor-value.jsoneditor-url:hover, 90 | a.jsoneditor-value.jsoneditor-url:focus { 91 | color: #ee422e; 92 | } 93 | 94 | div.jsoneditor td.jsoneditor-separator { 95 | padding: 3px 0; 96 | vertical-align: top; 97 | color: gray; 98 | } 99 | 100 | div.jsoneditor-field[contenteditable=true]:focus, 101 | div.jsoneditor-field[contenteditable=true]:hover, 102 | div.jsoneditor-value[contenteditable=true]:focus, 103 | div.jsoneditor-value[contenteditable=true]:hover, 104 | div.jsoneditor-field.jsoneditor-highlight, 105 | div.jsoneditor-value.jsoneditor-highlight { 106 | background-color: #FFFFAB; 107 | border: 1px solid yellow; 108 | border-radius: 2px; 109 | } 110 | 111 | div.jsoneditor-field.jsoneditor-highlight-active, 112 | div.jsoneditor-field.jsoneditor-highlight-active:focus, 113 | div.jsoneditor-field.jsoneditor-highlight-active:hover, 114 | div.jsoneditor-value.jsoneditor-highlight-active, 115 | div.jsoneditor-value.jsoneditor-highlight-active:focus, 116 | div.jsoneditor-value.jsoneditor-highlight-active:hover { 117 | background-color: #ffee00; 118 | border: 1px solid #ffc700; 119 | border-radius: 2px; 120 | } 121 | 122 | div.jsoneditor-value.jsoneditor-string { 123 | color: #008000; 124 | } 125 | 126 | div.jsoneditor-value.jsoneditor-object, 127 | div.jsoneditor-value.jsoneditor-array { 128 | min-width: 16px; 129 | color: #808080; 130 | } 131 | 132 | div.jsoneditor-value.jsoneditor-number { 133 | color: #ee422e; 134 | } 135 | 136 | div.jsoneditor-value.jsoneditor-boolean { 137 | color: #ff8c00; 138 | } 139 | 140 | div.jsoneditor-value.jsoneditor-null { 141 | color: #004ED0; 142 | } 143 | 144 | div.jsoneditor-value.jsoneditor-invalid { 145 | color: #000000; 146 | } 147 | 148 | div.jsoneditor-tree button { 149 | width: 24px; 150 | height: 24px; 151 | padding: 0; 152 | margin: 0; 153 | border: none; 154 | cursor: pointer; 155 | background: transparent url("img/jsoneditor-icons.svg"); 156 | } 157 | 158 | div.jsoneditor-mode-view tr.jsoneditor-expandable td.jsoneditor-tree, 159 | div.jsoneditor-mode-form tr.jsoneditor-expandable td.jsoneditor-tree { 160 | cursor: pointer; 161 | } 162 | 163 | div.jsoneditor-tree button.jsoneditor-collapsed { 164 | background-position: 0 -48px; 165 | } 166 | 167 | div.jsoneditor-tree button.jsoneditor-expanded { 168 | background-position: 0 -72px; 169 | } 170 | 171 | div.jsoneditor-tree button.jsoneditor-contextmenu { 172 | background-position: -48px -72px; 173 | } 174 | 175 | div.jsoneditor-tree button.jsoneditor-contextmenu:hover, 176 | div.jsoneditor-tree button.jsoneditor-contextmenu:focus, 177 | div.jsoneditor-tree button.jsoneditor-contextmenu.jsoneditor-selected, 178 | tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu { 179 | background-position: -48px -48px; 180 | } 181 | 182 | div.jsoneditor-tree *:focus { 183 | outline: none; 184 | } 185 | 186 | div.jsoneditor-tree button:focus { 187 | /* TODO: nice outline for buttons with focus 188 | outline: #97B0F8 solid 2px; 189 | box-shadow: 0 0 8px #97B0F8; 190 | */ 191 | background-color: #f5f5f5; 192 | outline: #e5e5e5 solid 1px; 193 | } 194 | 195 | div.jsoneditor-tree button.jsoneditor-invisible { 196 | visibility: hidden; 197 | background: none; 198 | } 199 | 200 | div.jsoneditor { 201 | color: #1A1A1A; 202 | border: 1px solid #3883fa; 203 | -moz-box-sizing: border-box; 204 | -webkit-box-sizing: border-box; 205 | box-sizing: border-box; 206 | width: 100%; 207 | height: 100%; 208 | overflow: hidden; 209 | position: relative; 210 | padding: 0; 211 | line-height: 100%; 212 | } 213 | 214 | div.jsoneditor-tree table.jsoneditor-tree { 215 | border-collapse: collapse; 216 | border-spacing: 0; 217 | width: 100%; 218 | margin: 0; 219 | } 220 | 221 | div.jsoneditor-outer { 222 | position: static; 223 | width: 100%; 224 | height: 100%; 225 | margin: -35px 0 0 0; 226 | padding: 35px 0 0 0; 227 | -moz-box-sizing: border-box; 228 | -webkit-box-sizing: border-box; 229 | box-sizing: border-box; 230 | } 231 | 232 | textarea.jsoneditor-text, 233 | .ace-jsoneditor { 234 | min-height: 150px; 235 | } 236 | 237 | div.jsoneditor-tree { 238 | width: 100%; 239 | height: 100%; 240 | position: relative; 241 | overflow: auto; 242 | } 243 | 244 | textarea.jsoneditor-text { 245 | width: 100%; 246 | height: 100%; 247 | margin: 0; 248 | -moz-box-sizing: border-box; 249 | -webkit-box-sizing: border-box; 250 | box-sizing: border-box; 251 | outline-width: 0; 252 | border: none; 253 | background-color: white; 254 | resize: none; 255 | } 256 | 257 | tr.jsoneditor-highlight, 258 | tr.jsoneditor-selected { 259 | background-color: #e6e6e6; 260 | } 261 | 262 | tr.jsoneditor-selected button.jsoneditor-dragarea, 263 | tr.jsoneditor-selected button.jsoneditor-contextmenu { 264 | visibility: hidden; 265 | } 266 | 267 | tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea, 268 | tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu { 269 | visibility: visible; 270 | } 271 | 272 | div.jsoneditor-tree button.jsoneditor-dragarea { 273 | background: url("img/jsoneditor-icons.svg") -72px -72px; 274 | cursor: move; 275 | } 276 | 277 | div.jsoneditor-tree button.jsoneditor-dragarea:hover, 278 | div.jsoneditor-tree button.jsoneditor-dragarea:focus, 279 | tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea { 280 | background-position: -72px -48px; 281 | } 282 | 283 | div.jsoneditor tr, 284 | div.jsoneditor th, 285 | div.jsoneditor td { 286 | padding: 0; 287 | margin: 0; 288 | } 289 | 290 | div.jsoneditor td { 291 | vertical-align: top; 292 | } 293 | 294 | div.jsoneditor td.jsoneditor-tree { 295 | vertical-align: top; 296 | } 297 | 298 | div.jsoneditor-field, 299 | div.jsoneditor-value, 300 | div.jsoneditor td, 301 | div.jsoneditor th, 302 | div.jsoneditor textarea, 303 | .jsoneditor-schema-error { 304 | font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif; 305 | font-size: 10pt; 306 | color: #1A1A1A; 307 | } 308 | 309 | /* popover */ 310 | 311 | .jsoneditor-schema-error { 312 | cursor: default; 313 | display: inline-block; 314 | /*font-family: arial, sans-serif;*/ 315 | height: 24px; 316 | line-height: 24px; 317 | position: relative; 318 | text-align: center; 319 | width: 24px; 320 | } 321 | 322 | div.jsoneditor-tree .jsoneditor-schema-error { 323 | width: 24px; 324 | height: 24px; 325 | padding: 0; 326 | margin: 0 4px 0 0; 327 | background: url("img/jsoneditor-icons.svg") -168px -48px; 328 | } 329 | 330 | .jsoneditor-schema-error .jsoneditor-popover { 331 | background-color: #4c4c4c; 332 | border-radius: 3px; 333 | box-shadow: 0 0 5px rgba(0,0,0,0.4); 334 | color: #fff; 335 | display: none; 336 | padding: 7px 10px; 337 | position: absolute; 338 | width: 200px; 339 | z-index: 4; 340 | } 341 | 342 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-above { 343 | bottom: 32px; 344 | left: -98px; 345 | } 346 | 347 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-below { 348 | top: 32px; 349 | left: -98px; 350 | } 351 | 352 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-left { 353 | top: -7px; 354 | right: 32px; 355 | } 356 | 357 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-right { 358 | top: -7px; 359 | left: 32px; 360 | } 361 | 362 | .jsoneditor-schema-error .jsoneditor-popover:before { 363 | border-right: 7px solid transparent; 364 | border-left: 7px solid transparent; 365 | content: ''; 366 | display: block; 367 | left: 50%; 368 | margin-left: -7px; 369 | position: absolute; 370 | } 371 | 372 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-above:before { 373 | border-top: 7px solid #4c4c4c; 374 | bottom: -7px; 375 | } 376 | 377 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-below:before { 378 | border-bottom: 7px solid #4c4c4c; 379 | top: -7px; 380 | } 381 | 382 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-left:before { 383 | border-left: 7px solid #4c4c4c; 384 | border-top: 7px solid transparent; 385 | border-bottom: 7px solid transparent; 386 | content: ''; 387 | top: 19px; 388 | right: -14px; 389 | left: inherit; 390 | margin-left: inherit; 391 | margin-top: -7px; 392 | position: absolute; 393 | } 394 | 395 | .jsoneditor-schema-error .jsoneditor-popover.jsoneditor-right:before { 396 | border-right: 7px solid #4c4c4c; 397 | border-top: 7px solid transparent; 398 | border-bottom: 7px solid transparent; 399 | content: ''; 400 | top: 19px; 401 | left: -14px; 402 | margin-left: inherit; 403 | margin-top: -7px; 404 | position: absolute; 405 | } 406 | 407 | .jsoneditor-schema-error:hover .jsoneditor-popover, 408 | .jsoneditor-schema-error:focus .jsoneditor-popover { 409 | display: block; 410 | -webkit-animation: fade-in .3s linear 1, move-up .3s linear 1; 411 | -moz-animation: fade-in .3s linear 1, move-up .3s linear 1; 412 | -ms-animation: fade-in .3s linear 1, move-up .3s linear 1; 413 | } 414 | 415 | @-webkit-keyframes fade-in { 416 | from { 417 | opacity: 0; 418 | } 419 | 420 | to { 421 | opacity: 1; 422 | } 423 | } 424 | 425 | @-moz-keyframes fade-in { 426 | from { 427 | opacity: 0; 428 | } 429 | 430 | to { 431 | opacity: 1; 432 | } 433 | } 434 | 435 | @-ms-keyframes fade-in { 436 | from { 437 | opacity: 0; 438 | } 439 | 440 | to { 441 | opacity: 1; 442 | } 443 | } 444 | 445 | /*@-webkit-keyframes move-up {*/ 446 | 447 | /*from { bottom: 24px; }*/ 448 | 449 | /*to { bottom: 32px; }*/ 450 | 451 | /*}*/ 452 | 453 | /*@-moz-keyframes move-up {*/ 454 | 455 | /*from { bottom: 24px; }*/ 456 | 457 | /*to { bottom: 32px; }*/ 458 | 459 | /*}*/ 460 | 461 | /*@-ms-keyframes move-up {*/ 462 | 463 | /*from { bottom: 24px; }*/ 464 | 465 | /*to { bottom: 32px; }*/ 466 | 467 | /*}*/ 468 | 469 | /* JSON schema errors displayed at the bottom of the editor in mode text and code */ 470 | 471 | .jsoneditor .jsoneditor-text-errors { 472 | width: 100%; 473 | border-collapse: collapse; 474 | background-color: #ffef8b; 475 | border-top: 1px solid #ffd700; 476 | } 477 | 478 | .jsoneditor .jsoneditor-text-errors td { 479 | padding: 3px 6px; 480 | vertical-align: middle; 481 | } 482 | 483 | .jsoneditor-text-errors .jsoneditor-schema-error { 484 | border: none; 485 | width: 24px; 486 | height: 24px; 487 | padding: 0; 488 | margin: 0 4px 0 0; 489 | background: url("img/jsoneditor-icons.svg") -168px -48px; 490 | } 491 | /* ContextMenu - main menu */ 492 | 493 | div.jsoneditor-contextmenu-root { 494 | position: relative; 495 | width: 0; 496 | height: 0; 497 | } 498 | 499 | div.jsoneditor-contextmenu { 500 | position: absolute; 501 | box-sizing: content-box; 502 | z-index: 99999; 503 | } 504 | 505 | div.jsoneditor-contextmenu ul, 506 | div.jsoneditor-contextmenu li { 507 | box-sizing: content-box; 508 | } 509 | 510 | div.jsoneditor-contextmenu ul { 511 | position: relative; 512 | left: 0; 513 | top: 0; 514 | width: 124px; 515 | background: white; 516 | border: 1px solid #d3d3d3; 517 | box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3); 518 | list-style: none; 519 | margin: 0; 520 | padding: 0; 521 | } 522 | 523 | div.jsoneditor-contextmenu ul li button { 524 | padding: 0; 525 | margin: 0; 526 | width: 124px; 527 | height: 24px; 528 | border: none; 529 | cursor: pointer; 530 | color: #4d4d4d; 531 | background: transparent; 532 | font-size: 10pt; 533 | font-family: arial, sans-serif; 534 | box-sizing: border-box; 535 | line-height: 26px; 536 | text-align: left; 537 | } 538 | 539 | /* Fix button padding in firefox */ 540 | 541 | div.jsoneditor-contextmenu ul li button::-moz-focus-inner { 542 | padding: 0; 543 | border: 0; 544 | } 545 | 546 | div.jsoneditor-contextmenu ul li button:hover, 547 | div.jsoneditor-contextmenu ul li button:focus { 548 | color: #1a1a1a; 549 | background-color: #f5f5f5; 550 | outline: none; 551 | } 552 | 553 | div.jsoneditor-contextmenu ul li button.jsoneditor-default { 554 | width: 92px; 555 | } 556 | 557 | div.jsoneditor-contextmenu ul li button.jsoneditor-expand { 558 | float: right; 559 | width: 32px; 560 | height: 24px; 561 | border-left: 1px solid #e5e5e5; 562 | } 563 | 564 | div.jsoneditor-contextmenu div.jsoneditor-icon { 565 | float: left; 566 | width: 24px; 567 | height: 24px; 568 | border: none; 569 | padding: 0; 570 | margin: 0; 571 | background-image: url("img/jsoneditor-icons.svg"); 572 | } 573 | 574 | div.jsoneditor-contextmenu ul li button div.jsoneditor-expand { 575 | float: right; 576 | width: 24px; 577 | height: 24px; 578 | padding: 0; 579 | margin: 0 4px 0 0; 580 | background: url("img/jsoneditor-icons.svg") 0 -72px; 581 | opacity: 0.4; 582 | } 583 | 584 | div.jsoneditor-contextmenu ul li button:hover div.jsoneditor-expand, 585 | div.jsoneditor-contextmenu ul li button:focus div.jsoneditor-expand, 586 | div.jsoneditor-contextmenu ul li.jsoneditor-selected div.jsoneditor-expand, 587 | div.jsoneditor-contextmenu ul li button.jsoneditor-expand:hover div.jsoneditor-expand, 588 | div.jsoneditor-contextmenu ul li button.jsoneditor-expand:focus div.jsoneditor-expand { 589 | opacity: 1; 590 | } 591 | 592 | div.jsoneditor-contextmenu div.jsoneditor-separator { 593 | height: 0; 594 | border-top: 1px solid #e5e5e5; 595 | padding-top: 5px; 596 | margin-top: 5px; 597 | } 598 | 599 | div.jsoneditor-contextmenu button.jsoneditor-remove > div.jsoneditor-icon { 600 | background-position: -24px -24px; 601 | } 602 | 603 | div.jsoneditor-contextmenu button.jsoneditor-remove:hover > div.jsoneditor-icon, 604 | div.jsoneditor-contextmenu button.jsoneditor-remove:focus > div.jsoneditor-icon { 605 | background-position: -24px 0; 606 | } 607 | 608 | div.jsoneditor-contextmenu button.jsoneditor-append > div.jsoneditor-icon { 609 | background-position: 0 -24px; 610 | } 611 | 612 | div.jsoneditor-contextmenu button.jsoneditor-append:hover > div.jsoneditor-icon, 613 | div.jsoneditor-contextmenu button.jsoneditor-append:focus > div.jsoneditor-icon { 614 | background-position: 0 0; 615 | } 616 | 617 | div.jsoneditor-contextmenu button.jsoneditor-insert > div.jsoneditor-icon { 618 | background-position: 0 -24px; 619 | } 620 | 621 | div.jsoneditor-contextmenu button.jsoneditor-insert:hover > div.jsoneditor-icon, 622 | div.jsoneditor-contextmenu button.jsoneditor-insert:focus > div.jsoneditor-icon { 623 | background-position: 0 0; 624 | } 625 | 626 | div.jsoneditor-contextmenu button.jsoneditor-duplicate > div.jsoneditor-icon { 627 | background-position: -48px -24px; 628 | } 629 | 630 | div.jsoneditor-contextmenu button.jsoneditor-duplicate:hover > div.jsoneditor-icon, 631 | div.jsoneditor-contextmenu button.jsoneditor-duplicate:focus > div.jsoneditor-icon { 632 | background-position: -48px 0; 633 | } 634 | 635 | div.jsoneditor-contextmenu button.jsoneditor-sort-asc > div.jsoneditor-icon { 636 | background-position: -168px -24px; 637 | } 638 | 639 | div.jsoneditor-contextmenu button.jsoneditor-sort-asc:hover > div.jsoneditor-icon, 640 | div.jsoneditor-contextmenu button.jsoneditor-sort-asc:focus > div.jsoneditor-icon { 641 | background-position: -168px 0; 642 | } 643 | 644 | div.jsoneditor-contextmenu button.jsoneditor-sort-desc > div.jsoneditor-icon { 645 | background-position: -192px -24px; 646 | } 647 | 648 | div.jsoneditor-contextmenu button.jsoneditor-sort-desc:hover > div.jsoneditor-icon, 649 | div.jsoneditor-contextmenu button.jsoneditor-sort-desc:focus > div.jsoneditor-icon { 650 | background-position: -192px 0; 651 | } 652 | 653 | /* ContextMenu - sub menu */ 654 | 655 | div.jsoneditor-contextmenu ul li button.jsoneditor-selected, 656 | div.jsoneditor-contextmenu ul li button.jsoneditor-selected:hover, 657 | div.jsoneditor-contextmenu ul li button.jsoneditor-selected:focus { 658 | color: white; 659 | background-color: #ee422e; 660 | } 661 | 662 | div.jsoneditor-contextmenu ul li { 663 | overflow: hidden; 664 | } 665 | 666 | div.jsoneditor-contextmenu ul li ul { 667 | display: none; 668 | position: relative; 669 | left: -10px; 670 | top: 0; 671 | border: none; 672 | box-shadow: inset 0 0 10px rgba(128, 128, 128, 0.5); 673 | padding: 0 10px; 674 | /* TODO: transition is not supported on IE8-9 */ 675 | -webkit-transition: all 0.3s ease-out; 676 | -moz-transition: all 0.3s ease-out; 677 | -o-transition: all 0.3s ease-out; 678 | transition: all 0.3s ease-out; 679 | } 680 | 681 | 682 | 683 | div.jsoneditor-contextmenu ul li ul li button { 684 | padding-left: 24px; 685 | animation: all ease-in-out 1s; 686 | } 687 | 688 | div.jsoneditor-contextmenu ul li ul li button:hover, 689 | div.jsoneditor-contextmenu ul li ul li button:focus { 690 | background-color: #f5f5f5; 691 | } 692 | 693 | div.jsoneditor-contextmenu button.jsoneditor-type-string > div.jsoneditor-icon { 694 | background-position: -144px -24px; 695 | } 696 | 697 | div.jsoneditor-contextmenu button.jsoneditor-type-string:hover > div.jsoneditor-icon, 698 | div.jsoneditor-contextmenu button.jsoneditor-type-string:focus > div.jsoneditor-icon, 699 | div.jsoneditor-contextmenu button.jsoneditor-type-string.jsoneditor-selected > div.jsoneditor-icon { 700 | background-position: -144px 0; 701 | } 702 | 703 | div.jsoneditor-contextmenu button.jsoneditor-type-auto > div.jsoneditor-icon { 704 | background-position: -120px -24px; 705 | } 706 | 707 | div.jsoneditor-contextmenu button.jsoneditor-type-auto:hover > div.jsoneditor-icon, 708 | div.jsoneditor-contextmenu button.jsoneditor-type-auto:focus > div.jsoneditor-icon, 709 | div.jsoneditor-contextmenu button.jsoneditor-type-auto.jsoneditor-selected > div.jsoneditor-icon { 710 | background-position: -120px 0; 711 | } 712 | 713 | div.jsoneditor-contextmenu button.jsoneditor-type-object > div.jsoneditor-icon { 714 | background-position: -72px -24px; 715 | } 716 | 717 | div.jsoneditor-contextmenu button.jsoneditor-type-object:hover > div.jsoneditor-icon, 718 | div.jsoneditor-contextmenu button.jsoneditor-type-object:focus > div.jsoneditor-icon, 719 | div.jsoneditor-contextmenu button.jsoneditor-type-object.jsoneditor-selected > div.jsoneditor-icon { 720 | background-position: -72px 0; 721 | } 722 | 723 | div.jsoneditor-contextmenu button.jsoneditor-type-array > div.jsoneditor-icon { 724 | background-position: -96px -24px; 725 | } 726 | 727 | div.jsoneditor-contextmenu button.jsoneditor-type-array:hover > div.jsoneditor-icon, 728 | div.jsoneditor-contextmenu button.jsoneditor-type-array:focus > div.jsoneditor-icon, 729 | div.jsoneditor-contextmenu button.jsoneditor-type-array.jsoneditor-selected > div.jsoneditor-icon { 730 | background-position: -96px 0; 731 | } 732 | 733 | div.jsoneditor-contextmenu button.jsoneditor-type-modes > div.jsoneditor-icon { 734 | background-image: none; 735 | width: 6px; 736 | } 737 | div.jsoneditor-menu { 738 | width: 100%; 739 | height: 35px; 740 | padding: 2px; 741 | margin: 0; 742 | -moz-box-sizing: border-box; 743 | -webkit-box-sizing: border-box; 744 | box-sizing: border-box; 745 | color: white; 746 | background-color: #CCCCCC; 747 | border-bottom: 1px solid #CCCCCC; 748 | } 749 | 750 | div.jsoneditor-menu > button, 751 | div.jsoneditor-menu > div.jsoneditor-modes > button { 752 | width: 26px; 753 | height: 26px; 754 | margin: 2px; 755 | padding: 0; 756 | border-radius: 2px; 757 | border: 1px solid transparent; 758 | background: transparent url("img/jsoneditor-icons.svg"); 759 | color: white; 760 | opacity: 0.8; 761 | font-family: arial, sans-serif; 762 | font-size: 10pt; 763 | float: left; 764 | } 765 | 766 | div.jsoneditor-menu > button:hover, 767 | div.jsoneditor-menu > div.jsoneditor-modes > button:hover { 768 | background-color: rgba(255,255,255,0.2); 769 | border: 1px solid rgba(255,255,255,0.4); 770 | } 771 | 772 | div.jsoneditor-menu > button:focus, 773 | div.jsoneditor-menu > button:active, 774 | div.jsoneditor-menu > div.jsoneditor-modes > button:focus, 775 | div.jsoneditor-menu > div.jsoneditor-modes > button:active { 776 | background-color: rgba(255,255,255,0.3); 777 | } 778 | 779 | div.jsoneditor-menu > button:disabled, 780 | div.jsoneditor-menu > div.jsoneditor-modes > button:disabled { 781 | opacity: 0.5; 782 | } 783 | 784 | div.jsoneditor-menu > button.jsoneditor-collapse-all { 785 | background-position: 0 -96px; 786 | } 787 | 788 | div.jsoneditor-menu > button.jsoneditor-expand-all { 789 | background-position: 0 -120px; 790 | } 791 | 792 | div.jsoneditor-menu > button.jsoneditor-undo { 793 | background-position: -24px -96px; 794 | } 795 | 796 | div.jsoneditor-menu > button.jsoneditor-undo:disabled { 797 | background-position: -24px -120px; 798 | } 799 | 800 | div.jsoneditor-menu > button.jsoneditor-redo { 801 | background-position: -48px -96px; 802 | } 803 | 804 | div.jsoneditor-menu > button.jsoneditor-redo:disabled { 805 | background-position: -48px -120px; 806 | } 807 | 808 | div.jsoneditor-menu > button.jsoneditor-compact { 809 | background-position: -72px -96px; 810 | } 811 | 812 | div.jsoneditor-menu > button.jsoneditor-format { 813 | background-position: -72px -120px; 814 | } 815 | 816 | div.jsoneditor-menu > div.jsoneditor-modes { 817 | display: inline-block; 818 | float: left; 819 | } 820 | 821 | div.jsoneditor-menu > div.jsoneditor-modes > button { 822 | background-image: none; 823 | width: auto; 824 | padding-left: 6px; 825 | padding-right: 6px; 826 | } 827 | 828 | div.jsoneditor-menu > button.jsoneditor-separator, 829 | div.jsoneditor-menu > div.jsoneditor-modes > button.jsoneditor-separator { 830 | margin-left: 10px; 831 | } 832 | 833 | div.jsoneditor-menu a { 834 | font-family: arial, sans-serif; 835 | font-size: 10pt; 836 | color: white; 837 | opacity: 0.8; 838 | vertical-align: middle; 839 | } 840 | 841 | div.jsoneditor-menu a:hover { 842 | opacity: 1; 843 | } 844 | 845 | div.jsoneditor-menu a.jsoneditor-poweredBy { 846 | font-size: 8pt; 847 | position: absolute; 848 | right: 0; 849 | top: 0; 850 | padding: 10px; 851 | } 852 | table.jsoneditor-search input, 853 | table.jsoneditor-search div.jsoneditor-results { 854 | font-family: arial, sans-serif; 855 | font-size: 10pt; 856 | color: #1A1A1A; 857 | background: transparent; 858 | /* For Firefox */ 859 | } 860 | 861 | table.jsoneditor-search div.jsoneditor-results { 862 | color: white; 863 | padding-right: 5px; 864 | line-height: 24px; 865 | } 866 | 867 | table.jsoneditor-search { 868 | position: absolute; 869 | right: 4px; 870 | top: 4px; 871 | border-collapse: collapse; 872 | border-spacing: 0; 873 | } 874 | 875 | table.jsoneditor-search div.jsoneditor-frame { 876 | border: 1px solid transparent; 877 | background-color: white; 878 | padding: 0 2px; 879 | margin: 0; 880 | } 881 | 882 | table.jsoneditor-search div.jsoneditor-frame table { 883 | border-collapse: collapse; 884 | } 885 | 886 | table.jsoneditor-search input { 887 | width: 120px; 888 | border: none; 889 | outline: none; 890 | margin: 1px; 891 | line-height: 20px; 892 | } 893 | 894 | table.jsoneditor-search button { 895 | width: 16px; 896 | height: 24px; 897 | padding: 0; 898 | margin: 0; 899 | border: none; 900 | background: url("img/jsoneditor-icons.svg"); 901 | vertical-align: top; 902 | } 903 | 904 | table.jsoneditor-search button:hover { 905 | background-color: transparent; 906 | } 907 | 908 | table.jsoneditor-search button.jsoneditor-refresh { 909 | width: 18px; 910 | background-position: -99px -73px; 911 | } 912 | 913 | table.jsoneditor-search button.jsoneditor-next { 914 | cursor: pointer; 915 | background-position: -124px -73px; 916 | } 917 | 918 | table.jsoneditor-search button.jsoneditor-next:hover { 919 | background-position: -124px -49px; 920 | } 921 | 922 | table.jsoneditor-search button.jsoneditor-previous { 923 | cursor: pointer; 924 | background-position: -148px -73px; 925 | margin-right: 2px; 926 | } 927 | 928 | table.jsoneditor-search button.jsoneditor-previous:hover { 929 | background-position: -148px -49px; 930 | } -------------------------------------------------------------------------------- /behaviortree-editor/panel/img/jsoneditor-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | JSON Editor Icons 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | JSON Editor Icons 27 | 28 | 29 | 30 | 32 | 56 | 60 | 61 | 62 | 64 | 71 | 78 | 85 | 92 | 99 | 102 | 109 | 116 | 117 | 121 | 128 | 135 | 136 | 143 | 150 | 157 | 159 | 166 | 173 | 180 | 181 | 184 | 191 | 198 | 205 | 206 | 213 | 219 | 225 | 232 | 237 | 242 | 249 | 255 | 260 | 267 | 273 | 279 | 280 | 287 | 294 | 301 | 308 | 315 | 319 | 326 | 333 | 334 | 338 | 345 | 352 | 353 | 360 | 367 | 374 | 377 | 384 | 391 | 398 | 399 | 402 | 409 | 416 | 423 | 424 | 431 | 437 | 443 | 450 | 455 | 460 | 467 | 473 | 478 | 485 | 491 | 497 | 504 | 511 | 518 | 525 | 532 | 539 | 546 | 552 | 560 | 566 | 572 | 579 | 587 | 595 | 602 | 609 | 616 | 623 | 630 | 637 | 644 | 651 | 657 | 665 | 671 | 677 | 684 | 692 | 700 | 707 | 714 | 721 | 728 | 735 | 742 | 749 | 756 | 761 | 766 | 771 | 777 | 783 | 788 | 793 | 798 | 803 | 808 | 824 | 841 | 858 | 875 | 881 | 887 | 893 | 894 | -------------------------------------------------------------------------------- /behaviortree-editor/b3core.0.1.0module.js: -------------------------------------------------------------------------------- 1 | /** 2 | * b3 3 | * 4 | * Copyright (c) 2014 Renato de Pontes Pereira. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to 8 | * deal in the Software without restriction, including without limitation the 9 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | * sell copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | * IN THE SOFTWARE. 23 | **/ 24 | 25 | //this.b3 = this.b3 || {}; 26 | let b3 = {}; 27 | 28 | /** 29 | * Behavior3JS 30 | * =========== 31 | * 32 | * * * * 33 | * 34 | * **Behavior3JS** is a Behavior Tree library written in JavaScript. It 35 | * provides structures and algorithms that assist you in the task of creating 36 | * intelligent agents for your game or application. Check it out some features 37 | * of Behavior3JS: 38 | * 39 | * - Based on the work of (Marzinotto et al., 2014), in which they propose a 40 | * **formal**, **consistent** and **general** definition of Behavior Trees; 41 | * - **Optimized to control multiple agents**: you can use a single behavior 42 | * tree instance to handle hundreds of agents; 43 | * - It was **designed to load and save trees in a JSON format**, in order to 44 | * use, edit and test it in multiple environments, tools and languages; 45 | * - A **cool visual editor** which you can access online; 46 | * - Several **composite, decorator and action nodes** available within the 47 | * library. You still can define your own nodes, including composites and 48 | * decorators; 49 | * - **Completely free**, the core module and the visual editor are all published 50 | * under the MIT License, which means that you can use them for your open source 51 | * and commercial projects; 52 | * - **Lightweight**, only 11.5KB! 53 | * 54 | * Visit http://behavior3js.guineashots.com to know more! 55 | * 56 | * 57 | * Core Classes and Functions 58 | * -------------------------- 59 | * 60 | * This library include the following core structures... 61 | * 62 | * **Public:** 63 | * 64 | * - **BehaviorTree**: the structure that represents a Behavior Tree; 65 | * - **Blackboard**: represents a "memory" in an agent and is required to to 66 | * run a `BehaviorTree`; 67 | * - **Composite**: base class for all composite nodes; 68 | * - **Decorator**: base class for all decorator nodes; 69 | * - **Action**: base class for all action nodes; 70 | * - **Condition**: base class for all condition nodes; 71 | * 72 | * **Internal:** 73 | * 74 | * 75 | * - **Tick**: used as container and tracking object through the tree during 76 | * the tick signal; 77 | * - **BaseNode**: the base class that provide all common node features; 78 | * 79 | * *Some classes are used internally on Behavior3JS, but you may need to access 80 | * its functionalities eventually, specially the `Tick` object.* 81 | * 82 | * 83 | * Nodes Included 84 | * -------------- 85 | * 86 | * **Composite Nodes**: 87 | * 88 | * - Sequence; 89 | * - Priority; 90 | * - MemSequence; 91 | * - MemPriority; 92 | * 93 | * 94 | * **Decorators**: 95 | * 96 | * - Inverter; 97 | * - Limiter 98 | * - MaxTime; 99 | * - Repeater; 100 | * - RepeaterUntilFailure; 101 | * - RepeaterUntilSuccess; 102 | * 103 | * 104 | * **Actions**: 105 | * 106 | * - Succeeder; 107 | * - Failer; 108 | * - Error; 109 | * - Runner; 110 | * - Wait. 111 | * 112 | * @module Behavior3JS 113 | * @main Behavior3JS 114 | **/ 115 | 116 | (function() { 117 | "use strict"; 118 | 119 | /** 120 | * List of all constants in Behavior3JS. 121 | * 122 | * @class Constants 123 | **/ 124 | 125 | /** 126 | * Version of the library. 127 | * 128 | * @property VERSION 129 | * @type {String} 130 | */ 131 | b3.VERSION = '0.1.0'; 132 | 133 | /** 134 | * Returned when a criterion has been met by a condition node or an action node 135 | * has been completed successfully. 136 | * 137 | * @property SUCCESS 138 | * @type {Integer} 139 | */ 140 | b3.SUCCESS = 1; 141 | 142 | /** 143 | * Returned when a criterion has not been met by a condition node or an action 144 | * node could not finish its execution for any reason. 145 | * 146 | * @property FAILURE 147 | * @type {Integer} 148 | */ 149 | b3.FAILURE = 2; 150 | 151 | /** 152 | * Returned when an action node has been initialized but is still waiting the 153 | * its resolution. 154 | * 155 | * @property FAILURE 156 | * @type {Integer} 157 | */ 158 | b3.RUNNING = 3; 159 | 160 | /** 161 | * Returned when some unexpected error happened in the tree, probably by a 162 | * programming error (trying to verify an undefined variable). Its use depends 163 | * on the final implementation of the leaf nodes. 164 | * 165 | * @property ERROR 166 | * @type {Integer} 167 | */ 168 | b3.ERROR = 4; 169 | 170 | 171 | /** 172 | * Describes the node category as Composite. 173 | * 174 | * @property COMPOSITE 175 | * @type {String} 176 | */ 177 | b3.COMPOSITE = 'composite'; 178 | 179 | /** 180 | * Describes the node category as Decorator. 181 | * 182 | * @property DECORATOR 183 | * @type {String} 184 | */ 185 | b3.DECORATOR = 'decorator'; 186 | 187 | /** 188 | * Describes the node category as Action. 189 | * 190 | * @property ACTION 191 | * @type {String} 192 | */ 193 | b3.ACTION = 'action'; 194 | 195 | /** 196 | * Describes the node category as Condition. 197 | * 198 | * @property CONDITION 199 | * @type {String} 200 | */ 201 | b3.CONDITION = 'condition'; 202 | 203 | 204 | /** 205 | * List of internal and helper functions in Behavior3JS. 206 | * 207 | * @class Utils 208 | **/ 209 | 210 | 211 | /** 212 | * This function is used to create unique IDs for trees and nodes. 213 | * 214 | * (consult http://www.ietf.org/rfc/rfc4122.txt). 215 | * 216 | * @method createUUID 217 | * @return {String} A unique ID. 218 | **/ 219 | b3.createUUID = function() { 220 | var s = []; 221 | var hexDigits = "0123456789abcdef"; 222 | for (var i = 0; i < 36; i++) { 223 | s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); 224 | } 225 | // bits 12-15 of the time_hi_and_version field to 0010 226 | s[14] = "4"; 227 | 228 | // bits 6-7 of the clock_seq_hi_and_reserved to 01 229 | s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); 230 | 231 | s[8] = s[13] = s[18] = s[23] = "-"; 232 | 233 | var uuid = s.join(""); 234 | return uuid; 235 | } 236 | 237 | /** 238 | * Class is a meta-factory function to create classes in JavaScript. It is a 239 | * shortcut for the CreateJS syntax style. By default, the class created by 240 | * this function have an initialize function (the constructor). Optionally, you 241 | * can specify the inheritance by passing another class as parameter. 242 | * 243 | * By default, all classes created using this function, may receives only a 244 | * settings parameter as argument. This pattern is commonly used by jQuery and 245 | * its plugins. 246 | * 247 | * Usage 248 | * ----- 249 | * 250 | * // Creating a simple class 251 | * var BaseClass = b3.Class(); 252 | * 253 | * // Using inheritance 254 | * var ChildClass = b3.Class(BaseClass); 255 | * 256 | * // Defining the constructor 257 | * ChildClass.prototype.initialize = function(settings) { ... } 258 | * 259 | * @method Class 260 | * @param {Object} [baseClass] The super class. 261 | * @return {Object} A new class. 262 | **/ 263 | b3.Class = function(baseClass) { 264 | // create a new class 265 | var cls = function(params) { 266 | this.initialize(params); 267 | } 268 | 269 | // if base class is provided, inherit 270 | if (baseClass) { 271 | cls.prototype = new baseClass(); 272 | cls.prototype.constructor = cls; 273 | } 274 | 275 | // create initialize if does not exist on baseClass 276 | cls.prototype.initialize = cls.prototype.initialize || function() {}; 277 | 278 | return cls; 279 | } 280 | 281 | })();/** 282 | * Blackboard 283 | * 284 | * Copyright (c) 2014 Renato de Pontes Pereira. 285 | * 286 | * Permission is hereby granted, free of charge, to any person obtaining a copy 287 | * of this software and associated documentation files (the "Software"), to 288 | * deal in the Software without restriction, including without limitation the 289 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 290 | * sell copies of the Software, and to permit persons to whom the Software is 291 | * furnished to do so, subject to the following conditions: 292 | * 293 | * The above copyright notice and this permission notice shall be included in 294 | * all copies or substantial portions of the Software. 295 | * 296 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 297 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 298 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 299 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 300 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 301 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 302 | * IN THE SOFTWARE. 303 | **/ 304 | 305 | /** 306 | * @module Behavior3JS 307 | **/ 308 | 309 | // namespace: 310 | //this.b3 = this.b3 || {}; 311 | 312 | (function() { 313 | "use strict"; 314 | 315 | /** 316 | * The Blackboard is the memory structure required by `BehaviorTree` and its 317 | * nodes. It only have 2 public methods: `set` and `get`. These methods works 318 | * in 3 different contexts: global, per tree, and per node per tree. 319 | * 320 | * Suppose you have two different trees controlling a single object with a 321 | * single blackboard, then: 322 | * 323 | * - In the global context, all nodes will access the stored information. 324 | * - In per tree context, only nodes sharing the same tree share the stored 325 | * information. 326 | * - In per node per tree context, the information stored in the blackboard can 327 | * only be accessed by the same node that wrote the data. 328 | * 329 | * The context is selected indirectly by the parameters provided to these 330 | * methods, for example: 331 | * 332 | * // getting/setting variable in global context 333 | * blackboard.set('testKey', 'value'); 334 | * var value = blackboard.get('testKey'); 335 | * 336 | * // getting/setting variable in per tree context 337 | * blackboard.set('testKey', 'value', tree.id); 338 | * var value = blackboard.get('testKey', tree.id); 339 | * 340 | * // getting/setting variable in per node per tree context 341 | * blackboard.set('testKey', 'value', tree.id, node.id); 342 | * var value = blackboard.get('testKey', tree.id, node.id); 343 | * 344 | * Note: Internally, the blackboard store these memories in different objects, 345 | * being the global on `_baseMemory`, the per tree on `_treeMemory` and the 346 | * per node per tree dynamically create inside the per tree memory (it is 347 | * accessed via `_treeMemory[id].nodeMemory`). Avoid to use these variables 348 | * manually, use `get` and `set` instead. 349 | * 350 | * @class Blackboard 351 | **/ 352 | var Blackboard = b3.Class(); 353 | 354 | var p = Blackboard.prototype; 355 | 356 | /** 357 | * Initialization method. 358 | * 359 | * @method initialize 360 | * @constructor 361 | **/ 362 | p.initialize = function() { 363 | this._baseMemory = {}; 364 | this._treeMemory = {}; 365 | } 366 | 367 | /** 368 | * Internal method to retrieve the tree context memory. If the memory does 369 | * not exist, this method creates it. 370 | * 371 | * @method _getTreeMemory 372 | * @param {string} treeScope The id of the tree in scope. 373 | * @returns {Object} The tree memory. 374 | * @protected 375 | **/ 376 | p._getTreeMemory = function(treeScope) { 377 | if (!this._treeMemory[treeScope]) { 378 | this._treeMemory[treeScope] = { 379 | 'nodeMemory' : {}, 380 | 'openNodes' : [], 381 | 'traversalDepth' : 0, 382 | 'traversalCycle' : 0, 383 | }; 384 | } 385 | return this._treeMemory[treeScope]; 386 | }; 387 | 388 | /** 389 | * Internal method to retrieve the node context memory, given the tree 390 | * memory. If the memory does not exist, this method creates is. 391 | * 392 | * @method _getNodeMemory 393 | * @param {String} treeMemory the tree memory. 394 | * @param {String} nodeScope The id of the node in scope. 395 | * @returns {Object} The node memory. 396 | * @protected 397 | **/ 398 | p._getNodeMemory = function(treeMemory, nodeScope) { 399 | var memory = treeMemory['nodeMemory']; 400 | if (!memory[nodeScope]) { 401 | memory[nodeScope] = {}; 402 | } 403 | 404 | return memory[nodeScope]; 405 | }; 406 | 407 | /** 408 | * Internal method to retrieve the context memory. If treeScope and 409 | * nodeScope are provided, this method returns the per node per tree 410 | * memory. If only the treeScope is provided, it returns the per tree 411 | * memory. If no parameter is provided, it returns the global memory. 412 | * Notice that, if only nodeScope is provided, this method will still 413 | * return the global memory. 414 | * 415 | * @method _getMemory 416 | * @param {String} treeScope The id of the tree scope. 417 | * @param {String} nodeScope The id of the node scope. 418 | * @returns {Object} A memory object. 419 | * @protected 420 | **/ 421 | p._getMemory = function(treeScope, nodeScope) { 422 | var memory = this._baseMemory; 423 | 424 | if (treeScope) { 425 | memory = this._getTreeMemory(treeScope); 426 | 427 | if (nodeScope) { 428 | memory = this._getNodeMemory(memory, nodeScope); 429 | } 430 | } 431 | 432 | return memory; 433 | }; 434 | 435 | /** 436 | * Stores a value in the blackboard. If treeScope and nodeScope are 437 | * provided, this method will save the value into the per node per tree 438 | * memory. If only the treeScope is provided, it will save the value into 439 | * the per tree memory. If no parameter is provided, this method will save 440 | * the value into the global memory. Notice that, if only nodeScope is 441 | * provided (but treeScope not), this method will still save the value into 442 | * the global memory. 443 | * 444 | * @method set 445 | * @param {String} key The key to be stored. 446 | * @param {String} value The value to be stored. 447 | * @param {String} treeScope The tree id if accessing the tree or node 448 | * memory. 449 | * @param {String} nodeScope The node id if accessing the node memory. 450 | **/ 451 | p.set = function(key, value, treeScope, nodeScope) { 452 | var memory = this._getMemory(treeScope, nodeScope); 453 | memory[key] = value; 454 | }; 455 | 456 | /** 457 | * Retrieves a value in the blackboard. If treeScope and nodeScope are 458 | * provided, this method will retrieve the value from the per node per tree 459 | * memory. If only the treeScope is provided, it will retrieve the value 460 | * from the per tree memory. If no parameter is provided, this method will 461 | * retrieve from the global memory. If only nodeScope is provided (but 462 | * treeScope not), this method will still try to retrieve from the global 463 | * memory. 464 | * 465 | * @method get 466 | * @param {String} key The key to be retrieved. 467 | * @param {String} treeScope The tree id if accessing the tree or node 468 | * memory. 469 | * @param {String} nodeScope The node id if accessing the node memory. 470 | * @returns {Object} The value stored or undefined. 471 | **/ 472 | p.get = function(key, treeScope, nodeScope) { 473 | var memory = this._getMemory(treeScope, nodeScope); 474 | return memory[key]; 475 | }; 476 | 477 | b3.Blackboard = Blackboard; 478 | 479 | })();/** 480 | * Tick 481 | * 482 | * Copyright (c) 2014 Renato de Pontes Pereira. 483 | * 484 | * Permission is hereby granted, free of charge, to any person obtaining a copy 485 | * of this software and associated documentation files (the "Software"), to 486 | * deal in the Software without restriction, including without limitation the 487 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 488 | * sell copies of the Software, and to permit persons to whom the Software is 489 | * furnished to do so, subject to the following conditions: 490 | * 491 | * The above copyright notice and this permission notice shall be included in 492 | * all copies or substantial portions of the Software. 493 | * 494 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 495 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 496 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 497 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 498 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 499 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 500 | * IN THE SOFTWARE. 501 | **/ 502 | 503 | /** 504 | * @module Behavior3JS 505 | **/ 506 | 507 | // namespace: 508 | //this.b3 = this.b3 || {}; 509 | 510 | (function() { 511 | "use strict"; 512 | 513 | /** 514 | * A new Tick object is instantiated every tick by BehaviorTree. It is passed 515 | * as parameter to the nodes through the tree during the traversal. 516 | * 517 | * The role of the Tick class is to store the instances of tree, debug, target 518 | * and blackboard. So, all nodes can access these informations. 519 | * 520 | * For internal uses, the Tick also is useful to store the open node after the 521 | * tick signal, in order to let `BehaviorTree` to keep track and close them 522 | * when necessary. 523 | * 524 | * This class also makes a bridge between nodes and the debug, passing the node 525 | * state to the debug if the last is provided. 526 | * 527 | * @class Tick 528 | **/ 529 | var Tick = b3.Class(); 530 | 531 | var p = Tick.prototype; 532 | 533 | /** 534 | * The tree reference. 535 | * 536 | * @property tree 537 | * @type {b3.BehaviorTree} 538 | * @readOnly 539 | */ 540 | 541 | /** 542 | * The debug reference. 543 | * 544 | * @property debug 545 | * @type {Object} 546 | * @readOnly 547 | */ 548 | 549 | /** 550 | * The target object reference. 551 | * 552 | * @property target 553 | * @type {Object} 554 | * @readOnly 555 | */ 556 | 557 | /** 558 | * The blackboard reference. 559 | * 560 | * @property blackboard 561 | * @type {Blackboard} 562 | * @readOnly 563 | */ 564 | 565 | /** 566 | * The list of open nodes. Update during the tree traversal. 567 | * 568 | * @property _openNodes 569 | * @type {Array} 570 | * @protected 571 | * @readOnly 572 | */ 573 | 574 | /** 575 | * The number of nodes entered during the tick. Update during the tree 576 | * traversal. 577 | * 578 | * @property _nodeCount 579 | * @type {Integer} 580 | * @protected 581 | * @readOnly 582 | */ 583 | 584 | /** 585 | * Initialization method. 586 | * 587 | * @method initialize 588 | * @constructor 589 | **/ 590 | p.initialize = function() { 591 | // set by BehaviorTree 592 | this.tree = null; 593 | this.debug = null; 594 | this.target = null; 595 | this.blackboard = null; 596 | 597 | // updated during the tick signal 598 | this._openNodes = []; 599 | this._nodeCount = 0; 600 | } 601 | 602 | /** 603 | * Called when entering a node (called by BaseNode). 604 | * 605 | * @method _enterNode 606 | * @param {Object} node The node that called this method. 607 | * @protected 608 | **/ 609 | p._enterNode = function(node) { 610 | this._nodeCount++; 611 | this._openNodes.push(node); 612 | 613 | // TODO: call debug here 614 | } 615 | 616 | /** 617 | * Callback when opening a node (called by BaseNode). 618 | * 619 | * @method _openNode 620 | * @param {Object} node The node that called this method. 621 | * @protected 622 | **/ 623 | p._openNode = function(node) { 624 | // TODO: call debug here 625 | } 626 | 627 | /** 628 | * Callback when ticking a node (called by BaseNode). 629 | * 630 | * @method _tickNode 631 | * @param {Object} node The node that called this method. 632 | * @protected 633 | **/ 634 | p._tickNode = function(node) { 635 | // TODO: call debug here 636 | } 637 | 638 | /** 639 | * Callback when closing a node (called by BaseNode). 640 | * 641 | * @method _closeNode 642 | * @param {Object} node The node that called this method. 643 | * @protected 644 | **/ 645 | p._closeNode = function(node) { 646 | // TODO: call debug here 647 | this._openNodes.pop(); 648 | } 649 | 650 | /** 651 | * Callback when exiting a node (called by BaseNode). 652 | * 653 | * @method _exitNode 654 | * @param {Object} node The node that called this method. 655 | * @protected 656 | **/ 657 | p._exitNode = function(node) { 658 | // TODO: call debug here 659 | } 660 | 661 | b3.Tick = Tick; 662 | 663 | })();/** 664 | * BehaviorTree 665 | * 666 | * Copyright (c) 2014 Renato de Pontes Pereira. 667 | * 668 | * Permission is hereby granted, free of charge, to any person obtaining a copy 669 | * of this software and associated documentation files (the "Software"), to 670 | * deal in the Software without restriction, including without limitation the 671 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 672 | * sell copies of the Software, and to permit persons to whom the Software is 673 | * furnished to do so, subject to the following conditions: 674 | * 675 | * The above copyright notice and this permission notice shall be included in 676 | * all copies or substantial portions of the Software. 677 | * 678 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 679 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 680 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 681 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 682 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 683 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 684 | * IN THE SOFTWARE. 685 | **/ 686 | 687 | /** 688 | * @module Behavior3JS 689 | **/ 690 | 691 | // namespace: 692 | //this.b3 = this.b3 || {}; 693 | 694 | (function() { 695 | "use strict"; 696 | 697 | /** 698 | * The BehaviorTree class, as the name implies, represents the Behavior Tree 699 | * structure. 700 | * 701 | * There are two ways to construct a Behavior Tree: by manually setting the 702 | * root node, or by loading it from a data structure (which can be loaded from 703 | * a JSON). Both methods are shown in the examples below and better explained 704 | * in the user guide. 705 | * 706 | * The tick method must be called periodically, in order to send the tick 707 | * signal to all nodes in the tree, starting from the root. The method 708 | * `BehaviorTree.tick` receives a target object and a blackboard as parameters. 709 | * The target object can be anything: a game agent, a system, a DOM object, 710 | * etc. This target is not used by any piece of Behavior3JS, i.e., the target 711 | * object will only be used by custom nodes. 712 | * 713 | * The blackboard is obligatory and must be an instance of `Blackboard`. This 714 | * requirement is necessary due to the fact that neither `BehaviorTree` or any 715 | * node will store the execution variables in its own object (e.g., the BT does 716 | * not store the target, information about opened nodes or number of times the 717 | * tree was called). But because of this, you only need a single tree instance 718 | * to control multiple (maybe hundreds) objects. 719 | * 720 | * Manual construction of a Behavior Tree 721 | * -------------------------------------- 722 | * 723 | * var tree = new b3.BehaviorTree(); 724 | * 725 | * tree.root = new b3.Sequence({children:[ 726 | * new b3.Priority({children:[ 727 | * new MyCustomNode(), 728 | * new MyCustomNode() 729 | * ]}), 730 | * ... 731 | * ]}); 732 | * 733 | * 734 | * Loading a Behavior Tree from data structure 735 | * ------------------------------------------- 736 | * 737 | * var tree = new b3.BehaviorTree(); 738 | * 739 | * tree.load({ 740 | * 'title' : 'Behavior Tree title' 741 | * 'description' : 'My description' 742 | * 'root' : 'node-id-1' 743 | * 'nodes' : { 744 | * 'node-id-1' : { 745 | * 'name' : 'Priority', // this is the node type 746 | * 'title' : 'Root Node', 747 | * 'description' : 'Description', 748 | * 'children' : ['node-id-2', 'node-id-3'], 749 | * }, 750 | * ... 751 | * } 752 | * }) 753 | * 754 | * 755 | * @class BehaviorTree 756 | **/ 757 | var BehaviorTree = b3.Class(); 758 | 759 | var p = BehaviorTree.prototype; 760 | 761 | /** 762 | * The tree id, must be unique. By default, created with `b3.createUUID`. 763 | * 764 | * @property id 765 | * @type {String} 766 | * @readOnly 767 | */ 768 | 769 | /** 770 | * The tree title. 771 | * 772 | * @property title 773 | * @type {String} 774 | */ 775 | 776 | /** 777 | * Description of the tree. 778 | * 779 | * @property description 780 | * @type {String} 781 | */ 782 | 783 | /** 784 | * A dictionary with (key-value) properties. Useful to define custom 785 | * variables in the visual editor. 786 | * 787 | * @property properties 788 | * @type {Object} 789 | */ 790 | 791 | /** 792 | * The reference to the root node. Must be an instance of `b3.BaseNode`. 793 | * 794 | * @property root 795 | * @type {BaseNode} 796 | */ 797 | 798 | /** 799 | * The reference to the debug instance. 800 | * 801 | * @property debug 802 | * @type {Object} 803 | */ 804 | 805 | /** 806 | * Initialization method. 807 | * 808 | * @method initialize 809 | * @constructor 810 | **/ 811 | p.initialize = function() { 812 | this.id = b3.createUUID(); 813 | this.title = 'The behavior tree'; 814 | this.description = 'Default description'; 815 | this.properties = {}; 816 | this.root = null; 817 | this.debug = null; 818 | } 819 | 820 | /** 821 | * This method loads a Behavior Tree from a data structure, populating this 822 | * object with the provided data. Notice that, the data structure must 823 | * follow the format specified by Behavior3JS. Consult the guide to know 824 | * more about this format. 825 | * 826 | * You probably want to use custom nodes in your BTs, thus, you need to 827 | * provide the `names` object, in which this method can find the nodes by 828 | * `names[NODE_NAME]`. This variable can be a namespace or a dictionary, 829 | * as long as this method can find the node by its name, for example: 830 | * 831 | * //json 832 | * ... 833 | * 'node1': { 834 | * 'name': MyCustomNode, 835 | * 'title': ... 836 | * } 837 | * ... 838 | * 839 | * //code 840 | * var bt = new b3.BehaviorTree(); 841 | * bt.load(data, {'MyCustomNode':MyCustomNode}) 842 | * 843 | * 844 | * @method load 845 | * @param {Object} data The data structure representing a Behavior Tree. 846 | * @param {Object} [names] A namespace or dict containing custom nodes. 847 | **/ 848 | p.load = function(data, names) { 849 | names = names || {}; 850 | 851 | this.title = data.title || this.title; 852 | this.description = data.description || this.description; 853 | this.properties = data.properties || this.properties; 854 | 855 | var nodes = {}; 856 | // Create the node list (without connection between them) 857 | for (var id in data.nodes) { 858 | var spec = data.nodes[id]; 859 | 860 | if (spec.name in names) { 861 | // Look for the name in custom nodes 862 | var cls = names[spec.name]; 863 | } else if (spec.name in b3) { 864 | // Look for the name in default nodes 865 | var cls = b3[spec.name]; 866 | } else { 867 | // Invalid node name 868 | throw EvalError('BehaviorTree.load: Invalid node name + "'+ 869 | spec.name+'".'); 870 | } 871 | 872 | var node = new cls(spec.parameters); 873 | node.id = spec.id || node.id; 874 | node.title = spec.title || node.title; 875 | node.description = spec.description || node.description; 876 | node.properties = spec.properties || node.properties; 877 | node.parameters = spec.parameters || node.parameters; 878 | 879 | nodes[id] = node; 880 | } 881 | 882 | // Connect the nodes 883 | for (var id in data.nodes) { 884 | var spec = data.nodes[id]; 885 | var node = nodes[id]; 886 | 887 | if (node.category === b3.COMPOSITE && spec.children) { 888 | for (var i=0; i 0) { 922 | var node = stack.pop(); 923 | 924 | var spec = {}; 925 | spec.id = node.id; 926 | spec.name = node.name; 927 | spec.title = node.title; 928 | spec.description = node.description; 929 | spec.properties = node.properties; 930 | spec.parameters = node.parameters; 931 | 932 | if (node.category === b3.COMPOSITE && node.children) { 933 | var children = [] 934 | for (var i=node.children.length-1; i>=0; i--) { 935 | children.push(node.children[i].id); 936 | stack.push(node.children[i]); 937 | } 938 | spec.children = children; 939 | } else if (node.category === b3.DECORATOR && node.child) { 940 | stack.push(node.child); 941 | spec.child = node.child.id; 942 | } 943 | 944 | data.nodes[node.id] = spec; 945 | } 946 | 947 | return data; 948 | }; 949 | 950 | /** 951 | * Propagates the tick signal through the tree, starting from the root. 952 | * 953 | * This method receives a target object of any type (Object, Array, 954 | * DOMElement, whatever) and a `Blackboard` instance. The target object has 955 | * no use at all for all Behavior3JS components, but surely is important 956 | * for custom nodes. The blackboard instance is used by the tree and nodes 957 | * to store execution variables (e.g., last node running) and is obligatory 958 | * to be a `Blackboard` instance (or an object with the same interface). 959 | * 960 | * Internally, this method creates a Tick object, which will store the 961 | * target and the blackboard objects. 962 | * 963 | * Note: BehaviorTree stores a list of open nodes from last tick, if these 964 | * nodes weren't called after the current tick, this method will close them 965 | * automatically. 966 | * 967 | * @method tick 968 | * @param {Object} target A target object. 969 | * @param {Blackboard} blackboard An instance of blackboard object. 970 | * @returns {Constant} The tick signal state. 971 | **/ 972 | p.tick = function(target, blackboard) { 973 | if (!blackboard) { 974 | throw 'The blackboard parameter is obligatory and must be an ' + 975 | 'instance of b3.Blackboard'; 976 | } 977 | 978 | /* CREATE A TICK OBJECT */ 979 | var tick = new b3.Tick(); 980 | tick.debug = this.debug; 981 | tick.target = target; 982 | tick.blackboard = blackboard; 983 | tick.tree = this; 984 | 985 | /* TICK NODE */ 986 | var state = this.root._execute(tick); 987 | 988 | /* CLOSE NODES FROM LAST TICK, IF NEEDED */ 989 | var lastOpenNodes = blackboard.get('openNodes', this.id); 990 | var currOpenNodes = tick._openNodes.slice(0); 991 | 992 | // does not close if it is still open in this tick 993 | var start = 0; 994 | for (var i=0; i=start; i--) { 1003 | lastOpenNodes[i]._close(tick); 1004 | } 1005 | 1006 | /* POPULATE BLACKBOARD */ 1007 | blackboard.set('openNodes', currOpenNodes, this.id); 1008 | blackboard.set('nodeCount', tick._nodeCount, this.id); 1009 | 1010 | return state; 1011 | }; 1012 | 1013 | 1014 | b3.BehaviorTree = BehaviorTree; 1015 | 1016 | })();/** 1017 | * BaseNode 1018 | * 1019 | * Copyright (c) 2014 Renato de Pontes Pereira. 1020 | * 1021 | * Permission is hereby granted, free of charge, to any person obtaining a copy 1022 | * of this software and associated documentation files (the "Software"), to 1023 | * deal in the Software without restriction, including without limitation the 1024 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 1025 | * sell copies of the Software, and to permit persons to whom the Software is 1026 | * furnished to do so, subject to the following conditions: 1027 | * 1028 | * The above copyright notice and this permission notice shall be included in 1029 | * all copies or substantial portions of the Software. 1030 | * 1031 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1032 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1033 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1034 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1035 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 1036 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 1037 | * IN THE SOFTWARE. 1038 | **/ 1039 | 1040 | /** 1041 | * @module Behavior3JS 1042 | **/ 1043 | 1044 | // namespace: 1045 | //this.b3 = this.b3 || {}; 1046 | 1047 | (function() { 1048 | "use strict"; 1049 | 1050 | /** 1051 | * The BaseNode class is used as super class to all nodes in BehaviorJS. It 1052 | * comprises all common variables and methods that a node must have to execute. 1053 | * 1054 | * **IMPORTANT:** Do not inherit from this class, use `b3.Composite`, 1055 | * `b3.Decorator`, `b3.Action` or `b3.Condition`, instead. 1056 | * 1057 | * The attributes are specially designed to serialization of the node in a JSON 1058 | * format. In special, the `parameters` attribute can be set into the visual 1059 | * editor (thus, in the JSON file), and it will be used as parameter on the 1060 | * node initialization at `BehaviorTree.load`. 1061 | * 1062 | * BaseNode also provide 5 callback methods, which the node implementations can 1063 | * override. They are `enter`, `open`, `tick`, `close` and `exit`. See their 1064 | * documentation to know more. These callbacks are called inside the `_execute` 1065 | * method, which is called in the tree traversal. 1066 | * 1067 | * @class BaseNode 1068 | **/ 1069 | var BaseNode = b3.Class(); 1070 | 1071 | var p = BaseNode.prototype; 1072 | 1073 | /** 1074 | * Node ID. 1075 | * 1076 | * @property id 1077 | * @type {String} 1078 | * @readonly 1079 | **/ 1080 | 1081 | /** 1082 | * Node name. Must be a unique identifier, preferable the same name of the 1083 | * class. You have to set the node name in the prototype. 1084 | * 1085 | * @property name 1086 | * @type {String} 1087 | * @readonly 1088 | **/ 1089 | p.name = null; 1090 | 1091 | /** 1092 | * Node category. Must be `b3.COMPOSITE`, `b3.DECORATOR`, `b3.ACTION` or 1093 | * `b3.CONDITION`. This is defined automatically be inheriting the 1094 | * correspondent class. 1095 | * 1096 | * @property category 1097 | * @type constant 1098 | * @readonly 1099 | **/ 1100 | p.category = null; 1101 | 1102 | /** 1103 | * Node title. 1104 | * 1105 | * @property title 1106 | * @type {String} 1107 | * @optional 1108 | * @readonly 1109 | **/ 1110 | p.title = null; 1111 | 1112 | /** 1113 | * Node description. 1114 | * 1115 | * @property description 1116 | * @type {String} 1117 | * @optional 1118 | * @readonly 1119 | **/ 1120 | p.description = null; 1121 | 1122 | /** 1123 | * A dictionary (key, value) describing the node parameters. Useful for 1124 | * defining parameter values in the visual editor. Note: this is only 1125 | * useful for nodes when loading trees from JSON files. 1126 | * 1127 | * @property parameters 1128 | * @type {Object} 1129 | * @readonly 1130 | **/ 1131 | p.parameters = null; 1132 | 1133 | /** 1134 | * A dictionary (key, value) describing the node properties. Useful for 1135 | * defining custom variables inside the visual editor. 1136 | * 1137 | * @property properties 1138 | * @type {Object} 1139 | * @readonly 1140 | **/ 1141 | p.properties = null; 1142 | 1143 | /** 1144 | * Initialization method. 1145 | * 1146 | * @method initialize 1147 | * @constructor 1148 | **/ 1149 | p.initialize = function() { 1150 | this.id = b3.createUUID(); 1151 | this.title = this.title || this.name; 1152 | this.description = ''; 1153 | this.parameters = {}; 1154 | this.properties = {}; 1155 | } 1156 | 1157 | /** 1158 | * This is the main method to propagate the tick signal to this node. This 1159 | * method calls all callbacks: `enter`, `open`, `tick`, `close`, and 1160 | * `exit`. It only opens a node if it is not already open. In the same 1161 | * way, this method only close a node if the node returned a status 1162 | * different of `b3.RUNNING`. 1163 | * 1164 | * @method _execute 1165 | * @param {Tick} tick A tick instance. 1166 | * @returns {Constant} The tick state. 1167 | * @protected 1168 | **/ 1169 | p._execute = function(tick) { 1170 | /* ENTER */ 1171 | this._enter(tick); 1172 | 1173 | /* OPEN */ 1174 | if (!tick.blackboard.get('isOpen', tick.tree.id, this.id)) { 1175 | this._open(tick); 1176 | } 1177 | 1178 | /* TICK */ 1179 | var status = this._tick(tick); 1180 | 1181 | /* CLOSE */ 1182 | if (status !== b3.RUNNING) { 1183 | this._close(tick); 1184 | } 1185 | 1186 | /* EXIT */ 1187 | this._exit(tick); 1188 | 1189 | return status; 1190 | } 1191 | 1192 | /** 1193 | * Wrapper for enter method. 1194 | * 1195 | * @method _enter 1196 | * @param {Tick} tick A tick instance. 1197 | * @protected 1198 | **/ 1199 | p._enter = function(tick) { 1200 | tick._enterNode(this); 1201 | this.enter(tick); 1202 | } 1203 | 1204 | /** 1205 | * Wrapper for open method. 1206 | * 1207 | * @method _open 1208 | * @param {Tick} tick A tick instance. 1209 | * @protected 1210 | **/ 1211 | p._open = function(tick) { 1212 | tick._openNode(this); 1213 | tick.blackboard.set('isOpen', true, tick.tree.id, this.id); 1214 | this.open(tick); 1215 | } 1216 | 1217 | /** 1218 | * Wrapper for tick method. 1219 | * 1220 | * @method _tick 1221 | * @param {Tick} tick A tick instance. 1222 | * @returns {Constant} A state constant. 1223 | * @protected 1224 | **/ 1225 | p._tick = function(tick) { 1226 | tick._tickNode(this); 1227 | return this.tick(tick); 1228 | } 1229 | 1230 | /** 1231 | * Wrapper for close method. 1232 | * 1233 | * @method _close 1234 | * @param {Tick} tick A tick instance. 1235 | * @protected 1236 | **/ 1237 | p._close = function(tick) { 1238 | tick._closeNode(this); 1239 | tick.blackboard.set('isOpen', false, tick.tree.id, this.id); 1240 | this.close(tick); 1241 | } 1242 | 1243 | /** 1244 | * Wrapper for exit method. 1245 | * 1246 | * @method _exit 1247 | * @param {Tick} tick A tick instance. 1248 | * @protected 1249 | **/ 1250 | p._exit = function(tick) { 1251 | tick._exitNode(this); 1252 | this.exit(tick); 1253 | } 1254 | 1255 | /** 1256 | * Enter method, override this to use. It is called every time a node is 1257 | * asked to execute, before the tick itself. 1258 | * 1259 | * @method enter 1260 | * @param {Tick} tick A tick instance. 1261 | **/ 1262 | p.enter = function(tick) {} 1263 | 1264 | /** 1265 | * Open method, override this to use. It is called only before the tick 1266 | * callback and only if the not isn't closed. 1267 | * 1268 | * Note: a node will be closed if it returned `b3.RUNNING` in the tick. 1269 | * 1270 | * @method open 1271 | * @param {Tick} tick A tick instance. 1272 | **/ 1273 | p.open = function(tick) {} 1274 | 1275 | /** 1276 | * Tick method, override this to use. This method must contain the real 1277 | * execution of node (perform a task, call children, etc.). It is called 1278 | * every time a node is asked to execute. 1279 | * 1280 | * @method tick 1281 | * @param {Tick} tick A tick instance. 1282 | **/ 1283 | p.tick = function(tick) {} 1284 | 1285 | /** 1286 | * Close method, override this to use. This method is called after the tick 1287 | * callback, and only if the tick return a state different from 1288 | * `b3.RUNNING`. 1289 | * 1290 | * @method close 1291 | * @param {Tick} tick A tick instance. 1292 | **/ 1293 | p.close = function(tick) {} 1294 | 1295 | /** 1296 | * Exit method, override this to use. Called every time in the end of the 1297 | * execution. 1298 | * 1299 | * @method exit 1300 | * @param {Tick} tick A tick instance. 1301 | **/ 1302 | p.exit = function(tick) {} 1303 | 1304 | b3.BaseNode = BaseNode; 1305 | 1306 | })();/** 1307 | * Action 1308 | * 1309 | * Copyright (c) 2014 Renato de Pontes Pereira. 1310 | * 1311 | * Permission is hereby granted, free of charge, to any person obtaining a copy 1312 | * of this software and associated documentation files (the "Software"), to 1313 | * deal in the Software without restriction, including without limitation the 1314 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 1315 | * sell copies of the Software, and to permit persons to whom the Software is 1316 | * furnished to do so, subject to the following conditions: 1317 | * 1318 | * The above copyright notice and this permission notice shall be included in 1319 | * all copies or substantial portions of the Software. 1320 | * 1321 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1322 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1323 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1324 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1325 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 1326 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 1327 | * IN THE SOFTWARE. 1328 | **/ 1329 | 1330 | /** 1331 | * @module Behavior3JS 1332 | **/ 1333 | 1334 | // namespace: 1335 | //this.b3 = this.b3 || {}; 1336 | 1337 | (function() { 1338 | "use strict"; 1339 | 1340 | /** 1341 | * Action is the base class for all action nodes. Thus, if you want to 1342 | * create new custom action nodes, you need to inherit from this class. 1343 | * 1344 | * For example, take a look at the Runner action: 1345 | * 1346 | * var Runner = b3.Class(b3.Action); 1347 | * var p = Runner.prototype; 1348 | * 1349 | * p.name = 'Runner'; 1350 | * 1351 | * p.tick = function(tick) { 1352 | * return b3.RUNNING; 1353 | * } 1354 | * 1355 | * @class Action 1356 | * @extends BaseNode 1357 | **/ 1358 | var Action = b3.Class(b3.BaseNode); 1359 | 1360 | var p = Action.prototype; 1361 | 1362 | /** 1363 | * Node category. Default to `b3.ACTION`. 1364 | * 1365 | * @property category 1366 | * @type {String} 1367 | * @readonly 1368 | **/ 1369 | p.category = b3.ACTION; 1370 | 1371 | p.__BaseNode_initialize = p.initialize; 1372 | /** 1373 | * Initialization method. 1374 | * 1375 | * @method initialize 1376 | * @constructor 1377 | **/ 1378 | p.initialize = function() { 1379 | this.__BaseNode_initialize(); 1380 | } 1381 | 1382 | b3.Action = Action; 1383 | 1384 | })();/** 1385 | * Composite 1386 | * 1387 | * Copyright (c) 2014 Renato de Pontes Pereira. 1388 | * 1389 | * Permission is hereby granted, free of charge, to any person obtaining a copy 1390 | * of this software and associated documentation files (the "Software"), to 1391 | * deal in the Software without restriction, including without limitation the 1392 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 1393 | * sell copies of the Software, and to permit persons to whom the Software is 1394 | * furnished to do so, subject to the following conditions: 1395 | * 1396 | * The above copyright notice and this permission notice shall be included in 1397 | * all copies or substantial portions of the Software. 1398 | * 1399 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1400 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1401 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1402 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1403 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 1404 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 1405 | * IN THE SOFTWARE. 1406 | **/ 1407 | 1408 | /** 1409 | * @module Behavior3JS 1410 | **/ 1411 | 1412 | // namespace: 1413 | //this.b3 = this.b3 || {}; 1414 | 1415 | (function() { 1416 | "use strict"; 1417 | 1418 | /** 1419 | * Composite is the base class for all composite nodes. Thus, if you want to 1420 | * create new custom composite nodes, you need to inherit from this class. 1421 | * 1422 | * When creating composite nodes, you will need to propagate the tick signal to 1423 | * the children nodes manually. To do that, override the `tick` method and call 1424 | * the `_execute` method on all nodes. For instance, take a look at how the 1425 | * Sequence node inherit this class and how it call its children: 1426 | * 1427 | * 1428 | * // Inherit from Composite, using the util function Class. 1429 | * var Sequence = b3.Class(b3.Composite); 1430 | * var p = Sequence.prototype; 1431 | * 1432 | * // Remember to set the name of the node. 1433 | * p.name = 'Sequence'; 1434 | * 1435 | * // Override the tick function 1436 | * p.tick = function(tick) { 1437 | * 1438 | * // Iterates over the children 1439 | * for (var i=0; i this.maxTime) { 2323 | return b3.FAILURE; 2324 | } 2325 | 2326 | return status; 2327 | }; 2328 | 2329 | b3.MaxTime = MaxTime; 2330 | 2331 | })();/** 2332 | * Repeater 2333 | * 2334 | * Copyright (c) 2014 Renato de Pontes Pereira. 2335 | * 2336 | * Permission is hereby granted, free of charge, to any person obtaining a copy 2337 | * of this software and associated documentation files (the "Software"), to 2338 | * deal in the Software without restriction, including without limitation the 2339 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 2340 | * sell copies of the Software, and to permit persons to whom the Software is 2341 | * furnished to do so, subject to the following conditions: 2342 | * 2343 | * The above copyright notice and this permission notice shall be included in 2344 | * all copies or substantial portions of the Software. 2345 | * 2346 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2347 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2348 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2349 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2350 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2351 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2352 | * IN THE SOFTWARE. 2353 | **/ 2354 | 2355 | /** 2356 | * @module Behavior3JS 2357 | **/ 2358 | 2359 | // namespace: 2360 | //this.b3 = this.b3 || {}; 2361 | 2362 | (function() { 2363 | "use strict"; 2364 | 2365 | /** 2366 | * Repeater is a decorator that repeats the tick signal until the child node 2367 | * return `RUNNING` or `ERROR`. Optionally, a maximum number of repetitions 2368 | * can be defined. 2369 | * 2370 | * @class Repeater 2371 | * @extends Decorator 2372 | **/ 2373 | var Repeater = b3.Class(b3.Decorator); 2374 | 2375 | var p = Repeater.prototype; 2376 | 2377 | /** 2378 | * Node name. Default to `Repeater`. 2379 | * 2380 | * @property name 2381 | * @type {String} 2382 | * @readonly 2383 | **/ 2384 | p.name = 'Repeater'; 2385 | 2386 | /** 2387 | * Node parameters. 2388 | * 2389 | * @property parameters 2390 | * @type {String} 2391 | * @readonly 2392 | **/ 2393 | p.parameters = {'maxLoop': -1}; 2394 | 2395 | p.__Decorator_initialize = p.initialize; 2396 | /** 2397 | * Initialization method. 2398 | * 2399 | * Settings parameters: 2400 | * 2401 | * - **maxLoop** (*Integer*) Maximum number of repetitions. Default to -1 2402 | * (infinite). 2403 | * - **child** (*BaseNode*) The child node. 2404 | * 2405 | * @method initialize 2406 | * @param {Object} settings Object with parameters. 2407 | * @constructor 2408 | **/ 2409 | p.initialize = function(settings) { 2410 | settings = settings || {}; 2411 | 2412 | this.__Decorator_initialize(settings); 2413 | 2414 | this.maxLoop = settings.maxLoop || -1; 2415 | }; 2416 | 2417 | /** 2418 | * Open method. 2419 | * 2420 | * @method open 2421 | * @param {Tick} tick A tick instance. 2422 | **/ 2423 | p.open = function(tick) { 2424 | tick.blackboard.set('i', 0, tick.tree.id, this.id); 2425 | }; 2426 | 2427 | /** 2428 | * Tick method. 2429 | * 2430 | * @method tick 2431 | * @param {Tick} tick A tick instance. 2432 | **/ 2433 | p.tick = function(tick) { 2434 | if (!this.child) { 2435 | return b3.ERROR; 2436 | } 2437 | 2438 | var i = tick.blackboard.get('i', tick.tree.id, this.id); 2439 | var status = b3.SUCCESS; 2440 | 2441 | while (this.maxLoop < 0 || i < this.maxLoop) { 2442 | status = this.child._execute(tick); 2443 | 2444 | if (status == b3.SUCCESS || status == b3.FAILURE) 2445 | i++; 2446 | else 2447 | break; 2448 | } 2449 | 2450 | i = tick.blackboard.set('i', i, tick.tree.id, this.id); 2451 | return status; 2452 | }; 2453 | 2454 | b3.Repeater = Repeater; 2455 | 2456 | })();/** 2457 | * RepeatUntilFailure 2458 | * 2459 | * Copyright (c) 2014 Renato de Pontes Pereira. 2460 | * 2461 | * Permission is hereby granted, free of charge, to any person obtaining a copy 2462 | * of this software and associated documentation files (the "Software"), to 2463 | * deal in the Software without restriction, including without limitation the 2464 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 2465 | * sell copies of the Software, and to permit persons to whom the Software is 2466 | * furnished to do so, subject to the following conditions: 2467 | * 2468 | * The above copyright notice and this permission notice shall be included in 2469 | * all copies or substantial portions of the Software. 2470 | * 2471 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2472 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2473 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2474 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2475 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2476 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2477 | * IN THE SOFTWARE. 2478 | **/ 2479 | 2480 | /** 2481 | * @module Behavior3JS 2482 | **/ 2483 | 2484 | // namespace: 2485 | //this.b3 = this.b3 || {}; 2486 | 2487 | (function() { 2488 | "use strict"; 2489 | 2490 | /** 2491 | * RepeatUntilFailure is a decorator that repeats the tick signal until the 2492 | * node child returns `FAILURE`, `RUNNING` or `ERROR`. Optionally, a maximum 2493 | * number of repetitions can be defined. 2494 | * 2495 | * @class RepeatUntilFailure 2496 | * @extends Decorator 2497 | **/ 2498 | var RepeatUntilFailure = b3.Class(b3.Decorator); 2499 | 2500 | var p = RepeatUntilFailure.prototype; 2501 | 2502 | /** 2503 | * Node name. Default to `RepeatUntilFailure`. 2504 | * 2505 | * @property name 2506 | * @type {String} 2507 | * @readonly 2508 | **/ 2509 | p.name = 'RepeatUntilFailure'; 2510 | 2511 | /** 2512 | * Node title. Default to `Repeat Until Failure`. 2513 | * 2514 | * @property title 2515 | * @type {String} 2516 | * @readonly 2517 | **/ 2518 | p.title = 'Repeat Until Failure'; 2519 | 2520 | /** 2521 | * Node parameters. 2522 | * 2523 | * @property parameters 2524 | * @type {String} 2525 | * @readonly 2526 | **/ 2527 | p.parameters = {'maxLoop': -1}; 2528 | 2529 | p.__Decorator_initialize = p.initialize; 2530 | /** 2531 | * Initialization method. 2532 | * 2533 | * Settings parameters: 2534 | * 2535 | * - **maxLoop** (*Integer*) Maximum number of repetitions. Default to -1 2536 | * (infinite). 2537 | * - **child** (*BaseNode*) The child node. 2538 | * 2539 | * @method initialize 2540 | * @param {Object} settings Object with parameters. 2541 | * @constructor 2542 | **/ 2543 | p.initialize = function(settings) { 2544 | settings = settings || {}; 2545 | 2546 | this.__Decorator_initialize(settings); 2547 | 2548 | this.maxLoop = settings.maxLoop || -1; 2549 | } 2550 | 2551 | /** 2552 | * Open method. 2553 | * 2554 | * @method open 2555 | * @param {Tick} tick A tick instance. 2556 | **/ 2557 | p.open = function(tick) { 2558 | tick.blackboard.set('i', 0, tick.tree.id, this.id); 2559 | } 2560 | 2561 | /** 2562 | * Tick method. 2563 | * 2564 | * @method tick 2565 | * @param {Tick} tick A tick instance. 2566 | * @returns {Constant} A state constant. 2567 | **/ 2568 | p.tick = function(tick) { 2569 | if (!this.child) { 2570 | return b3.ERROR; 2571 | } 2572 | 2573 | var i = tick.blackboard.get('i', tick.tree.id, this.id); 2574 | 2575 | while (this.maxLoop < 0 || i < this.maxLoop) { 2576 | var status = this.child._execute(tick); 2577 | 2578 | if (status == b3.SUCCESS) 2579 | i++; 2580 | else 2581 | break; 2582 | } 2583 | 2584 | var i = tick.blackboard.set('i', i, tick.tree.id, this.id); 2585 | return status; 2586 | } 2587 | 2588 | b3.RepeatUntilFailure = RepeatUntilFailure; 2589 | 2590 | })();/** 2591 | * RepeatUntilSuccess 2592 | * 2593 | * Copyright (c) 2014 Renato de Pontes Pereira. 2594 | * 2595 | * Permission is hereby granted, free of charge, to any person obtaining a copy 2596 | * of this software and associated documentation files (the "Software"), to 2597 | * deal in the Software without restriction, including without limitation the 2598 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 2599 | * sell copies of the Software, and to permit persons to whom the Software is 2600 | * furnished to do so, subject to the following conditions: 2601 | * 2602 | * The above copyright notice and this permission notice shall be included in 2603 | * all copies or substantial portions of the Software. 2604 | * 2605 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2606 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2607 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2608 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2609 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2610 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2611 | * IN THE SOFTWARE. 2612 | **/ 2613 | 2614 | /** 2615 | * @module Behavior3JS 2616 | **/ 2617 | 2618 | // namespace: 2619 | //this.b3 = this.b3 || {}; 2620 | 2621 | (function() { 2622 | "use strict"; 2623 | 2624 | /** 2625 | * RepeatUntilSuccess is a decorator that repeats the tick signal until the 2626 | * node child returns `SUCCESS`, `RUNNING` or `ERROR`. Optionally, a maximum 2627 | * number of repetitions can be defined. 2628 | * 2629 | * @class RepeatUntilSuccess 2630 | * @extends Decorator 2631 | **/ 2632 | var RepeatUntilSuccess = b3.Class(b3.Decorator); 2633 | 2634 | var p = RepeatUntilSuccess.prototype; 2635 | 2636 | /** 2637 | * Node name. Default to `RepeatUntilSuccess`. 2638 | * 2639 | * @property name 2640 | * @type {String} 2641 | * @readonly 2642 | **/ 2643 | p.name = 'RepeatUntilSuccess'; 2644 | 2645 | /** 2646 | * Node title. Default to `Repeat Until Success`. 2647 | * 2648 | * @property title 2649 | * @type {String} 2650 | * @readonly 2651 | **/ 2652 | p.title = 'Repeat Until Success'; 2653 | 2654 | /** 2655 | * Node parameters. 2656 | * 2657 | * @property parameters 2658 | * @type {String} 2659 | * @readonly 2660 | **/ 2661 | p.parameters = {'maxLoop': -1}; 2662 | 2663 | p.__Decorator_initialize = p.initialize; 2664 | /** 2665 | * Initialization method. 2666 | * 2667 | * Settings parameters: 2668 | * 2669 | * - **maxLoop** (*Integer*) Maximum number of repetitions. Default to -1 2670 | * (infinite). 2671 | * - **child** (*BaseNode*) The child node. 2672 | * 2673 | * @method initialize 2674 | * @param {Object} settings Object with parameters. 2675 | * @constructor 2676 | **/ 2677 | p.initialize = function(settings) { 2678 | settings = settings || {}; 2679 | 2680 | this.__Decorator_initialize(settings); 2681 | 2682 | this.maxLoop = settings.maxLoop || -1; 2683 | } 2684 | 2685 | /** 2686 | * Open method. 2687 | * 2688 | * @method open 2689 | * @param {Tick} tick A tick instance. 2690 | **/ 2691 | p.open = function(tick) { 2692 | tick.blackboard.set('i', 0, tick.tree.id, this.id); 2693 | } 2694 | 2695 | /** 2696 | * Tick method. 2697 | * 2698 | * @method tick 2699 | * @param {Tick} tick A tick instance. 2700 | * @returns {Constant} A state constant. 2701 | **/ 2702 | p.tick = function(tick) { 2703 | if (!this.child) { 2704 | return b3.ERROR; 2705 | } 2706 | 2707 | var i = tick.blackboard.get('i', tick.tree.id, this.id); 2708 | 2709 | while (this.maxLoop < 0 || i < this.maxLoop) { 2710 | var status = this.child._execute(tick); 2711 | 2712 | if (status == b3.FAILURE) 2713 | i++; 2714 | else 2715 | break; 2716 | } 2717 | 2718 | var i = tick.blackboard.set('i', i, tick.tree.id, this.id); 2719 | return status; 2720 | } 2721 | 2722 | b3.RepeatUntilSuccess = RepeatUntilSuccess; 2723 | 2724 | })();/** 2725 | * Error 2726 | * 2727 | * Copyright (c) 2014 Renato de Pontes Pereira. 2728 | * 2729 | * Permission is hereby granted, free of charge, to any person obtaining a copy 2730 | * of this software and associated documentation files (the "Software"), to 2731 | * deal in the Software without restriction, including without limitation the 2732 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 2733 | * sell copies of the Software, and to permit persons to whom the Software is 2734 | * furnished to do so, subject to the following conditions: 2735 | * 2736 | * The above copyright notice and this permission notice shall be included in 2737 | * all copies or substantial portions of the Software. 2738 | * 2739 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2740 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2741 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2742 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2743 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2744 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2745 | * IN THE SOFTWARE. 2746 | **/ 2747 | 2748 | /** 2749 | * @module Behavior3JS 2750 | **/ 2751 | 2752 | // namespace: 2753 | //this.b3 = this.b3 || {}; 2754 | 2755 | (function() { 2756 | "use strict"; 2757 | 2758 | /** 2759 | * This action node returns `ERROR` always. 2760 | * 2761 | * @class Error 2762 | * @extends Action 2763 | **/ 2764 | var Error = b3.Class(b3.Action); 2765 | 2766 | var p = Error.prototype; 2767 | 2768 | /** 2769 | * Node name. Default to `Error`. 2770 | * 2771 | * @property name 2772 | * @type {String} 2773 | * @readonly 2774 | **/ 2775 | p.name = 'Error'; 2776 | 2777 | /** 2778 | * Tick method. 2779 | * 2780 | * @method tick 2781 | * @param {b3.Tick} tick A tick instance. 2782 | * @returns {Constant} Always return `b3.ERROR`. 2783 | **/ 2784 | p.tick = function(tick) { 2785 | return b3.ERROR; 2786 | } 2787 | 2788 | b3.Error = Error; 2789 | 2790 | })();/** 2791 | * Failer 2792 | * 2793 | * Copyright (c) 2014 Renato de Pontes Pereira. 2794 | * 2795 | * Permission is hereby granted, free of charge, to any person obtaining a copy 2796 | * of this software and associated documentation files (the "Software"), to 2797 | * deal in the Software without restriction, including without limitation the 2798 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 2799 | * sell copies of the Software, and to permit persons to whom the Software is 2800 | * furnished to do so, subject to the following conditions: 2801 | * 2802 | * The above copyright notice and this permission notice shall be included in 2803 | * all copies or substantial portions of the Software. 2804 | * 2805 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2806 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2807 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2808 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2809 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2810 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2811 | * IN THE SOFTWARE. 2812 | **/ 2813 | 2814 | /** 2815 | * @module Behavior3JS 2816 | **/ 2817 | 2818 | // namespace: 2819 | //this.b3 = this.b3 || {}; 2820 | 2821 | (function() { 2822 | "use strict"; 2823 | 2824 | /** 2825 | * This action node returns `FAILURE` always. 2826 | * 2827 | * @class Failer 2828 | * @extends Action 2829 | **/ 2830 | var Failer = b3.Class(b3.Action); 2831 | 2832 | var p = Failer.prototype; 2833 | 2834 | /** 2835 | * Node name. Default to `Failer`. 2836 | * 2837 | * @property name 2838 | * @type {String} 2839 | * @readonly 2840 | **/ 2841 | p.name = 'Failer'; 2842 | 2843 | /** 2844 | * Tick method. 2845 | * 2846 | * @method tick 2847 | * @param {b3.Tick} tick A tick instance. 2848 | * @returns {Constant} Always return `b3.FAILURE`. 2849 | **/ 2850 | p.tick = function(tick) { 2851 | return b3.FAILURE; 2852 | } 2853 | 2854 | b3.Failer = Failer; 2855 | 2856 | })();/** 2857 | * Runner 2858 | * 2859 | * Copyright (c) 2014 Renato de Pontes Pereira. 2860 | * 2861 | * Permission is hereby granted, free of charge, to any person obtaining a copy 2862 | * of this software and associated documentation files (the "Software"), to 2863 | * deal in the Software without restriction, including without limitation the 2864 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 2865 | * sell copies of the Software, and to permit persons to whom the Software is 2866 | * furnished to do so, subject to the following conditions: 2867 | * 2868 | * The above copyright notice and this permission notice shall be included in 2869 | * all copies or substantial portions of the Software. 2870 | * 2871 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2872 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2873 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2874 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2875 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2876 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2877 | * IN THE SOFTWARE. 2878 | **/ 2879 | 2880 | /** 2881 | * @module Behavior3JS 2882 | **/ 2883 | 2884 | // namespace: 2885 | //this.b3 = this.b3 || {}; 2886 | 2887 | (function() { 2888 | "use strict"; 2889 | 2890 | /** 2891 | * This action node returns RUNNING always. 2892 | * 2893 | * @class Runner 2894 | * @extends Action 2895 | **/ 2896 | var Runner = b3.Class(b3.Action); 2897 | 2898 | var p = Runner.prototype; 2899 | 2900 | /** 2901 | * Node name. Default to `Runner`. 2902 | * 2903 | * @property name 2904 | * @type {String} 2905 | * @readonly 2906 | **/ 2907 | p.name = 'Runner'; 2908 | 2909 | /** 2910 | * Tick method. 2911 | * 2912 | * @method tick 2913 | * @param {b3.Tick} tick A tick instance. 2914 | * @returns {Constant} Always return `b3.RUNNING`. 2915 | **/ 2916 | p.tick = function(tick) { 2917 | return b3.RUNNING; 2918 | } 2919 | 2920 | b3.Runner = Runner; 2921 | 2922 | })();/** 2923 | * Succeeder 2924 | * 2925 | * Copyright (c) 2014 Renato de Pontes Pereira. 2926 | * 2927 | * Permission is hereby granted, free of charge, to any person obtaining a copy 2928 | * of this software and associated documentation files (the "Software"), to 2929 | * deal in the Software without restriction, including without limitation the 2930 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 2931 | * sell copies of the Software, and to permit persons to whom the Software is 2932 | * furnished to do so, subject to the following conditions: 2933 | * 2934 | * The above copyright notice and this permission notice shall be included in 2935 | * all copies or substantial portions of the Software. 2936 | * 2937 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2938 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2939 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 2940 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2941 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2942 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2943 | * IN THE SOFTWARE. 2944 | **/ 2945 | 2946 | /** 2947 | * @module Behavior3JS 2948 | **/ 2949 | 2950 | // namespace: 2951 | //this.b3 = this.b3 || {}; 2952 | 2953 | (function() { 2954 | "use strict"; 2955 | 2956 | /** 2957 | * This action node returns `SUCCESS` always. 2958 | * 2959 | * @class Succeeder 2960 | * @extends Action 2961 | **/ 2962 | var Succeeder = b3.Class(b3.Action); 2963 | 2964 | var p = Succeeder.prototype; 2965 | 2966 | /** 2967 | * Node name. Default to `Succeeder`. 2968 | * 2969 | * @property name 2970 | * @type String 2971 | * @readonly 2972 | **/ 2973 | p.name = 'Succeeder'; 2974 | 2975 | /** 2976 | * Tick method. 2977 | * 2978 | * @method tick 2979 | * @param {b3.Tick} tick A tick instance. 2980 | * @returns {Constant} Always return `b3.SUCCESS`. 2981 | **/ 2982 | p.tick = function(tick) { 2983 | return b3.SUCCESS; 2984 | } 2985 | 2986 | b3.Succeeder = Succeeder; 2987 | 2988 | })();/** 2989 | * Wait 2990 | * 2991 | * Copyright (c) 2014 Renato de Pontes Pereira. 2992 | * 2993 | * Permission is hereby granted, free of charge, to any person obtaining a copy 2994 | * of this software and associated documentation files (the "Software"), to 2995 | * deal in the Software without restriction, including without limitation the 2996 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 2997 | * sell copies of the Software, and to permit persons to whom the Software is 2998 | * furnished to do so, subject to the following conditions: 2999 | * 3000 | * The above copyright notice and this permission notice shall be included in 3001 | * all copies or substantial portions of the Software. 3002 | * 3003 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 3004 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 3005 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 3006 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 3007 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 3008 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 3009 | * IN THE SOFTWARE. 3010 | **/ 3011 | 3012 | /** 3013 | * @module Behavior3JS 3014 | **/ 3015 | 3016 | // namespace: 3017 | //this.b3 = this.b3 || {}; 3018 | 3019 | (function() { 3020 | "use strict"; 3021 | 3022 | /** 3023 | * Wait a few seconds. 3024 | * 3025 | * @class Wait 3026 | * @extends Action 3027 | **/ 3028 | var Wait = b3.Class(b3.Action); 3029 | 3030 | var p = Wait.prototype; 3031 | 3032 | /** 3033 | * Node name. Default to `Wait`. 3034 | * 3035 | * @property name 3036 | * @type {String} 3037 | * @readonly 3038 | **/ 3039 | p.name = 'Wait'; 3040 | 3041 | /** 3042 | * Node parameters. 3043 | * 3044 | * @property parameters 3045 | * @type {String} 3046 | * @readonly 3047 | **/ 3048 | p.parameters = {'milliseconds': 0}; 3049 | 3050 | p.__Action_initialize = p.initialize; 3051 | /** 3052 | * Initialization method. 3053 | * 3054 | * Settings parameters: 3055 | * 3056 | * - **milliseconds** (*Integer*) Maximum time, in milliseconds, a child 3057 | * can execute. 3058 | * 3059 | * @method initialize 3060 | * @param {Object} settings Object with parameters. 3061 | * @constructor 3062 | **/ 3063 | p.initialize = function(settings) { 3064 | settings = settings || {}; 3065 | 3066 | this.__Action_initialize(); 3067 | 3068 | this.endTime = settings.milliseconds || 0; 3069 | } 3070 | 3071 | /** 3072 | * Open method. 3073 | * 3074 | * @method open 3075 | * @param {Tick} tick A tick instance. 3076 | **/ 3077 | p.open = function(tick) { 3078 | var startTime = (new Date()).getTime(); 3079 | tick.blackboard.set('startTime', startTime, tick.tree.id, this.id); 3080 | } 3081 | 3082 | /** 3083 | * Tick method. 3084 | * 3085 | * @method tick 3086 | * @param {Tick} tick A tick instance. 3087 | * @returns {Constant} A state constant. 3088 | **/ 3089 | p.tick = function(tick) { 3090 | var currTime = (new Date()).getTime(); 3091 | var startTime = tick.blackboard.get('startTime', tick.tree.id, this.id); 3092 | 3093 | if (currTime - startTime > this.endTime) { 3094 | return b3.SUCCESS; 3095 | } 3096 | 3097 | return b3.RUNNING; 3098 | } 3099 | 3100 | b3.Wait = Wait; 3101 | 3102 | })(); 3103 | 3104 | module.exports = b3; --------------------------------------------------------------------------------