├── README.md ├── project.json ├── .gitattributes ├── template-banner.png ├── assets ├── Texture │ ├── HelloWorld.png │ ├── singleColor.png │ ├── singleColor.png.meta │ └── HelloWorld.png.meta ├── Prefabs.meta ├── Scene.meta ├── Script.meta ├── Texture.meta ├── Prefabs │ ├── node.prefab.meta │ └── node.prefab ├── Scene │ ├── helloworld.fire.meta │ └── helloworld.fire └── Script │ ├── Node.ts.meta │ ├── Controller.ts.meta │ ├── QuadTree.ts.meta │ ├── Node.ts │ ├── Controller.ts │ └── QuadTree.ts ├── template.json ├── settings ├── builder.panel.json ├── builder.json └── project.json ├── jsconfig.json ├── tsconfig.json └── .gitignore /README.md: -------------------------------------------------------------------------------- 1 | # Collision 2 | 3 | 四叉树碰撞检测优化 -------------------------------------------------------------------------------- /project.json: -------------------------------------------------------------------------------- 1 | { 2 | "engine": "cocos2d-html5", 3 | "packages": "packages" 4 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /template-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjz1994/Collision/HEAD/template-banner.png -------------------------------------------------------------------------------- /assets/Texture/HelloWorld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjz1994/Collision/HEAD/assets/Texture/HelloWorld.png -------------------------------------------------------------------------------- /assets/Texture/singleColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xjz1994/Collision/HEAD/assets/Texture/singleColor.png -------------------------------------------------------------------------------- /assets/Prefabs.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.1", 3 | "uuid": "bf1069cd-87d7-4bda-ab63-67ac4776d1e7", 4 | "subMetas": {} 5 | } -------------------------------------------------------------------------------- /assets/Scene.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.1", 3 | "uuid": "29f52784-2fca-467b-92e7-8fd9ef8c57b7", 4 | "isGroup": false, 5 | "subMetas": {} 6 | } -------------------------------------------------------------------------------- /assets/Script.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.1", 3 | "uuid": "4734c20c-0db8-4eb2-92ea-e692f4d70934", 4 | "isGroup": false, 5 | "subMetas": {} 6 | } -------------------------------------------------------------------------------- /assets/Texture.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.1", 3 | "uuid": "7b81d4e8-ec84-4716-968d-500ac1d78a54", 4 | "isGroup": false, 5 | "subMetas": {} 6 | } -------------------------------------------------------------------------------- /template.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TEMPLATES.helloworld-ts.name", 3 | "desc": "TEMPLATES.helloworld-ts.desc", 4 | "banner": "template-banner.png" 5 | } -------------------------------------------------------------------------------- /assets/Prefabs/node.prefab.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.0", 3 | "uuid": "ebdae515-8caa-4855-bb1c-54a10d97127a", 4 | "asyncLoadAssets": false, 5 | "subMetas": {} 6 | } -------------------------------------------------------------------------------- /assets/Scene/helloworld.fire.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.0", 3 | "uuid": "2d2f792f-a40c-49bb-a189-ed176a246e49", 4 | "asyncLoadAssets": false, 5 | "autoReleaseAssets": false, 6 | "subMetas": {} 7 | } -------------------------------------------------------------------------------- /settings/builder.panel.json: -------------------------------------------------------------------------------- 1 | { 2 | "excludeScenes": [], 3 | "packageName": "org.cocos2d.helloworld", 4 | "platform": "web-mobile", 5 | "startScene": "2d2f792f-a40c-49bb-a189-ed176a246e49", 6 | "title": "HelloWorld" 7 | } -------------------------------------------------------------------------------- /assets/Script/Node.ts.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.5", 3 | "uuid": "9b77e76a-1ed0-4d11-8e48-cbe46288c98c", 4 | "isPlugin": false, 5 | "loadPluginInWeb": true, 6 | "loadPluginInNative": true, 7 | "loadPluginInEditor": false, 8 | "subMetas": {} 9 | } -------------------------------------------------------------------------------- /assets/Script/Controller.ts.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.5", 3 | "uuid": "89b7f536-a584-42ca-8d20-1e4cdb3b362d", 4 | "isPlugin": false, 5 | "loadPluginInWeb": true, 6 | "loadPluginInNative": true, 7 | "loadPluginInEditor": false, 8 | "subMetas": {} 9 | } -------------------------------------------------------------------------------- /assets/Script/QuadTree.ts.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.5", 3 | "uuid": "71f1bd04-33b9-4447-9468-725ba1ed83c5", 4 | "isPlugin": false, 5 | "loadPluginInWeb": true, 6 | "loadPluginInNative": true, 7 | "loadPluginInEditor": false, 8 | "subMetas": {} 9 | } -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "experimentalDecorators": true 6 | }, 7 | "exclude": [ 8 | "node_modules", 9 | ".vscode", 10 | "library", 11 | "local", 12 | "settings", 13 | "temp" 14 | ] 15 | } -------------------------------------------------------------------------------- /settings/builder.json: -------------------------------------------------------------------------------- 1 | { 2 | "excludeScenes": [], 3 | "orientation": { 4 | "landscapeLeft": true, 5 | "landscapeRight": true, 6 | "portrait": false, 7 | "upsideDown": false 8 | }, 9 | "packageName": "org.cocos2d.helloworld", 10 | "startScene": "2d2f792f-a40c-49bb-a189-ed176a246e49", 11 | "title": "hello_world", 12 | "webOrientation": "auto" 13 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "lib": [ "dom", "es5", "es2015.promise" ], 5 | "target": "es5", 6 | "allowJs": true, 7 | "experimentalDecorators": true, 8 | "skipLibCheck": true 9 | }, 10 | "exclude": [ 11 | "node_modules", 12 | "library", 13 | "local", 14 | "temp", 15 | "build", 16 | "settings" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /settings/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "collision-matrix": [ 3 | [ 4 | true 5 | ] 6 | ], 7 | "excluded-modules": [], 8 | "group-list": [ 9 | "default" 10 | ], 11 | "start-scene": "current", 12 | "design-resolution-width": 960, 13 | "design-resolution-height": 640, 14 | "fit-width": false, 15 | "fit-height": true, 16 | "use-project-simulator-setting": false, 17 | "simulator-orientation": false, 18 | "use-customize-simulator": false, 19 | "simulator-resolution": { 20 | "width": 960, 21 | "height": 640 22 | }, 23 | "cocos-analytics": { 24 | "enable": false, 25 | "appID": "13798", 26 | "appSecret": "959b3ac0037d0f3c2fdce94f8421a9b2" 27 | } 28 | } -------------------------------------------------------------------------------- /assets/Texture/singleColor.png.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.0", 3 | "uuid": "a8027877-d8d6-4645-97a0-52d4a0123dba", 4 | "type": "sprite", 5 | "wrapMode": "clamp", 6 | "filterMode": "bilinear", 7 | "subMetas": { 8 | "singleColor": { 9 | "ver": "1.0.3", 10 | "uuid": "410fb916-8721-4663-bab8-34397391ace7", 11 | "rawTextureUuid": "a8027877-d8d6-4645-97a0-52d4a0123dba", 12 | "trimType": "auto", 13 | "trimThreshold": 1, 14 | "rotated": false, 15 | "offsetX": 0, 16 | "offsetY": 0, 17 | "trimX": 0, 18 | "trimY": 0, 19 | "width": 2, 20 | "height": 2, 21 | "rawWidth": 2, 22 | "rawHeight": 2, 23 | "borderTop": 0, 24 | "borderBottom": 0, 25 | "borderLeft": 0, 26 | "borderRight": 0, 27 | "subMetas": {} 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /assets/Texture/HelloWorld.png.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.0", 3 | "uuid": "6aa0aa6a-ebee-4155-a088-a687a6aadec4", 4 | "type": "sprite", 5 | "wrapMode": "clamp", 6 | "filterMode": "bilinear", 7 | "subMetas": { 8 | "HelloWorld": { 9 | "ver": "1.0.3", 10 | "uuid": "31bc895a-c003-4566-a9f3-2e54ae1c17dc", 11 | "rawTextureUuid": "6aa0aa6a-ebee-4155-a088-a687a6aadec4", 12 | "trimType": "auto", 13 | "trimThreshold": 1, 14 | "rotated": false, 15 | "offsetX": 0, 16 | "offsetY": 0, 17 | "trimX": 0, 18 | "trimY": 0, 19 | "width": 195, 20 | "height": 270, 21 | "rawWidth": 195, 22 | "rawHeight": 270, 23 | "borderTop": 0, 24 | "borderBottom": 0, 25 | "borderLeft": 0, 26 | "borderRight": 0, 27 | "subMetas": {} 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /assets/Script/Node.ts: -------------------------------------------------------------------------------- 1 | // Learn TypeScript: 2 | // - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/typescript.html 3 | // - [English] http://www.cocos2d-x.org/docs/creator/en/scripting/typescript.html 4 | // Learn Attribute: 5 | // - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/reference/attributes.html 6 | // - [English] http://www.cocos2d-x.org/docs/creator/en/scripting/reference/attributes.html 7 | // Learn life-cycle callbacks: 8 | // - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/life-cycle-callbacks.html 9 | // - [English] http://www.cocos2d-x.org/docs/creator/en/scripting/life-cycle-callbacks.html 10 | 11 | const { ccclass, property } = cc._decorator; 12 | 13 | @ccclass 14 | export default class NewClass extends cc.Component { 15 | 16 | // LIFE-CYCLE CALLBACKS: 17 | 18 | // onLoad () {} 19 | public isCollision: boolean = false; 20 | 21 | start() { 22 | this.node.x = cc.random0To1() * cc.Canvas.instance.node.width; 23 | this.node.y = cc.random0To1() * cc.Canvas.instance.node.height; 24 | } 25 | 26 | update(dt) { 27 | // let speed = 3; 28 | // this.node.x += cc.randomMinus1To1() * speed; 29 | // this.node.y += cc.randomMinus1To1() * speed; 30 | } 31 | 32 | public setIsCollision(isCollision) { 33 | this.isCollision = isCollision; 34 | if (isCollision) { 35 | this.node.color = cc.color(255, 0, 0); 36 | } else { 37 | this.node.color = cc.color(255, 255, 255); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #///////////////////////////////////////////////////////////////////////////// 2 | # Fireball Projects 3 | #///////////////////////////////////////////////////////////////////////////// 4 | 5 | library/ 6 | temp/ 7 | local/ 8 | build/ 9 | 10 | #///////////////////////////////////////////////////////////////////////////// 11 | # Logs and databases 12 | #///////////////////////////////////////////////////////////////////////////// 13 | 14 | *.log 15 | *.sql 16 | *.sqlite 17 | 18 | #///////////////////////////////////////////////////////////////////////////// 19 | # files for debugger 20 | #///////////////////////////////////////////////////////////////////////////// 21 | 22 | *.sln 23 | *.csproj 24 | *.pidb 25 | *.unityproj 26 | *.suo 27 | 28 | #///////////////////////////////////////////////////////////////////////////// 29 | # OS generated files 30 | #///////////////////////////////////////////////////////////////////////////// 31 | 32 | .DS_Store 33 | ehthumbs.db 34 | Thumbs.db 35 | 36 | #///////////////////////////////////////////////////////////////////////////// 37 | # exvim files 38 | #///////////////////////////////////////////////////////////////////////////// 39 | 40 | *UnityVS.meta 41 | *.err 42 | *.err.meta 43 | *.exvim 44 | *.exvim.meta 45 | *.vimentry 46 | *.vimentry.meta 47 | *.vimproject 48 | *.vimproject.meta 49 | .vimfiles.*/ 50 | .exvim.*/ 51 | quick_gen_project_*_autogen.bat 52 | quick_gen_project_*_autogen.bat.meta 53 | quick_gen_project_*_autogen.sh 54 | quick_gen_project_*_autogen.sh.meta 55 | .exvim.app 56 | 57 | #///////////////////////////////////////////////////////////////////////////// 58 | # webstorm files 59 | #///////////////////////////////////////////////////////////////////////////// 60 | 61 | .idea/ 62 | 63 | #////////////////////////// 64 | # VS Code 65 | #////////////////////////// 66 | 67 | .vscode/ -------------------------------------------------------------------------------- /assets/Prefabs/node.prefab: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "__type__": "cc.Prefab", 4 | "_name": "", 5 | "_objFlags": 0, 6 | "_rawFiles": null, 7 | "data": { 8 | "__id__": 1 9 | } 10 | }, 11 | { 12 | "__type__": "cc.Node", 13 | "_name": "node", 14 | "_objFlags": 0, 15 | "_parent": null, 16 | "_children": [], 17 | "_tag": -1, 18 | "_active": true, 19 | "_components": [ 20 | { 21 | "__id__": 2 22 | }, 23 | { 24 | "__id__": 3 25 | } 26 | ], 27 | "_prefab": { 28 | "__id__": 4 29 | }, 30 | "_id": "", 31 | "_opacity": 255, 32 | "_color": { 33 | "__type__": "cc.Color", 34 | "r": 255, 35 | "g": 255, 36 | "b": 255, 37 | "a": 255 38 | }, 39 | "_cascadeOpacityEnabled": true, 40 | "_anchorPoint": { 41 | "__type__": "cc.Vec2", 42 | "x": 0, 43 | "y": 0 44 | }, 45 | "_contentSize": { 46 | "__type__": "cc.Size", 47 | "width": 25, 48 | "height": 35 49 | }, 50 | "_rotationX": 0, 51 | "_rotationY": 0, 52 | "_scaleX": 1, 53 | "_scaleY": 1, 54 | "_position": { 55 | "__type__": "cc.Vec2", 56 | "x": 19, 57 | "y": 35 58 | }, 59 | "_skewX": 0, 60 | "_skewY": 0, 61 | "_localZOrder": 0, 62 | "_globalZOrder": 0, 63 | "_opacityModifyRGB": false, 64 | "groupIndex": 0 65 | }, 66 | { 67 | "__type__": "cc.Sprite", 68 | "_name": "", 69 | "_objFlags": 0, 70 | "node": { 71 | "__id__": 1 72 | }, 73 | "_enabled": true, 74 | "_spriteFrame": { 75 | "__uuid__": "31bc895a-c003-4566-a9f3-2e54ae1c17dc" 76 | }, 77 | "_type": 0, 78 | "_sizeMode": 0, 79 | "_fillType": 0, 80 | "_fillCenter": { 81 | "__type__": "cc.Vec2", 82 | "x": 0, 83 | "y": 0 84 | }, 85 | "_fillStart": 0, 86 | "_fillRange": 0, 87 | "_isTrimmedMode": true, 88 | "_srcBlendFactor": 770, 89 | "_dstBlendFactor": 771, 90 | "_atlas": null 91 | }, 92 | { 93 | "__type__": "9b77edqHtBNEY5Iy+RiiMmM", 94 | "_name": "", 95 | "_objFlags": 0, 96 | "node": { 97 | "__id__": 1 98 | }, 99 | "_enabled": true 100 | }, 101 | { 102 | "__type__": "cc.PrefabInfo", 103 | "root": { 104 | "__id__": 1 105 | }, 106 | "asset": { 107 | "__uuid__": "ebdae515-8caa-4855-bb1c-54a10d97127a" 108 | }, 109 | "fileId": "4bJTXftu5MMIhpfN6Gk6K8", 110 | "sync": false 111 | } 112 | ] -------------------------------------------------------------------------------- /assets/Script/Controller.ts: -------------------------------------------------------------------------------- 1 | // Learn TypeScript: 2 | // - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/typescript.html 3 | // - [English] http://www.cocos2d-x.org/docs/creator/en/scripting/typescript.html 4 | // Learn Attribute: 5 | // - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/reference/attributes.html 6 | // - [English] http://www.cocos2d-x.org/docs/creator/en/scripting/reference/attributes.html 7 | // Learn life-cycle callbacks: 8 | // - [Chinese] http://docs.cocos.com/creator/manual/zh/scripting/life-cycle-callbacks.html 9 | // - [English] http://www.cocos2d-x.org/docs/creator/en/scripting/life-cycle-callbacks.html 10 | 11 | const { ccclass, property } = cc._decorator; 12 | import { QuadTree, Node, BoundsNode } from "./QuadTree"; 13 | 14 | @ccclass 15 | export default class NewClass extends cc.Component { 16 | 17 | @property(cc.Prefab) 18 | nodePrefab: cc.Prefab = null; 19 | 20 | private nodes: Array = []; 21 | private tree: QuadTree = null; 22 | 23 | start() { 24 | var bounds = { 25 | x: 0, 26 | y: 0, 27 | width: cc.Canvas.instance.node.width, 28 | height: cc.Canvas.instance.node.height 29 | } 30 | this.tree = new QuadTree(bounds, true); 31 | 32 | for (let i = 0; i < 150; i++) { 33 | let newNode = cc.instantiate(this.nodePrefab); 34 | this.node.addChild(newNode); 35 | this.nodes.push(newNode); 36 | } 37 | this.tree.insert(this.nodes); 38 | } 39 | 40 | update(dt) { 41 | 42 | for (let i in this.nodes) { 43 | this.nodes[i].getComponent("Node").setIsCollision(false); 44 | } 45 | 46 | this.tree.clear(); 47 | this.tree.insert(this.nodes); 48 | 49 | for (let i in this.nodes) { 50 | let curNode = this.nodes[i]; 51 | let items = this.tree.retrieve(curNode); 52 | for (let i in items) { 53 | let item = items[i]; 54 | 55 | if (item.uuid == curNode.uuid) { 56 | continue; 57 | } 58 | 59 | let curScript = curNode.getComponent("Node"); 60 | let itemScript = item.getComponent("Node"); 61 | 62 | if (curScript.isCollision && itemScript.isCollision) { 63 | continue; 64 | } 65 | 66 | let isCollision = this.isCollision(curNode, item); 67 | 68 | if (!curScript.isCollision) { 69 | curScript.setIsCollision(isCollision); 70 | } 71 | 72 | if (!itemScript.isCollision) { 73 | itemScript.setIsCollision(isCollision); 74 | } 75 | } 76 | } 77 | } 78 | 79 | isCollision(node1, node2) { 80 | let node1Left = node1.x; 81 | let node2Left = node2.x; 82 | let node1Top = node1.y - node1.height; 83 | let node2Top = node2.y - node2.height; 84 | 85 | return node1Left < node2Left + node2.width && 86 | node1Left + node1.width > node2Left && 87 | node1Top < node2Top + node2.height && 88 | node1Top + node1.height > node2Top 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /assets/Scene/helloworld.fire: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "__type__": "cc.SceneAsset", 4 | "_name": "", 5 | "_objFlags": 0, 6 | "_rawFiles": null, 7 | "scene": { 8 | "__id__": 1 9 | } 10 | }, 11 | { 12 | "__type__": "cc.Scene", 13 | "_objFlags": 0, 14 | "_parent": null, 15 | "_children": [ 16 | { 17 | "__id__": 2 18 | }, 19 | { 20 | "__id__": 4 21 | } 22 | ], 23 | "_tag": -1, 24 | "_active": true, 25 | "_components": [], 26 | "_prefab": null, 27 | "_id": "2d2f792f-a40c-49bb-a189-ed176a246e49", 28 | "_opacity": 255, 29 | "_color": { 30 | "__type__": "cc.Color", 31 | "r": 255, 32 | "g": 255, 33 | "b": 255, 34 | "a": 255 35 | }, 36 | "_cascadeOpacityEnabled": true, 37 | "_anchorPoint": { 38 | "__type__": "cc.Vec2", 39 | "x": 0, 40 | "y": 0 41 | }, 42 | "_contentSize": { 43 | "__type__": "cc.Size", 44 | "width": 0, 45 | "height": 0 46 | }, 47 | "_localZOrder": 0, 48 | "_globalZOrder": 0, 49 | "_opacityModifyRGB": false, 50 | "groupIndex": 0, 51 | "autoReleaseAssets": false 52 | }, 53 | { 54 | "__type__": "cc.Node", 55 | "_name": "Canvas", 56 | "_objFlags": 0, 57 | "_parent": { 58 | "__id__": 1 59 | }, 60 | "_children": [], 61 | "_tag": -1, 62 | "_active": true, 63 | "_components": [ 64 | { 65 | "__id__": 3 66 | } 67 | ], 68 | "_prefab": null, 69 | "_id": "a286bbGknJLZpRpxROV6M94", 70 | "_opacity": 255, 71 | "_color": { 72 | "__type__": "cc.Color", 73 | "r": 252, 74 | "g": 252, 75 | "b": 252, 76 | "a": 255 77 | }, 78 | "_cascadeOpacityEnabled": true, 79 | "_anchorPoint": { 80 | "__type__": "cc.Vec2", 81 | "x": 0.5, 82 | "y": 0.5 83 | }, 84 | "_contentSize": { 85 | "__type__": "cc.Size", 86 | "width": 960, 87 | "height": 640 88 | }, 89 | "_rotationX": 0, 90 | "_rotationY": 0, 91 | "_scaleX": 1, 92 | "_scaleY": 1, 93 | "_position": { 94 | "__type__": "cc.Vec2", 95 | "x": 480, 96 | "y": 320 97 | }, 98 | "_skewX": 0, 99 | "_skewY": 0, 100 | "_localZOrder": 0, 101 | "_globalZOrder": 0, 102 | "_opacityModifyRGB": false, 103 | "groupIndex": 0 104 | }, 105 | { 106 | "__type__": "cc.Canvas", 107 | "_name": "", 108 | "_objFlags": 0, 109 | "node": { 110 | "__id__": 2 111 | }, 112 | "_enabled": true, 113 | "_designResolution": { 114 | "__type__": "cc.Size", 115 | "width": 960, 116 | "height": 640 117 | }, 118 | "_fitWidth": false, 119 | "_fitHeight": true 120 | }, 121 | { 122 | "__type__": "cc.Node", 123 | "_name": "Controller", 124 | "_objFlags": 0, 125 | "_parent": { 126 | "__id__": 1 127 | }, 128 | "_children": [], 129 | "_tag": -1, 130 | "_active": true, 131 | "_components": [ 132 | { 133 | "__id__": 5 134 | } 135 | ], 136 | "_prefab": null, 137 | "_id": "dbnxLkJStBfoPjfCB6PxlP", 138 | "_opacity": 255, 139 | "_color": { 140 | "__type__": "cc.Color", 141 | "r": 255, 142 | "g": 255, 143 | "b": 255, 144 | "a": 255 145 | }, 146 | "_cascadeOpacityEnabled": true, 147 | "_anchorPoint": { 148 | "__type__": "cc.Vec2", 149 | "x": 0.5, 150 | "y": 0.5 151 | }, 152 | "_contentSize": { 153 | "__type__": "cc.Size", 154 | "width": 0, 155 | "height": 0 156 | }, 157 | "_rotationX": 0, 158 | "_rotationY": 0, 159 | "_scaleX": 1, 160 | "_scaleY": 1, 161 | "_position": { 162 | "__type__": "cc.Vec2", 163 | "x": 0, 164 | "y": 0 165 | }, 166 | "_skewX": 0, 167 | "_skewY": 0, 168 | "_localZOrder": 0, 169 | "_globalZOrder": 0, 170 | "_opacityModifyRGB": false, 171 | "groupIndex": 0 172 | }, 173 | { 174 | "__type__": "89b7fU2pYRCyo0gHkzbOzYt", 175 | "_name": "", 176 | "_objFlags": 0, 177 | "node": { 178 | "__id__": 4 179 | }, 180 | "_enabled": true, 181 | "nodePrefab": { 182 | "__uuid__": "ebdae515-8caa-4855-bb1c-54a10d97127a" 183 | } 184 | } 185 | ] -------------------------------------------------------------------------------- /assets/Script/QuadTree.ts: -------------------------------------------------------------------------------- 1 | export class QuadTree { 2 | 3 | private root = null; 4 | 5 | public constructor(bounds, pointQuad, maxDepth?, maxChildren?) { 6 | var node; 7 | if (pointQuad) { 8 | node = new Node(bounds, 0, maxDepth, maxChildren); 9 | } else { 10 | node = new BoundsNode(bounds, 0, maxDepth, maxChildren); 11 | } 12 | this.root = node; 13 | } 14 | 15 | public insert(item) { 16 | if (item instanceof Array) { 17 | var len = item.length; 18 | for (var i = 0; i < len; i++) { 19 | this.root.insert(item[i]); 20 | } 21 | } else { 22 | this.root.insert(item); 23 | } 24 | } 25 | 26 | public clear() { 27 | this.root.clear(); 28 | } 29 | 30 | public retrieve(item): Array { 31 | var out = this.root.retrieve(item).slice(0); 32 | return out; 33 | } 34 | } 35 | 36 | 37 | export class Node { 38 | //subnodes 39 | protected nodes = null; 40 | 41 | //children contained directly in the node 42 | protected children = null; 43 | private _bounds = null; 44 | 45 | //read only 46 | protected _depth = 0; 47 | 48 | protected _maxChildren = 4; 49 | protected _maxDepth = 4; 50 | 51 | public static TOP_LEFT = 0; 52 | public static TOP_RIGHT = 1; 53 | public static BOTTOM_LEFT = 2; 54 | public static BOTTOM_RIGHT = 3; 55 | 56 | public constructor(bounds, depth, maxDepth, maxChildren) { 57 | this._bounds = bounds; 58 | this.children = []; 59 | this.nodes = []; 60 | 61 | if (maxChildren) { 62 | this._maxChildren = maxChildren; 63 | } 64 | 65 | if (maxDepth) { 66 | this._maxDepth = maxDepth; 67 | } 68 | 69 | if (depth) { 70 | this._depth = depth; 71 | } 72 | } 73 | 74 | public insert(item) { 75 | if (this.nodes.length) { 76 | var index = this._findIndex(item); 77 | 78 | this.nodes[index].insert(item); 79 | 80 | return; 81 | } 82 | 83 | this.children.push(item); 84 | 85 | var len = this.children.length; 86 | if (!(this._depth >= this._maxDepth) && 87 | len > this._maxChildren) { 88 | 89 | this.subdivide(); 90 | 91 | var i; 92 | for (i = 0; i < len; i++) { 93 | this.insert(this.children[i]); 94 | } 95 | 96 | this.children.length = 0; 97 | } if (this.nodes.length) { 98 | var index = this._findIndex(item); 99 | 100 | this.nodes[index].insert(item); 101 | 102 | return; 103 | } 104 | 105 | this.children.push(item); 106 | 107 | var len = this.children.length; 108 | if (!(this._depth >= this._maxDepth) && 109 | len > this._maxChildren) { 110 | 111 | this.subdivide(); 112 | 113 | var i; 114 | for (i = 0; i < len; i++) { 115 | this.insert(this.children[i]); 116 | } 117 | 118 | this.children.length = 0; 119 | } 120 | } 121 | 122 | public retrieve(item) { 123 | if (this.nodes.length) { 124 | var index = this._findIndex(item); 125 | 126 | return this.nodes[index].retrieve(item); 127 | } 128 | 129 | return this.children; 130 | } 131 | 132 | public _findIndex(item) { 133 | var b = this._bounds; 134 | var left = (item.x > b.x + b.width / 2) ? false : true; 135 | var top = (item.y > b.y + b.height / 2) ? false : true; 136 | 137 | //top left 138 | var index = Node.TOP_LEFT; 139 | if (left) { 140 | //left side 141 | if (!top) { 142 | //bottom left 143 | index = Node.BOTTOM_LEFT; 144 | } 145 | } else { 146 | //right side 147 | if (top) { 148 | //top right 149 | index = Node.TOP_RIGHT; 150 | } else { 151 | //bottom right 152 | index = Node.BOTTOM_RIGHT; 153 | } 154 | } 155 | 156 | return index; 157 | } 158 | 159 | public subdivide() { 160 | var depth = this._depth + 1; 161 | 162 | var bx = this._bounds.x; 163 | var by = this._bounds.y; 164 | 165 | //floor the values 166 | var b_w_h = (this._bounds.width / 2); //todo: Math.floor? 167 | var b_h_h = (this._bounds.height / 2); 168 | var bx_b_w_h = bx + b_w_h; 169 | var by_b_h_h = by + b_h_h; 170 | 171 | //top left 172 | this.nodes[Node.TOP_LEFT] = new Node({ 173 | x: bx, 174 | y: by, 175 | width: b_w_h, 176 | height: b_h_h 177 | }, 178 | depth, this._maxDepth, this._maxChildren); 179 | 180 | //top right 181 | this.nodes[Node.TOP_RIGHT] = new Node({ 182 | x: bx_b_w_h, 183 | y: by, 184 | width: b_w_h, 185 | height: b_h_h 186 | }, 187 | depth, this._maxDepth, this._maxChildren); 188 | 189 | //bottom left 190 | this.nodes[Node.BOTTOM_LEFT] = new Node({ 191 | x: bx, 192 | y: by_b_h_h, 193 | width: b_w_h, 194 | height: b_h_h 195 | }, 196 | depth, this._maxDepth, this._maxChildren); 197 | 198 | 199 | //bottom right 200 | this.nodes[Node.BOTTOM_RIGHT] = new Node({ 201 | x: bx_b_w_h, 202 | y: by_b_h_h, 203 | width: b_w_h, 204 | height: b_h_h 205 | }, 206 | depth, this._maxDepth, this._maxChildren); 207 | } 208 | 209 | public clear() { 210 | this.children.length = 0; 211 | 212 | var len = this.nodes.length; 213 | 214 | var i; 215 | for (i = 0; i < len; i++) { 216 | this.nodes[i].clear(); 217 | } 218 | 219 | this.nodes.length = 0; 220 | } 221 | } 222 | 223 | export class BoundsNode extends Node { 224 | 225 | protected _stuckChildren = null; 226 | protected _out = []; 227 | 228 | public constructor(bounds, depth, maxChildren, maxDepth) { 229 | super(bounds, depth, maxChildren, maxDepth); 230 | } 231 | 232 | public insert(item) { 233 | if (this.nodes.length) { 234 | var index = this._findIndex(item); 235 | var node = this.nodes[index]; 236 | 237 | //todo: make _bounds bounds 238 | if (item.x >= node._bounds.x && 239 | item.x + item.width <= node._bounds.x + node._bounds.width && 240 | item.y >= node._bounds.y && 241 | item.y + item.height <= node._bounds.y + node._bounds.height) { 242 | 243 | this.nodes[index].insert(item); 244 | 245 | } else { 246 | this._stuckChildren.push(item); 247 | } 248 | 249 | return; 250 | } 251 | 252 | this.children.push(item); 253 | 254 | var len = this.children.length; 255 | 256 | if (!(this._depth >= this._maxDepth) && 257 | len > this._maxChildren) { 258 | 259 | this.subdivide(); 260 | 261 | var i; 262 | for (i = 0; i < len; i++) { 263 | this.insert(this.children[i]); 264 | } 265 | 266 | this.children.length = 0; 267 | } 268 | } 269 | 270 | public getChildren() { 271 | return this.children.concat(this._stuckChildren); 272 | } 273 | 274 | public retrieve(item) { 275 | var out = this._out; 276 | out.length = 0; 277 | if (this.nodes.length) { 278 | var index = this._findIndex(item); 279 | var node = this.nodes[index]; 280 | 281 | if (item.x >= node._bounds.x && 282 | item.x + item.width <= node._bounds.x + node._bounds.width && 283 | item.y >= node._bounds.y && 284 | item.y + item.height <= node._bounds.y + node._bounds.height) { 285 | 286 | out.push.apply(out, this.nodes[index].retrieve(item)); 287 | } else { 288 | //Part of the item are overlapping multiple child nodes. For each of the overlapping nodes, return all containing objects. 289 | 290 | if (item.x <= this.nodes[Node.TOP_RIGHT]._bounds.x) { 291 | if (item.y <= this.nodes[Node.BOTTOM_LEFT]._bounds.y) { 292 | out.push.apply(out, this.nodes[Node.TOP_LEFT].getAllContent()); 293 | } 294 | 295 | if (item.y + item.height > this.nodes[Node.BOTTOM_LEFT]._bounds.y) { 296 | out.push.apply(out, this.nodes[Node.BOTTOM_LEFT].getAllContent()); 297 | } 298 | } 299 | 300 | if (item.x + item.width > this.nodes[Node.TOP_RIGHT]._bounds.x) {//position+width bigger than middle x 301 | if (item.y <= this.nodes[Node.BOTTOM_RIGHT]._bounds.y) { 302 | out.push.apply(out, this.nodes[Node.TOP_RIGHT].getAllContent()); 303 | } 304 | 305 | if (item.y + item.height > this.nodes[Node.BOTTOM_RIGHT]._bounds.y) { 306 | out.push.apply(out, this.nodes[Node.BOTTOM_RIGHT].getAllContent()); 307 | } 308 | } 309 | } 310 | } 311 | 312 | out.push.apply(out, this._stuckChildren); 313 | out.push.apply(out, this.children); 314 | 315 | return out; 316 | } 317 | 318 | public getAllContent() { 319 | var out = this._out; 320 | if (this.nodes.length) { 321 | 322 | var i; 323 | for (i = 0; i < this.nodes.length; i++) { 324 | this.nodes[i].getAllContent(); 325 | } 326 | } 327 | out.push.apply(out, this._stuckChildren); 328 | out.push.apply(out, this.children); 329 | return out; 330 | } 331 | 332 | public clear() { 333 | this._stuckChildren.length = 0; 334 | 335 | //array 336 | this.children.length = 0; 337 | 338 | var len = this.nodes.length; 339 | 340 | if (!len) { 341 | return; 342 | } 343 | 344 | var i; 345 | for (i = 0; i < len; i++) { 346 | this.nodes[i].clear(); 347 | } 348 | 349 | //array 350 | this.nodes.length = 0; 351 | } 352 | } 353 | --------------------------------------------------------------------------------