├── 1.png ├── 1.png.meta ├── 2.png ├── 2.png.meta ├── 563.gif ├── 563.gif.meta ├── README.md ├── README.md.meta ├── Scene.meta ├── Scene ├── helloworld - 001.fire ├── helloworld - 001.fire.meta ├── helloworld.fire └── helloworld.fire.meta ├── Script.meta ├── Script ├── Helloworld.ts ├── Helloworld.ts.meta ├── JPS.ts └── JPS.ts.meta ├── Texture.meta ├── Texture ├── HelloWorld.png ├── HelloWorld.png.meta ├── singleColor.png └── singleColor.png.meta ├── creator.d.ts ├── creator.d.ts.meta ├── demo.gif ├── demo.gif.meta ├── global.d.ts ├── global.d.ts.meta ├── tsconfig.json └── tsconfig.json.meta /1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microcisco/jpsFindPath/a66370ef89b17b6d0bb9a632eff1a088cdbc20f9/1.png -------------------------------------------------------------------------------- /1.png.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "2.3.7", 3 | "uuid": "dd500e19-2e91-499f-99b7-0fdb2e8c04e6", 4 | "importer": "texture", 5 | "type": "sprite", 6 | "wrapMode": "clamp", 7 | "filterMode": "bilinear", 8 | "premultiplyAlpha": false, 9 | "genMipmaps": false, 10 | "packable": true, 11 | "width": 717, 12 | "height": 464, 13 | "platformSettings": {}, 14 | "subMetas": { 15 | "1": { 16 | "ver": "1.0.6", 17 | "uuid": "cfbe9cf2-aa97-4737-b4c7-cc297d688a92", 18 | "importer": "sprite-frame", 19 | "rawTextureUuid": "dd500e19-2e91-499f-99b7-0fdb2e8c04e6", 20 | "trimType": "auto", 21 | "trimThreshold": 1, 22 | "rotated": false, 23 | "offsetX": 0, 24 | "offsetY": 0, 25 | "trimX": 0, 26 | "trimY": 0, 27 | "width": 717, 28 | "height": 464, 29 | "rawWidth": 717, 30 | "rawHeight": 464, 31 | "borderTop": 0, 32 | "borderBottom": 0, 33 | "borderLeft": 0, 34 | "borderRight": 0, 35 | "subMetas": {} 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microcisco/jpsFindPath/a66370ef89b17b6d0bb9a632eff1a088cdbc20f9/2.png -------------------------------------------------------------------------------- /2.png.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "2.3.7", 3 | "uuid": "14fa49e0-4f9e-45ae-b792-c53ae3298e34", 4 | "importer": "texture", 5 | "type": "sprite", 6 | "wrapMode": "clamp", 7 | "filterMode": "bilinear", 8 | "premultiplyAlpha": false, 9 | "genMipmaps": false, 10 | "packable": true, 11 | "width": 1062, 12 | "height": 438, 13 | "platformSettings": {}, 14 | "subMetas": { 15 | "2": { 16 | "ver": "1.0.6", 17 | "uuid": "8388f92c-71fa-42ae-bbb8-fb5ec84155d5", 18 | "importer": "sprite-frame", 19 | "rawTextureUuid": "14fa49e0-4f9e-45ae-b792-c53ae3298e34", 20 | "trimType": "auto", 21 | "trimThreshold": 1, 22 | "rotated": false, 23 | "offsetX": 0, 24 | "offsetY": 0, 25 | "trimX": 0, 26 | "trimY": 0, 27 | "width": 1062, 28 | "height": 438, 29 | "rawWidth": 1062, 30 | "rawHeight": 438, 31 | "borderTop": 0, 32 | "borderBottom": 0, 33 | "borderLeft": 0, 34 | "borderRight": 0, 35 | "subMetas": {} 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /563.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microcisco/jpsFindPath/a66370ef89b17b6d0bb9a632eff1a088cdbc20f9/563.gif -------------------------------------------------------------------------------- /563.gif.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.3", 3 | "uuid": "4b56560e-3220-4dad-8561-38a94b0437f1", 4 | "importer": "asset", 5 | "subMetas": {} 6 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cocos create JPS寻路(跳点寻路)算法TS版本 2 | *** 3 | - 简介 4 | ```$xslt 5 | + 最近又研究了一下跳点寻路所以又来分享给大家了接口什么的没变,此外还有a星什么的也有自己翻阅哈 6 | + 具体原理参考 https://zhuanlan.zhihu.com/p/25093275 7 | ``` 8 | ![avatar](https://github.com/microcisco/jpsFindPath/blob/master/demo.gif) 9 | 10 | 11 | - 快速使用 12 | ```$xslt 13 | private customGenerateLogicMap() { 14 | let mapData = AutoFindPath.formatToMapData(this.map, this.map.children[0].width); 15 | let autoFindPath = new AutoFindPath(mapData); 16 | this.autoFindPath = autoFindPath; 17 | //更新当前地图里所有障碍物 18 | for (const child of this.obstacles.children) autoFindPath.updateMap(child); 19 | } 20 | 21 | private searchPath() { 22 | let pos0 = cc.find('Canvas/起点'); 23 | let pos1 = cc.find('Canvas/终点'); 24 | let paths = this.autoFindPath.gridPositionConvertGameObjectPosition(this.autoFindPath.findGridPath(pos0, pos1, models.normal), 25 | cc.v2(0.5, 0.5), cc.Vec2); 26 | if (paths.length === 0) console.log('死路'); 27 | for (let i = 0; i < paths.length; i++) { 28 | this.scheduleOnce(() => { 29 | pos0.runAction(cc.moveTo(0.5, paths[i])); 30 | }, i * 0.5); 31 | } 32 | } 33 | 34 | start() { 35 | this.customGenerateLogicMap(); 36 | this.searchPath(); 37 | } 38 | ``` 39 | ![avatar](https://github.com/microcisco/astartForTS/blob/master/1.png) 40 | 41 | 42 | ![avatar](https://github.com/microcisco/astartForTS/blob/master/2.png) 43 | 44 | 45 | --- 46 | - 扩展 47 | ```$xslt 48 | 本项目还可以动态的添加和移除障碍物(比如建筑物被攻击后可以移动到该位置,以及在游戏过程中添加建筑),更多细节可以看核心类AutoFindPath 49 | 1. 移除障碍物的方法是 50 | autoFindPath.removeFixObstacle(...obstacles); 51 | 1. 添加障碍物的方法是 52 | autoFindPath.updateMap(...obstacles); 53 | ``` 54 | --- 55 | - 结尾 56 | ```$xslt 57 | 有问题欢迎大家提issue 58 | ``` 59 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "2.0.2", 3 | "uuid": "94cf5c6f-e988-4541-abf9-e631616c9ddc", 4 | "importer": "markdown", 5 | "subMetas": {} 6 | } -------------------------------------------------------------------------------- /Scene.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.1.3", 3 | "uuid": "bda06b15-0aa5-4b19-9748-b3da6ed32a2c", 4 | "importer": "folder", 5 | "isBundle": false, 6 | "bundleName": "", 7 | "priority": 1, 8 | "compressionType": {}, 9 | "optimizeHotUpdate": {}, 10 | "inlineSpriteFrames": {}, 11 | "isRemoteBundle": {}, 12 | "subMetas": {} 13 | } -------------------------------------------------------------------------------- /Scene/helloworld - 001.fire.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.3.2", 3 | "uuid": "b07943b6-a580-4a28-81f6-7b9b7779dde9", 4 | "importer": "scene", 5 | "asyncLoadAssets": false, 6 | "autoReleaseAssets": false, 7 | "subMetas": {} 8 | } -------------------------------------------------------------------------------- /Scene/helloworld.fire: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "__type__": "cc.SceneAsset", 4 | "_name": "", 5 | "_objFlags": 0, 6 | "_native": "", 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 | "_active": true, 21 | "_components": [], 22 | "_prefab": null, 23 | "_opacity": 255, 24 | "_color": { 25 | "__type__": "cc.Color", 26 | "r": 255, 27 | "g": 255, 28 | "b": 255, 29 | "a": 255 30 | }, 31 | "_contentSize": { 32 | "__type__": "cc.Size", 33 | "width": 0, 34 | "height": 0 35 | }, 36 | "_anchorPoint": { 37 | "__type__": "cc.Vec2", 38 | "x": 0, 39 | "y": 0 40 | }, 41 | "_trs": { 42 | "__type__": "TypedArray", 43 | "ctor": "Float64Array", 44 | "array": [ 45 | 0, 46 | 0, 47 | 0, 48 | 0, 49 | 0, 50 | 0, 51 | 1, 52 | 1, 53 | 1, 54 | 1 55 | ] 56 | }, 57 | "_is3DNode": true, 58 | "_groupIndex": 0, 59 | "groupIndex": 0, 60 | "autoReleaseAssets": false, 61 | "_id": "805f9e76-6558-4db4-96ad-23031a3f906a" 62 | }, 63 | { 64 | "__type__": "cc.Node", 65 | "_name": "Canvas", 66 | "_objFlags": 0, 67 | "_parent": { 68 | "__id__": 1 69 | }, 70 | "_children": [ 71 | { 72 | "__id__": 3 73 | }, 74 | { 75 | "__id__": 5 76 | }, 77 | { 78 | "__id__": 19 79 | }, 80 | { 81 | "__id__": 23 82 | }, 83 | { 84 | "__id__": 25 85 | }, 86 | { 87 | "__id__": 27 88 | } 89 | ], 90 | "_active": true, 91 | "_components": [ 92 | { 93 | "__id__": 35 94 | }, 95 | { 96 | "__id__": 36 97 | }, 98 | { 99 | "__id__": 37 100 | } 101 | ], 102 | "_prefab": null, 103 | "_opacity": 255, 104 | "_color": { 105 | "__type__": "cc.Color", 106 | "r": 252, 107 | "g": 252, 108 | "b": 252, 109 | "a": 255 110 | }, 111 | "_contentSize": { 112 | "__type__": "cc.Size", 113 | "width": 1280, 114 | "height": 720 115 | }, 116 | "_anchorPoint": { 117 | "__type__": "cc.Vec2", 118 | "x": 0.5, 119 | "y": 0.5 120 | }, 121 | "_trs": { 122 | "__type__": "TypedArray", 123 | "ctor": "Float64Array", 124 | "array": [ 125 | 640, 126 | 360, 127 | 0, 128 | 0, 129 | 0, 130 | 0, 131 | 1, 132 | 1, 133 | 1, 134 | 1 135 | ] 136 | }, 137 | "_eulerAngles": { 138 | "__type__": "cc.Vec3", 139 | "x": 0, 140 | "y": 0, 141 | "z": 0 142 | }, 143 | "_skewX": 0, 144 | "_skewY": 0, 145 | "_is3DNode": false, 146 | "_groupIndex": 0, 147 | "groupIndex": 0, 148 | "_id": "a286bbGknJLZpRpxROV6M94" 149 | }, 150 | { 151 | "__type__": "cc.Node", 152 | "_name": "Main Camera", 153 | "_objFlags": 0, 154 | "_parent": { 155 | "__id__": 2 156 | }, 157 | "_children": [], 158 | "_active": true, 159 | "_components": [ 160 | { 161 | "__id__": 4 162 | } 163 | ], 164 | "_prefab": null, 165 | "_opacity": 255, 166 | "_color": { 167 | "__type__": "cc.Color", 168 | "r": 255, 169 | "g": 255, 170 | "b": 255, 171 | "a": 255 172 | }, 173 | "_contentSize": { 174 | "__type__": "cc.Size", 175 | "width": 0, 176 | "height": 0 177 | }, 178 | "_anchorPoint": { 179 | "__type__": "cc.Vec2", 180 | "x": 0.5, 181 | "y": 0.5 182 | }, 183 | "_trs": { 184 | "__type__": "TypedArray", 185 | "ctor": "Float64Array", 186 | "array": [ 187 | 0, 188 | 0, 189 | 0, 190 | 0, 191 | 0, 192 | 0, 193 | 1, 194 | 1, 195 | 1, 196 | 1 197 | ] 198 | }, 199 | "_eulerAngles": { 200 | "__type__": "cc.Vec3", 201 | "x": 0, 202 | "y": 0, 203 | "z": 0 204 | }, 205 | "_skewX": 0, 206 | "_skewY": 0, 207 | "_is3DNode": false, 208 | "_groupIndex": 0, 209 | "groupIndex": 0, 210 | "_id": "4f/SH6T6lBnpxZahBdPjQW" 211 | }, 212 | { 213 | "__type__": "cc.Camera", 214 | "_name": "", 215 | "_objFlags": 0, 216 | "node": { 217 | "__id__": 3 218 | }, 219 | "_enabled": true, 220 | "_cullingMask": 4294967295, 221 | "_clearFlags": 7, 222 | "_backgroundColor": { 223 | "__type__": "cc.Color", 224 | "r": 0, 225 | "g": 0, 226 | "b": 0, 227 | "a": 255 228 | }, 229 | "_depth": -1, 230 | "_zoomRatio": 1, 231 | "_targetTexture": null, 232 | "_fov": 60, 233 | "_orthoSize": 10, 234 | "_nearClip": 1, 235 | "_farClip": 4096, 236 | "_ortho": true, 237 | "_rect": { 238 | "__type__": "cc.Rect", 239 | "x": 0, 240 | "y": 0, 241 | "width": 1, 242 | "height": 1 243 | }, 244 | "_renderStages": 1, 245 | "_alignWithScreen": true, 246 | "_id": "c4pILQHV1M6Lz2ZS/VbRv3" 247 | }, 248 | { 249 | "__type__": "cc.Node", 250 | "_name": "map", 251 | "_objFlags": 0, 252 | "_parent": { 253 | "__id__": 2 254 | }, 255 | "_children": [ 256 | { 257 | "__id__": 6 258 | } 259 | ], 260 | "_active": true, 261 | "_components": [ 262 | { 263 | "__id__": 16 264 | }, 265 | { 266 | "__id__": 17 267 | }, 268 | { 269 | "__id__": 18 270 | } 271 | ], 272 | "_prefab": null, 273 | "_opacity": 255, 274 | "_color": { 275 | "__type__": "cc.Color", 276 | "r": 27, 277 | "g": 38, 278 | "b": 46, 279 | "a": 255 280 | }, 281 | "_contentSize": { 282 | "__type__": "cc.Size", 283 | "width": 1281, 284 | "height": 721 285 | }, 286 | "_anchorPoint": { 287 | "__type__": "cc.Vec2", 288 | "x": 0.5, 289 | "y": 0.5 290 | }, 291 | "_trs": { 292 | "__type__": "TypedArray", 293 | "ctor": "Float64Array", 294 | "array": [ 295 | 0, 296 | 0, 297 | 0, 298 | 0, 299 | 0, 300 | 0, 301 | 1, 302 | 1, 303 | 1, 304 | 1 305 | ] 306 | }, 307 | "_eulerAngles": { 308 | "__type__": "cc.Vec3", 309 | "x": 0, 310 | "y": 0, 311 | "z": 0 312 | }, 313 | "_skewX": 0, 314 | "_skewY": 0, 315 | "_is3DNode": false, 316 | "_groupIndex": 0, 317 | "groupIndex": 0, 318 | "_id": "e2e0crkOLxGrpMxpbC4iQg1" 319 | }, 320 | { 321 | "__type__": "cc.Node", 322 | "_name": "New Sprite(Splash) copy", 323 | "_objFlags": 0, 324 | "_parent": { 325 | "__id__": 5 326 | }, 327 | "_children": [ 328 | { 329 | "__id__": 7 330 | }, 331 | { 332 | "__id__": 9 333 | }, 334 | { 335 | "__id__": 11 336 | }, 337 | { 338 | "__id__": 13 339 | } 340 | ], 341 | "_active": true, 342 | "_components": [ 343 | { 344 | "__id__": 15 345 | } 346 | ], 347 | "_prefab": null, 348 | "_opacity": 255, 349 | "_color": { 350 | "__type__": "cc.Color", 351 | "r": 255, 352 | "g": 255, 353 | "b": 255, 354 | "a": 255 355 | }, 356 | "_contentSize": { 357 | "__type__": "cc.Size", 358 | "width": 120, 359 | "height": 120 360 | }, 361 | "_anchorPoint": { 362 | "__type__": "cc.Vec2", 363 | "x": 0.5, 364 | "y": 0.5 365 | }, 366 | "_trs": { 367 | "__type__": "TypedArray", 368 | "ctor": "Float64Array", 369 | "array": [ 370 | -630.499998, 371 | -350.499998, 372 | 0, 373 | 0, 374 | 0, 375 | 0, 376 | 1, 377 | 0.1666667, 378 | 0.1666667, 379 | 1 380 | ] 381 | }, 382 | "_eulerAngles": { 383 | "__type__": "cc.Vec3", 384 | "x": 0, 385 | "y": 0, 386 | "z": 0 387 | }, 388 | "_skewX": 0, 389 | "_skewY": 0, 390 | "_is3DNode": false, 391 | "_groupIndex": 0, 392 | "groupIndex": 0, 393 | "_id": "b7lFs5E1RMBqtghmfpGnxx" 394 | }, 395 | { 396 | "__type__": "cc.Node", 397 | "_name": "New Sprite(Splash)", 398 | "_objFlags": 0, 399 | "_parent": { 400 | "__id__": 6 401 | }, 402 | "_children": [], 403 | "_active": true, 404 | "_components": [ 405 | { 406 | "__id__": 8 407 | } 408 | ], 409 | "_prefab": null, 410 | "_opacity": 255, 411 | "_color": { 412 | "__type__": "cc.Color", 413 | "r": 230, 414 | "g": 85, 415 | "b": 17, 416 | "a": 255 417 | }, 418 | "_contentSize": { 419 | "__type__": "cc.Size", 420 | "width": 120, 421 | "height": 10 422 | }, 423 | "_anchorPoint": { 424 | "__type__": "cc.Vec2", 425 | "x": 0.5, 426 | "y": 0.5 427 | }, 428 | "_trs": { 429 | "__type__": "TypedArray", 430 | "ctor": "Float64Array", 431 | "array": [ 432 | 0, 433 | -54.982, 434 | 0, 435 | 0, 436 | 0, 437 | 0, 438 | 1, 439 | 1, 440 | 1, 441 | 1 442 | ] 443 | }, 444 | "_eulerAngles": { 445 | "__type__": "cc.Vec3", 446 | "x": 0, 447 | "y": 0, 448 | "z": 0 449 | }, 450 | "_skewX": 0, 451 | "_skewY": 0, 452 | "_is3DNode": false, 453 | "_groupIndex": 0, 454 | "groupIndex": 0, 455 | "_id": "61MHvgB4RC355lQ8twBIMo" 456 | }, 457 | { 458 | "__type__": "cc.Sprite", 459 | "_name": "", 460 | "_objFlags": 0, 461 | "node": { 462 | "__id__": 7 463 | }, 464 | "_enabled": true, 465 | "_materials": [ 466 | { 467 | "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" 468 | } 469 | ], 470 | "_srcBlendFactor": 770, 471 | "_dstBlendFactor": 771, 472 | "_spriteFrame": { 473 | "__uuid__": "a23235d1-15db-4b95-8439-a2e005bfff91" 474 | }, 475 | "_type": 0, 476 | "_sizeMode": 0, 477 | "_fillType": 0, 478 | "_fillCenter": { 479 | "__type__": "cc.Vec2", 480 | "x": 0, 481 | "y": 0 482 | }, 483 | "_fillStart": 0, 484 | "_fillRange": 0, 485 | "_isTrimmedMode": true, 486 | "_atlas": null, 487 | "_id": "a6fo1CZmJCEqw0yPeFe0l3" 488 | }, 489 | { 490 | "__type__": "cc.Node", 491 | "_name": "New Sprite(Splash) copy", 492 | "_objFlags": 0, 493 | "_parent": { 494 | "__id__": 6 495 | }, 496 | "_children": [], 497 | "_active": true, 498 | "_components": [ 499 | { 500 | "__id__": 10 501 | } 502 | ], 503 | "_prefab": null, 504 | "_opacity": 255, 505 | "_color": { 506 | "__type__": "cc.Color", 507 | "r": 230, 508 | "g": 85, 509 | "b": 17, 510 | "a": 255 511 | }, 512 | "_contentSize": { 513 | "__type__": "cc.Size", 514 | "width": 120, 515 | "height": 10 516 | }, 517 | "_anchorPoint": { 518 | "__type__": "cc.Vec2", 519 | "x": 0.5, 520 | "y": 0.5 521 | }, 522 | "_trs": { 523 | "__type__": "TypedArray", 524 | "ctor": "Float64Array", 525 | "array": [ 526 | 0, 527 | 54.864, 528 | 0, 529 | 0, 530 | 0, 531 | 0, 532 | 1, 533 | 1, 534 | 1, 535 | 1 536 | ] 537 | }, 538 | "_eulerAngles": { 539 | "__type__": "cc.Vec3", 540 | "x": 0, 541 | "y": 0, 542 | "z": 0 543 | }, 544 | "_skewX": 0, 545 | "_skewY": 0, 546 | "_is3DNode": false, 547 | "_groupIndex": 0, 548 | "groupIndex": 0, 549 | "_id": "7djMrdtmlP57t6C2WbcHdQ" 550 | }, 551 | { 552 | "__type__": "cc.Sprite", 553 | "_name": "", 554 | "_objFlags": 0, 555 | "node": { 556 | "__id__": 9 557 | }, 558 | "_enabled": true, 559 | "_materials": [ 560 | { 561 | "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" 562 | } 563 | ], 564 | "_srcBlendFactor": 770, 565 | "_dstBlendFactor": 771, 566 | "_spriteFrame": { 567 | "__uuid__": "a23235d1-15db-4b95-8439-a2e005bfff91" 568 | }, 569 | "_type": 0, 570 | "_sizeMode": 0, 571 | "_fillType": 0, 572 | "_fillCenter": { 573 | "__type__": "cc.Vec2", 574 | "x": 0, 575 | "y": 0 576 | }, 577 | "_fillStart": 0, 578 | "_fillRange": 0, 579 | "_isTrimmedMode": true, 580 | "_atlas": null, 581 | "_id": "7a5kiis6ZPMJHoux+UpnJj" 582 | }, 583 | { 584 | "__type__": "cc.Node", 585 | "_name": "New Sprite(Splash) copy", 586 | "_objFlags": 0, 587 | "_parent": { 588 | "__id__": 6 589 | }, 590 | "_children": [], 591 | "_active": true, 592 | "_components": [ 593 | { 594 | "__id__": 12 595 | } 596 | ], 597 | "_prefab": null, 598 | "_opacity": 255, 599 | "_color": { 600 | "__type__": "cc.Color", 601 | "r": 230, 602 | "g": 85, 603 | "b": 17, 604 | "a": 255 605 | }, 606 | "_contentSize": { 607 | "__type__": "cc.Size", 608 | "width": 120, 609 | "height": 10 610 | }, 611 | "_anchorPoint": { 612 | "__type__": "cc.Vec2", 613 | "x": 0.5, 614 | "y": 0.5 615 | }, 616 | "_trs": { 617 | "__type__": "TypedArray", 618 | "ctor": "Float64Array", 619 | "array": [ 620 | 54.905, 621 | -0.169, 622 | 0, 623 | 0, 624 | 0, 625 | 0.7071067811865475, 626 | 0.7071067811865476, 627 | 1, 628 | 1, 629 | 1 630 | ] 631 | }, 632 | "_eulerAngles": { 633 | "__type__": "cc.Vec3", 634 | "x": 0, 635 | "y": 0, 636 | "z": 90 637 | }, 638 | "_skewX": 0, 639 | "_skewY": 0, 640 | "_is3DNode": false, 641 | "_groupIndex": 0, 642 | "groupIndex": 0, 643 | "_id": "2ev41b49RFzoO1rYhTWJQv" 644 | }, 645 | { 646 | "__type__": "cc.Sprite", 647 | "_name": "", 648 | "_objFlags": 0, 649 | "node": { 650 | "__id__": 11 651 | }, 652 | "_enabled": true, 653 | "_materials": [ 654 | { 655 | "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" 656 | } 657 | ], 658 | "_srcBlendFactor": 770, 659 | "_dstBlendFactor": 771, 660 | "_spriteFrame": { 661 | "__uuid__": "a23235d1-15db-4b95-8439-a2e005bfff91" 662 | }, 663 | "_type": 0, 664 | "_sizeMode": 0, 665 | "_fillType": 0, 666 | "_fillCenter": { 667 | "__type__": "cc.Vec2", 668 | "x": 0, 669 | "y": 0 670 | }, 671 | "_fillStart": 0, 672 | "_fillRange": 0, 673 | "_isTrimmedMode": true, 674 | "_atlas": null, 675 | "_id": "22ojtpK2ZLdI6GnwWymbju" 676 | }, 677 | { 678 | "__type__": "cc.Node", 679 | "_name": "New Sprite(Splash) copy", 680 | "_objFlags": 0, 681 | "_parent": { 682 | "__id__": 6 683 | }, 684 | "_children": [], 685 | "_active": true, 686 | "_components": [ 687 | { 688 | "__id__": 14 689 | } 690 | ], 691 | "_prefab": null, 692 | "_opacity": 255, 693 | "_color": { 694 | "__type__": "cc.Color", 695 | "r": 230, 696 | "g": 85, 697 | "b": 17, 698 | "a": 255 699 | }, 700 | "_contentSize": { 701 | "__type__": "cc.Size", 702 | "width": 120, 703 | "height": 10 704 | }, 705 | "_anchorPoint": { 706 | "__type__": "cc.Vec2", 707 | "x": 0.5, 708 | "y": 0.5 709 | }, 710 | "_trs": { 711 | "__type__": "TypedArray", 712 | "ctor": "Float64Array", 713 | "array": [ 714 | -54.906, 715 | -0.169, 716 | 0, 717 | 0, 718 | 0, 719 | 0.7071067811865475, 720 | 0.7071067811865476, 721 | 1, 722 | 1, 723 | 1 724 | ] 725 | }, 726 | "_eulerAngles": { 727 | "__type__": "cc.Vec3", 728 | "x": 0, 729 | "y": 0, 730 | "z": 90 731 | }, 732 | "_skewX": 0, 733 | "_skewY": 0, 734 | "_is3DNode": false, 735 | "_groupIndex": 0, 736 | "groupIndex": 0, 737 | "_id": "91vF1OB3VIjrqr4JeyKrft" 738 | }, 739 | { 740 | "__type__": "cc.Sprite", 741 | "_name": "", 742 | "_objFlags": 0, 743 | "node": { 744 | "__id__": 13 745 | }, 746 | "_enabled": true, 747 | "_materials": [ 748 | { 749 | "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" 750 | } 751 | ], 752 | "_srcBlendFactor": 770, 753 | "_dstBlendFactor": 771, 754 | "_spriteFrame": { 755 | "__uuid__": "a23235d1-15db-4b95-8439-a2e005bfff91" 756 | }, 757 | "_type": 0, 758 | "_sizeMode": 0, 759 | "_fillType": 0, 760 | "_fillCenter": { 761 | "__type__": "cc.Vec2", 762 | "x": 0, 763 | "y": 0 764 | }, 765 | "_fillStart": 0, 766 | "_fillRange": 0, 767 | "_isTrimmedMode": true, 768 | "_atlas": null, 769 | "_id": "daoYdGJ41PrbjjWGOBWIr3" 770 | }, 771 | { 772 | "__type__": "cc.Sprite", 773 | "_name": "", 774 | "_objFlags": 0, 775 | "node": { 776 | "__id__": 6 777 | }, 778 | "_enabled": true, 779 | "_materials": [ 780 | { 781 | "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" 782 | } 783 | ], 784 | "_srcBlendFactor": 770, 785 | "_dstBlendFactor": 771, 786 | "_spriteFrame": { 787 | "__uuid__": "a23235d1-15db-4b95-8439-a2e005bfff91" 788 | }, 789 | "_type": 0, 790 | "_sizeMode": 0, 791 | "_fillType": 0, 792 | "_fillCenter": { 793 | "__type__": "cc.Vec2", 794 | "x": 0, 795 | "y": 0 796 | }, 797 | "_fillStart": 0, 798 | "_fillRange": 0, 799 | "_isTrimmedMode": true, 800 | "_atlas": null, 801 | "_id": "07X5MVmStL2Iv+fkPucbaV" 802 | }, 803 | { 804 | "__type__": "cc.Widget", 805 | "_name": "", 806 | "_objFlags": 0, 807 | "node": { 808 | "__id__": 5 809 | }, 810 | "_enabled": true, 811 | "alignMode": 0, 812 | "_target": null, 813 | "_alignFlags": 18, 814 | "_left": 0, 815 | "_right": 540, 816 | "_top": 0, 817 | "_bottom": 0, 818 | "_verticalCenter": 0, 819 | "_horizontalCenter": 0, 820 | "_isAbsLeft": true, 821 | "_isAbsRight": true, 822 | "_isAbsTop": true, 823 | "_isAbsBottom": true, 824 | "_isAbsHorizontalCenter": true, 825 | "_isAbsVerticalCenter": true, 826 | "_originalWidth": 200, 827 | "_originalHeight": 150, 828 | "_id": "58G2u77j9PB6RCTNazi0Qe" 829 | }, 830 | { 831 | "__type__": "cc.Sprite", 832 | "_name": "", 833 | "_objFlags": 0, 834 | "node": { 835 | "__id__": 5 836 | }, 837 | "_enabled": true, 838 | "_materials": [ 839 | { 840 | "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" 841 | } 842 | ], 843 | "_srcBlendFactor": 770, 844 | "_dstBlendFactor": 771, 845 | "_spriteFrame": null, 846 | "_type": 1, 847 | "_sizeMode": 0, 848 | "_fillType": 0, 849 | "_fillCenter": { 850 | "__type__": "cc.Vec2", 851 | "x": 0, 852 | "y": 0 853 | }, 854 | "_fillStart": 0, 855 | "_fillRange": 0, 856 | "_isTrimmedMode": true, 857 | "_atlas": null, 858 | "_id": "beNGWS/4NOZriDM3vaqdWf" 859 | }, 860 | { 861 | "__type__": "cc.Layout", 862 | "_name": "", 863 | "_objFlags": 0, 864 | "node": { 865 | "__id__": 5 866 | }, 867 | "_enabled": true, 868 | "_layoutSize": { 869 | "__type__": "cc.Size", 870 | "width": 1281, 871 | "height": 721 872 | }, 873 | "_resize": 0, 874 | "_N$layoutType": 3, 875 | "_N$cellSize": { 876 | "__type__": "cc.Size", 877 | "width": 40, 878 | "height": 40 879 | }, 880 | "_N$startAxis": 0, 881 | "_N$paddingLeft": 0, 882 | "_N$paddingRight": 0, 883 | "_N$paddingTop": 0, 884 | "_N$paddingBottom": 0, 885 | "_N$spacingX": 0, 886 | "_N$spacingY": 0, 887 | "_N$verticalDirection": 0, 888 | "_N$horizontalDirection": 0, 889 | "_N$affectedByScale": true, 890 | "_id": "afWYQudEdN2bsfie9Gn3HF" 891 | }, 892 | { 893 | "__type__": "cc.Node", 894 | "_name": "obs", 895 | "_objFlags": 0, 896 | "_parent": { 897 | "__id__": 2 898 | }, 899 | "_children": [ 900 | { 901 | "__id__": 20 902 | } 903 | ], 904 | "_active": true, 905 | "_components": [ 906 | { 907 | "__id__": 22 908 | } 909 | ], 910 | "_prefab": null, 911 | "_opacity": 255, 912 | "_color": { 913 | "__type__": "cc.Color", 914 | "r": 255, 915 | "g": 255, 916 | "b": 255, 917 | "a": 255 918 | }, 919 | "_contentSize": { 920 | "__type__": "cc.Size", 921 | "width": 0, 922 | "height": 0 923 | }, 924 | "_anchorPoint": { 925 | "__type__": "cc.Vec2", 926 | "x": 0.5, 927 | "y": 0.5 928 | }, 929 | "_trs": { 930 | "__type__": "TypedArray", 931 | "ctor": "Float64Array", 932 | "array": [ 933 | 0, 934 | 0, 935 | 0, 936 | 0, 937 | 0, 938 | 0, 939 | 1, 940 | 1, 941 | 1, 942 | 1 943 | ] 944 | }, 945 | "_eulerAngles": { 946 | "__type__": "cc.Vec3", 947 | "x": 0, 948 | "y": 0, 949 | "z": 0 950 | }, 951 | "_skewX": 0, 952 | "_skewY": 0, 953 | "_is3DNode": false, 954 | "_groupIndex": 0, 955 | "groupIndex": 0, 956 | "_id": "143Cih2IdKf5IfQWI9M+D0" 957 | }, 958 | { 959 | "__type__": "cc.Node", 960 | "_name": "obs", 961 | "_objFlags": 0, 962 | "_parent": { 963 | "__id__": 19 964 | }, 965 | "_children": [], 966 | "_active": true, 967 | "_components": [ 968 | { 969 | "__id__": 21 970 | } 971 | ], 972 | "_prefab": null, 973 | "_opacity": 255, 974 | "_color": { 975 | "__type__": "cc.Color", 976 | "r": 28, 977 | "g": 29, 978 | "b": 32, 979 | "a": 255 980 | }, 981 | "_contentSize": { 982 | "__type__": "cc.Size", 983 | "width": 3, 984 | "height": 3 985 | }, 986 | "_anchorPoint": { 987 | "__type__": "cc.Vec2", 988 | "x": 0.5, 989 | "y": 0.5 990 | }, 991 | "_trs": { 992 | "__type__": "TypedArray", 993 | "ctor": "Float64Array", 994 | "array": [ 995 | 0, 996 | 0, 997 | 0, 998 | 0, 999 | 0, 1000 | 0, 1001 | 1, 1002 | 1, 1003 | 1, 1004 | 1 1005 | ] 1006 | }, 1007 | "_eulerAngles": { 1008 | "__type__": "cc.Vec3", 1009 | "x": 0, 1010 | "y": 0, 1011 | "z": 0 1012 | }, 1013 | "_skewX": 0, 1014 | "_skewY": 0, 1015 | "_is3DNode": false, 1016 | "_groupIndex": 0, 1017 | "groupIndex": 0, 1018 | "_id": "b43slAe+5C75h2XPTcd3Wm" 1019 | }, 1020 | { 1021 | "__type__": "cc.Sprite", 1022 | "_name": "", 1023 | "_objFlags": 0, 1024 | "node": { 1025 | "__id__": 20 1026 | }, 1027 | "_enabled": true, 1028 | "_materials": [ 1029 | { 1030 | "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" 1031 | } 1032 | ], 1033 | "_srcBlendFactor": 770, 1034 | "_dstBlendFactor": 771, 1035 | "_spriteFrame": { 1036 | "__uuid__": "a23235d1-15db-4b95-8439-a2e005bfff91" 1037 | }, 1038 | "_type": 0, 1039 | "_sizeMode": 0, 1040 | "_fillType": 0, 1041 | "_fillCenter": { 1042 | "__type__": "cc.Vec2", 1043 | "x": 0, 1044 | "y": 0 1045 | }, 1046 | "_fillStart": 0, 1047 | "_fillRange": 0, 1048 | "_isTrimmedMode": true, 1049 | "_atlas": null, 1050 | "_id": "2cRCQChjtI9akT6D7HpeNK" 1051 | }, 1052 | { 1053 | "__type__": "cc.Widget", 1054 | "_name": "", 1055 | "_objFlags": 0, 1056 | "node": { 1057 | "__id__": 19 1058 | }, 1059 | "_enabled": false, 1060 | "alignMode": 0, 1061 | "_target": null, 1062 | "_alignFlags": 12, 1063 | "_left": 640, 1064 | "_right": 540, 1065 | "_top": 0, 1066 | "_bottom": 360, 1067 | "_verticalCenter": 0, 1068 | "_horizontalCenter": 0, 1069 | "_isAbsLeft": true, 1070 | "_isAbsRight": true, 1071 | "_isAbsTop": true, 1072 | "_isAbsBottom": true, 1073 | "_isAbsHorizontalCenter": true, 1074 | "_isAbsVerticalCenter": true, 1075 | "_originalWidth": 200, 1076 | "_originalHeight": 150, 1077 | "_id": "4btTcYFidMArhSS/wogn3D" 1078 | }, 1079 | { 1080 | "__type__": "cc.Node", 1081 | "_name": "终点", 1082 | "_objFlags": 0, 1083 | "_parent": { 1084 | "__id__": 2 1085 | }, 1086 | "_children": [], 1087 | "_active": true, 1088 | "_components": [ 1089 | { 1090 | "__id__": 24 1091 | } 1092 | ], 1093 | "_prefab": null, 1094 | "_opacity": 255, 1095 | "_color": { 1096 | "__type__": "cc.Color", 1097 | "r": 32, 1098 | "g": 55, 1099 | "b": 224, 1100 | "a": 255 1101 | }, 1102 | "_contentSize": { 1103 | "__type__": "cc.Size", 1104 | "width": 90, 1105 | "height": 90 1106 | }, 1107 | "_anchorPoint": { 1108 | "__type__": "cc.Vec2", 1109 | "x": 0.5, 1110 | "y": 0.5 1111 | }, 1112 | "_trs": { 1113 | "__type__": "TypedArray", 1114 | "ctor": "Float64Array", 1115 | "array": [ 1116 | 218.477, 1117 | -26.084, 1118 | 0, 1119 | 0, 1120 | 0, 1121 | 0, 1122 | 1, 1123 | 0.1666667, 1124 | 0.1666667, 1125 | 1 1126 | ] 1127 | }, 1128 | "_eulerAngles": { 1129 | "__type__": "cc.Vec3", 1130 | "x": 0, 1131 | "y": 0, 1132 | "z": 0 1133 | }, 1134 | "_skewX": 0, 1135 | "_skewY": 0, 1136 | "_is3DNode": false, 1137 | "_groupIndex": 0, 1138 | "groupIndex": 0, 1139 | "_id": "2aJtf3vytLS5WE2V9gA2cP" 1140 | }, 1141 | { 1142 | "__type__": "cc.Sprite", 1143 | "_name": "", 1144 | "_objFlags": 0, 1145 | "node": { 1146 | "__id__": 23 1147 | }, 1148 | "_enabled": true, 1149 | "_materials": [ 1150 | { 1151 | "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" 1152 | } 1153 | ], 1154 | "_srcBlendFactor": 770, 1155 | "_dstBlendFactor": 771, 1156 | "_spriteFrame": { 1157 | "__uuid__": "a23235d1-15db-4b95-8439-a2e005bfff91" 1158 | }, 1159 | "_type": 0, 1160 | "_sizeMode": 0, 1161 | "_fillType": 0, 1162 | "_fillCenter": { 1163 | "__type__": "cc.Vec2", 1164 | "x": 0, 1165 | "y": 0 1166 | }, 1167 | "_fillStart": 0, 1168 | "_fillRange": 0, 1169 | "_isTrimmedMode": true, 1170 | "_atlas": null, 1171 | "_id": "30+vCIayxNmaVW+4T+vHLm" 1172 | }, 1173 | { 1174 | "__type__": "cc.Node", 1175 | "_name": "起点", 1176 | "_objFlags": 0, 1177 | "_parent": { 1178 | "__id__": 2 1179 | }, 1180 | "_children": [], 1181 | "_active": true, 1182 | "_components": [ 1183 | { 1184 | "__id__": 26 1185 | } 1186 | ], 1187 | "_prefab": null, 1188 | "_opacity": 255, 1189 | "_color": { 1190 | "__type__": "cc.Color", 1191 | "r": 78, 1192 | "g": 211, 1193 | "b": 27, 1194 | "a": 255 1195 | }, 1196 | "_contentSize": { 1197 | "__type__": "cc.Size", 1198 | "width": 90, 1199 | "height": 90 1200 | }, 1201 | "_anchorPoint": { 1202 | "__type__": "cc.Vec2", 1203 | "x": 0.5, 1204 | "y": 0.5 1205 | }, 1206 | "_trs": { 1207 | "__type__": "TypedArray", 1208 | "ctor": "Float64Array", 1209 | "array": [ 1210 | -294.241, 1211 | 117.335, 1212 | 0, 1213 | 0, 1214 | 0, 1215 | 0, 1216 | 1, 1217 | 0.1666667, 1218 | 0.1666667, 1219 | 1 1220 | ] 1221 | }, 1222 | "_eulerAngles": { 1223 | "__type__": "cc.Vec3", 1224 | "x": 0, 1225 | "y": 0, 1226 | "z": 0 1227 | }, 1228 | "_skewX": 0, 1229 | "_skewY": 0, 1230 | "_is3DNode": false, 1231 | "_groupIndex": 0, 1232 | "groupIndex": 0, 1233 | "_id": "7eurOfJypGAoIV8kWR2dnP" 1234 | }, 1235 | { 1236 | "__type__": "cc.Sprite", 1237 | "_name": "", 1238 | "_objFlags": 0, 1239 | "node": { 1240 | "__id__": 25 1241 | }, 1242 | "_enabled": true, 1243 | "_materials": [ 1244 | { 1245 | "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" 1246 | } 1247 | ], 1248 | "_srcBlendFactor": 770, 1249 | "_dstBlendFactor": 771, 1250 | "_spriteFrame": { 1251 | "__uuid__": "a23235d1-15db-4b95-8439-a2e005bfff91" 1252 | }, 1253 | "_type": 0, 1254 | "_sizeMode": 0, 1255 | "_fillType": 0, 1256 | "_fillCenter": { 1257 | "__type__": "cc.Vec2", 1258 | "x": 0, 1259 | "y": 0 1260 | }, 1261 | "_fillStart": 0, 1262 | "_fillRange": 0, 1263 | "_isTrimmedMode": true, 1264 | "_atlas": null, 1265 | "_id": "3f1A0g/b1F4qE6GqoCjLeY" 1266 | }, 1267 | { 1268 | "__type__": "cc.Node", 1269 | "_name": "New Button", 1270 | "_objFlags": 0, 1271 | "_parent": { 1272 | "__id__": 2 1273 | }, 1274 | "_children": [ 1275 | { 1276 | "__id__": 28 1277 | } 1278 | ], 1279 | "_active": true, 1280 | "_components": [ 1281 | { 1282 | "__id__": 33 1283 | } 1284 | ], 1285 | "_prefab": null, 1286 | "_opacity": 255, 1287 | "_color": { 1288 | "__type__": "cc.Color", 1289 | "r": 255, 1290 | "g": 255, 1291 | "b": 255, 1292 | "a": 255 1293 | }, 1294 | "_contentSize": { 1295 | "__type__": "cc.Size", 1296 | "width": 100, 1297 | "height": 40 1298 | }, 1299 | "_anchorPoint": { 1300 | "__type__": "cc.Vec2", 1301 | "x": 0.5, 1302 | "y": 0.5 1303 | }, 1304 | "_trs": { 1305 | "__type__": "TypedArray", 1306 | "ctor": "Float64Array", 1307 | "array": [ 1308 | 569.231, 1309 | 287.51, 1310 | 0, 1311 | 0, 1312 | 0, 1313 | 0, 1314 | 1, 1315 | 1, 1316 | 1, 1317 | 1 1318 | ] 1319 | }, 1320 | "_eulerAngles": { 1321 | "__type__": "cc.Vec3", 1322 | "x": 0, 1323 | "y": 0, 1324 | "z": 0 1325 | }, 1326 | "_skewX": 0, 1327 | "_skewY": 0, 1328 | "_is3DNode": false, 1329 | "_groupIndex": 0, 1330 | "groupIndex": 0, 1331 | "_id": "f3bOIKw8pDrqoM+5UWDZPs" 1332 | }, 1333 | { 1334 | "__type__": "cc.Node", 1335 | "_name": "Background", 1336 | "_objFlags": 512, 1337 | "_parent": { 1338 | "__id__": 27 1339 | }, 1340 | "_children": [ 1341 | { 1342 | "__id__": 29 1343 | } 1344 | ], 1345 | "_active": true, 1346 | "_components": [ 1347 | { 1348 | "__id__": 31 1349 | }, 1350 | { 1351 | "__id__": 32 1352 | } 1353 | ], 1354 | "_prefab": null, 1355 | "_opacity": 255, 1356 | "_color": { 1357 | "__type__": "cc.Color", 1358 | "r": 255, 1359 | "g": 255, 1360 | "b": 255, 1361 | "a": 255 1362 | }, 1363 | "_contentSize": { 1364 | "__type__": "cc.Size", 1365 | "width": 100, 1366 | "height": 40 1367 | }, 1368 | "_anchorPoint": { 1369 | "__type__": "cc.Vec2", 1370 | "x": 0.5, 1371 | "y": 0.5 1372 | }, 1373 | "_trs": { 1374 | "__type__": "TypedArray", 1375 | "ctor": "Float64Array", 1376 | "array": [ 1377 | 0, 1378 | 0, 1379 | 0, 1380 | 0, 1381 | 0, 1382 | 0, 1383 | 1, 1384 | 1, 1385 | 1, 1386 | 1 1387 | ] 1388 | }, 1389 | "_eulerAngles": { 1390 | "__type__": "cc.Vec3", 1391 | "x": 0, 1392 | "y": 0, 1393 | "z": 0 1394 | }, 1395 | "_skewX": 0, 1396 | "_skewY": 0, 1397 | "_is3DNode": false, 1398 | "_groupIndex": 0, 1399 | "groupIndex": 0, 1400 | "_id": "b0pW8EbolOK4nTPpbkM1yu" 1401 | }, 1402 | { 1403 | "__type__": "cc.Node", 1404 | "_name": "Label", 1405 | "_objFlags": 512, 1406 | "_parent": { 1407 | "__id__": 28 1408 | }, 1409 | "_children": [], 1410 | "_active": true, 1411 | "_components": [ 1412 | { 1413 | "__id__": 30 1414 | } 1415 | ], 1416 | "_prefab": null, 1417 | "_opacity": 255, 1418 | "_color": { 1419 | "__type__": "cc.Color", 1420 | "r": 0, 1421 | "g": 0, 1422 | "b": 0, 1423 | "a": 255 1424 | }, 1425 | "_contentSize": { 1426 | "__type__": "cc.Size", 1427 | "width": 100, 1428 | "height": 40 1429 | }, 1430 | "_anchorPoint": { 1431 | "__type__": "cc.Vec2", 1432 | "x": 0.5, 1433 | "y": 0.5 1434 | }, 1435 | "_trs": { 1436 | "__type__": "TypedArray", 1437 | "ctor": "Float64Array", 1438 | "array": [ 1439 | 0, 1440 | 0, 1441 | 0, 1442 | 0, 1443 | 0, 1444 | 0, 1445 | 1, 1446 | 1, 1447 | 1, 1448 | 1 1449 | ] 1450 | }, 1451 | "_eulerAngles": { 1452 | "__type__": "cc.Vec3", 1453 | "x": 0, 1454 | "y": 0, 1455 | "z": 0 1456 | }, 1457 | "_skewX": 0, 1458 | "_skewY": 0, 1459 | "_is3DNode": false, 1460 | "_groupIndex": 0, 1461 | "groupIndex": 0, 1462 | "_id": "81GvAyKcdAl53PyPA1Uf0p" 1463 | }, 1464 | { 1465 | "__type__": "cc.Label", 1466 | "_name": "", 1467 | "_objFlags": 0, 1468 | "node": { 1469 | "__id__": 29 1470 | }, 1471 | "_enabled": true, 1472 | "_materials": [ 1473 | { 1474 | "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" 1475 | } 1476 | ], 1477 | "_srcBlendFactor": 770, 1478 | "_dstBlendFactor": 771, 1479 | "_string": "button", 1480 | "_N$string": "button", 1481 | "_fontSize": 20, 1482 | "_lineHeight": 40, 1483 | "_enableWrapText": false, 1484 | "_N$file": null, 1485 | "_isSystemFontUsed": true, 1486 | "_spacingX": 0, 1487 | "_batchAsBitmap": false, 1488 | "_styleFlags": 0, 1489 | "_underlineHeight": 0, 1490 | "_N$horizontalAlign": 1, 1491 | "_N$verticalAlign": 1, 1492 | "_N$fontFamily": "Arial", 1493 | "_N$overflow": 1, 1494 | "_N$cacheMode": 1, 1495 | "_id": "12fBPGxJhACqmnpu5Z3bik" 1496 | }, 1497 | { 1498 | "__type__": "cc.Sprite", 1499 | "_name": "", 1500 | "_objFlags": 0, 1501 | "node": { 1502 | "__id__": 28 1503 | }, 1504 | "_enabled": true, 1505 | "_materials": [ 1506 | { 1507 | "__uuid__": "eca5d2f2-8ef6-41c2-bbe6-f9c79d09c432" 1508 | } 1509 | ], 1510 | "_srcBlendFactor": 770, 1511 | "_dstBlendFactor": 771, 1512 | "_spriteFrame": { 1513 | "__uuid__": "f0048c10-f03e-4c97-b9d3-3506e1d58952" 1514 | }, 1515 | "_type": 1, 1516 | "_sizeMode": 0, 1517 | "_fillType": 0, 1518 | "_fillCenter": { 1519 | "__type__": "cc.Vec2", 1520 | "x": 0, 1521 | "y": 0 1522 | }, 1523 | "_fillStart": 0, 1524 | "_fillRange": 0, 1525 | "_isTrimmedMode": true, 1526 | "_atlas": null, 1527 | "_id": "26BS8etYNBhJ+DqrDxgShD" 1528 | }, 1529 | { 1530 | "__type__": "cc.Widget", 1531 | "_name": "", 1532 | "_objFlags": 0, 1533 | "node": { 1534 | "__id__": 28 1535 | }, 1536 | "_enabled": true, 1537 | "alignMode": 0, 1538 | "_target": null, 1539 | "_alignFlags": 45, 1540 | "_left": 0, 1541 | "_right": 0, 1542 | "_top": 0, 1543 | "_bottom": 0, 1544 | "_verticalCenter": 0, 1545 | "_horizontalCenter": 0, 1546 | "_isAbsLeft": true, 1547 | "_isAbsRight": true, 1548 | "_isAbsTop": true, 1549 | "_isAbsBottom": true, 1550 | "_isAbsHorizontalCenter": true, 1551 | "_isAbsVerticalCenter": true, 1552 | "_originalWidth": 100, 1553 | "_originalHeight": 40, 1554 | "_id": "a3x209oGFFBbEZaA0q6Gmc" 1555 | }, 1556 | { 1557 | "__type__": "cc.Button", 1558 | "_name": "", 1559 | "_objFlags": 0, 1560 | "node": { 1561 | "__id__": 27 1562 | }, 1563 | "_enabled": true, 1564 | "_normalMaterial": null, 1565 | "_grayMaterial": null, 1566 | "duration": 0.1, 1567 | "zoomScale": 1.2, 1568 | "clickEvents": [ 1569 | { 1570 | "__id__": 34 1571 | } 1572 | ], 1573 | "_N$interactable": true, 1574 | "_N$enableAutoGrayEffect": false, 1575 | "_N$transition": 2, 1576 | "transition": 2, 1577 | "_N$normalColor": { 1578 | "__type__": "cc.Color", 1579 | "r": 230, 1580 | "g": 230, 1581 | "b": 230, 1582 | "a": 255 1583 | }, 1584 | "_N$pressedColor": { 1585 | "__type__": "cc.Color", 1586 | "r": 200, 1587 | "g": 200, 1588 | "b": 200, 1589 | "a": 255 1590 | }, 1591 | "pressedColor": { 1592 | "__type__": "cc.Color", 1593 | "r": 200, 1594 | "g": 200, 1595 | "b": 200, 1596 | "a": 255 1597 | }, 1598 | "_N$hoverColor": { 1599 | "__type__": "cc.Color", 1600 | "r": 255, 1601 | "g": 255, 1602 | "b": 255, 1603 | "a": 255 1604 | }, 1605 | "hoverColor": { 1606 | "__type__": "cc.Color", 1607 | "r": 255, 1608 | "g": 255, 1609 | "b": 255, 1610 | "a": 255 1611 | }, 1612 | "_N$disabledColor": { 1613 | "__type__": "cc.Color", 1614 | "r": 120, 1615 | "g": 120, 1616 | "b": 120, 1617 | "a": 200 1618 | }, 1619 | "_N$normalSprite": { 1620 | "__uuid__": "f0048c10-f03e-4c97-b9d3-3506e1d58952" 1621 | }, 1622 | "_N$pressedSprite": { 1623 | "__uuid__": "e9ec654c-97a2-4787-9325-e6a10375219a" 1624 | }, 1625 | "pressedSprite": { 1626 | "__uuid__": "e9ec654c-97a2-4787-9325-e6a10375219a" 1627 | }, 1628 | "_N$hoverSprite": { 1629 | "__uuid__": "f0048c10-f03e-4c97-b9d3-3506e1d58952" 1630 | }, 1631 | "hoverSprite": { 1632 | "__uuid__": "f0048c10-f03e-4c97-b9d3-3506e1d58952" 1633 | }, 1634 | "_N$disabledSprite": { 1635 | "__uuid__": "29158224-f8dd-4661-a796-1ffab537140e" 1636 | }, 1637 | "_N$target": { 1638 | "__id__": 28 1639 | }, 1640 | "_id": "8btltnBJZGfbZEC8zJhsn1" 1641 | }, 1642 | { 1643 | "__type__": "cc.ClickEvent", 1644 | "target": { 1645 | "__id__": 2 1646 | }, 1647 | "component": "", 1648 | "_componentId": "915abhOpixOfoQ7UVGkkZqW", 1649 | "handler": "hh", 1650 | "customEventData": "" 1651 | }, 1652 | { 1653 | "__type__": "cc.Canvas", 1654 | "_name": "", 1655 | "_objFlags": 0, 1656 | "node": { 1657 | "__id__": 2 1658 | }, 1659 | "_enabled": true, 1660 | "_designResolution": { 1661 | "__type__": "cc.Size", 1662 | "width": 1280, 1663 | "height": 720 1664 | }, 1665 | "_fitWidth": false, 1666 | "_fitHeight": true, 1667 | "_id": "d6O2pDuwlI/JlmG3msPBxC" 1668 | }, 1669 | { 1670 | "__type__": "915abhOpixOfoQ7UVGkkZqW", 1671 | "_name": "", 1672 | "_objFlags": 0, 1673 | "node": { 1674 | "__id__": 2 1675 | }, 1676 | "_enabled": true, 1677 | "map": { 1678 | "__id__": 5 1679 | }, 1680 | "obstacles": { 1681 | "__id__": 19 1682 | }, 1683 | "_id": "b9svP2hpdAppwxU9grL9aK" 1684 | }, 1685 | { 1686 | "__type__": "cc.Widget", 1687 | "_name": "", 1688 | "_objFlags": 0, 1689 | "node": { 1690 | "__id__": 2 1691 | }, 1692 | "_enabled": true, 1693 | "alignMode": 1, 1694 | "_target": null, 1695 | "_alignFlags": 45, 1696 | "_left": 0, 1697 | "_right": 0, 1698 | "_top": 0, 1699 | "_bottom": 0, 1700 | "_verticalCenter": 0, 1701 | "_horizontalCenter": 0, 1702 | "_isAbsLeft": true, 1703 | "_isAbsRight": true, 1704 | "_isAbsTop": true, 1705 | "_isAbsBottom": true, 1706 | "_isAbsHorizontalCenter": true, 1707 | "_isAbsVerticalCenter": true, 1708 | "_originalWidth": 0, 1709 | "_originalHeight": 0, 1710 | "_id": "2emLph1/RIpI6TiebzkKfq" 1711 | } 1712 | ] -------------------------------------------------------------------------------- /Scene/helloworld.fire.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.3.2", 3 | "uuid": "805f9e76-6558-4db4-96ad-23031a3f906a", 4 | "importer": "scene", 5 | "asyncLoadAssets": false, 6 | "autoReleaseAssets": false, 7 | "subMetas": {} 8 | } -------------------------------------------------------------------------------- /Script.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.1.3", 3 | "uuid": "b21965c3-9a41-4bba-b925-8b3a9a0207af", 4 | "importer": "folder", 5 | "isBundle": false, 6 | "bundleName": "", 7 | "priority": 1, 8 | "compressionType": {}, 9 | "optimizeHotUpdate": {}, 10 | "inlineSpriteFrames": {}, 11 | "isRemoteBundle": {}, 12 | "subMetas": {} 13 | } -------------------------------------------------------------------------------- /Script/Helloworld.ts: -------------------------------------------------------------------------------- 1 | import {JPS} from "./JPS"; 2 | 3 | const {ccclass, property} = cc._decorator; 4 | 5 | @ccclass 6 | export default class Helloworld extends cc.Component { 7 | 8 | @property({displayName: '地图', type: cc.Node}) 9 | map: cc.Node = null; 10 | 11 | @property({displayName: '障碍物集合', type: cc.Node}) 12 | obstacles: cc.Node = null; 13 | 14 | private jps: JPS = null; 15 | 16 | private customGenerateLogicMap() { 17 | window.a = this; 18 | let mapData = JPS.formatToMapData(this.map, this.map.children[0].width * this.map.children[0].scale); 19 | let autoFindPath = new JPS(mapData); 20 | this.jps = autoFindPath; 21 | //更新当前地图里所有障碍物 22 | for (const child of this.obstacles.children) autoFindPath.updateMap(child); 23 | } 24 | 25 | hhh() { 26 | let pos0 = cc.find('Canvas/起点'); 27 | pos0.stopAllActions() 28 | this.unscheduleAllCallbacks() 29 | } 30 | hh() { 31 | this.jps.removeAllObstacle() 32 | for (const child of this.obstacles.children) this.jps.updateMap(child); 33 | 34 | 35 | this.obsP.destroyAllChildren(); 36 | this.jps.fixClosedListMap.forEach((v,a)=>{ 37 | 38 | let vec2s = this.jps.gridPositionConvertGameObjectPosition([cc.v2(v.x, v.y)],cc.v2(0.5, 0.5), cc.Vec2); 39 | 40 | let location = vec2s[0]; 41 | let node3 = cc.instantiate(this.obs); 42 | node3.width = 16; 43 | node3.height = 16; 44 | this.obsP.addChild(node3) 45 | node3.setPosition(location) 46 | 47 | }) 48 | 49 | 50 | this.searchPath(); 51 | } 52 | 53 | private searchPath() { 54 | let pos0 = cc.find('Canvas/起点'); 55 | let pos1 = cc.find('Canvas/终点'); 56 | console.time('kaka') 57 | let paths = this.jps.gridPositionConvertGameObjectPosition(this.jps.findGridPath(pos0, pos1, 0), cc.v2(0.5, 0.5), cc.Vec2); 58 | console.timeEnd('kaka') 59 | if (paths.length === 0) console.log('死路'); 60 | for (let i = 0; i < paths.length; i++) { 61 | this.scheduleOnce(() => { 62 | pos0.runAction(cc.moveTo(0.5, paths[i])); 63 | }, i * 0.5); 64 | } 65 | } 66 | 67 | private obsP:cc.Node; 68 | private obs:cc.Node; 69 | start() { 70 | let map = cc.find('Canvas/map'); 71 | let node = map.children[0]; 72 | node.removeFromParent(); 73 | for (let i = 0; i < 64 * 36; i++) { 74 | map.addChild(cc.instantiate(node)) 75 | } 76 | map.getComponent(cc.Layout).updateLayout(); 77 | 78 | this.obs = cc.find('Canvas/obs/obs'); 79 | this.obsP = this.obs.parent; 80 | this.obs.removeFromParent(); 81 | 82 | 83 | const k = 1; 84 | 85 | const node1 = cc.find('Canvas/起点'); 86 | const node2 = cc.find('Canvas/终点'); 87 | node1.on(cc.Node.EventType.TOUCH_MOVE, function (e) { 88 | node1.setPosition(node1.getPosition().add(e.getDelta().mul(k))); 89 | }); 90 | node2.on(cc.Node.EventType.TOUCH_MOVE, function (e) { 91 | node2.setPosition(node2.getPosition().add(e.getDelta().mul(k))); 92 | }); 93 | 94 | 95 | 96 | map.on(cc.Node.EventType.TOUCH_START, (e) =>{ 97 | this.obsP.destroyAllChildren() 98 | this.obsP.removeAllChildren(); 99 | //更新当前地图里所有障碍物 100 | if(this.jps) { 101 | this.jps.removeAllObstacle(); 102 | // for (const child of this.obstacles.children) this.jps.updateMap(child); 103 | } 104 | }); 105 | map.on(cc.Node.EventType.TOUCH_MOVE, (e) =>{ 106 | if(!this.jps) return; 107 | 108 | 109 | // for (const child of map.children) { 110 | // if(child.getBoundingBoxToWorld().contains(e.getLocation())) { 111 | // child 112 | // } 113 | // } 114 | 115 | let location = e.getLocation().sub(cc.v2(640, 360)); 116 | let node3 = cc.instantiate(this.obs); 117 | this.obsP.addChild(node3) 118 | node3.setPosition(location) 119 | // this.jps.updateMap(node3) 120 | 121 | 122 | }); 123 | 124 | 125 | 126 | 127 | this.scheduleOnce(()=>{ 128 | this.customGenerateLogicMap(); 129 | this.searchPath(); 130 | }) 131 | 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Script/Helloworld.ts.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.1.0", 3 | "uuid": "915ab84e-a62c-4e7e-843b-5151a4919a96", 4 | "importer": "typescript", 5 | "isPlugin": false, 6 | "loadPluginInWeb": true, 7 | "loadPluginInNative": true, 8 | "loadPluginInEditor": false, 9 | "subMetas": {} 10 | } -------------------------------------------------------------------------------- /Script/JPS.ts: -------------------------------------------------------------------------------- 1 | export interface Vector2 { 2 | x: number; 3 | y: number; 4 | } 5 | 6 | export interface Size { 7 | width: number; 8 | height: number; 9 | } 10 | 11 | interface V2 { 12 | new(x: number, y: number): T; 13 | } 14 | 15 | //寻路的路点信息 16 | class PathPointData implements Vector2 { 17 | constructor(x: number, y: number) { 18 | this.x = x; 19 | this.y = y; 20 | } 21 | 22 | x: number = 0; //X axis position 23 | y: number = 0; //Y axis position 24 | F: number = 0; //G + H + K 25 | G: number = 0; //开始点到当前路点的移动量 26 | H: number = 0; //当前路点到目标点的移动量估值 27 | parent: PathPointData = null; //上一个节点 28 | K: number = lands.normal //地形值 29 | 30 | } 31 | 32 | export type GameObject = Size & Vector2 & { anchorX: number, anchorY: number, angle: number }; 33 | 34 | //模式 35 | export const enum models { 36 | normal, //普通的 37 | tilt, //倾斜的 38 | } 39 | 40 | //地形 41 | export const enum lands { 42 | normal = 1, //普通的 43 | hard = 2, //类似沼泽之类的 44 | } 45 | 46 | /**@description 每张地图对应一个寻路实例。 全部给世界坐标,返回的也全部是世界坐标*/ 47 | export class JPS { 48 | //分隔符 49 | private static sep: string = "_"; 50 | //模式 51 | private model: models = models.tilt; 52 | //地图映射 格子坐标<>当前格子的K数值(K值用于处理不同的地形) 53 | private mapTable: Map = new Map(); 54 | //open列表 55 | private openList: PathPointData[] = []; 56 | private openListMap: Map = new Map(); 57 | //closed列表 58 | private fixClosedListMap: Map = new Map(); 59 | private closedListMap: Map = new Map(); 60 | //出生点 61 | private bronPoint: PathPointData = null; 62 | //目标点 63 | private targetPoint: PathPointData = null; 64 | //当前寻路点 65 | private nowPoint: PathPointData = null; 66 | //地图数据 67 | private readonly mapData: GameObject & { gridLength: number } = null; 68 | 69 | /**@description 格式化成地图数据*/ 70 | public static formatToMapData(gameObject: GameObject, gridLength: number): GameObject & { gridLength: number} { 71 | return { 72 | anchorY: gameObject.anchorY, 73 | anchorX: gameObject.anchorX, 74 | height: gameObject.height, 75 | width: gameObject.width, 76 | x: gameObject.x, 77 | y: gameObject.y, 78 | gridLength: gridLength, 79 | angle: -gameObject.angle, 80 | }; 81 | } 82 | 83 | /**@description 根据格子对象获取对应的key值*/ 84 | private static getKey(p: Vector2) { 85 | return p.x.toString() + JPS.sep + p.y.toString(); 86 | } 87 | 88 | /**@description 添加到openList*/ 89 | private addToOpenList(v2: PathPointData) { 90 | let p = JPS.getKey(v2); 91 | v2 = this.mapTable.get(JPS.getKey(v2)) 92 | if (this.mapTable.get(p) === void 0) throw new Error('this point not in map'); 93 | if (this.openListMap.get(p)) { 94 | //该点已经在open列表中 && 重新计算F值 && 新F值更低就将父方格修改为当前节点否则什么都不做 95 | let oldParent = v2.parent; 96 | let oldF = v2.F; 97 | v2.parent = this.nowPoint; 98 | this.F(v2); 99 | if (v2.F > oldF) { 100 | v2.parent = oldParent; 101 | this.F(v2); 102 | return; 103 | } 104 | return; 105 | } else { 106 | v2.parent = this.nowPoint; //设置父方格 107 | this.F(v2); //计算F值 108 | } 109 | this.openList.push(v2); 110 | this.openListMap.set(p, this.mapTable.get(p)); 111 | } 112 | 113 | /**@description 是否已经在closedList中*/ 114 | private isInClosedList(p: Vector2) { 115 | let key = JPS.getKey(p); 116 | return !!(this.fixClosedListMap.get(key) || this.closedListMap.get(key)); 117 | } 118 | 119 | /**@description 移除最小F值的路点*/ 120 | private removeMinFFromOpenList(): PathPointData { 121 | //排序 122 | this.openList.sort((a: PathPointData, b: PathPointData) => { 123 | if (a.F > b.F) return -1; 124 | return 1 125 | }); 126 | let v2: PathPointData = this.openList.pop(); 127 | if(v2) { 128 | this.removeFromOpenList(v2); 129 | return this.mapTable.get(JPS.getKey(v2)) 130 | } else { 131 | return null; 132 | } 133 | 134 | } 135 | 136 | /**@description 移除最小F值的路点*/ 137 | private removeFromOpenList(v2: PathPointData) { 138 | let p = JPS.getKey(v2); 139 | if (!this.openListMap.has(p)) throw new Error('not in openList'); 140 | this.openListMap.delete(p); 141 | } 142 | 143 | /**@description 添加到closedList*/ 144 | private addToClosedList(v2: PathPointData) { 145 | let p = JPS.getKey(v2); 146 | if (this.mapTable.get(p) === void 0) throw new Error('this point not in map'); 147 | if (this.closedListMap.get(p)) throw new Error('is in closedList'); 148 | this.closedListMap.set(p, this.mapTable.get(p)); 149 | } 150 | 151 | // 单次寻路最大限制次数 152 | private readonly searchLimit: number = 688; 153 | 154 | /**@description 构造函数 155 | * @param mapData 地图坐标,地图尺寸,格子尺寸 156 | * @param obstacles 障碍物坐标及尺寸 157 | * */ 158 | public constructor(mapData: GameObject & { gridLength: number, searchLimit?: number }, obstacles?: GameObject[]) { 159 | if (mapData.searchLimit > 0) this.searchLimit = mapData.searchLimit; 160 | mapData.x = mapData.x - mapData.width * mapData.anchorX; 161 | mapData.y = mapData.y - mapData.height * mapData.anchorY; 162 | this.mapData = mapData; 163 | for (let i = 0, i1 = Math.ceil(mapData.width / this.mapData.gridLength); i < i1; ++i) { 164 | for (let j = 0, j1 = Math.ceil(mapData.height / this.mapData.gridLength); j < j1; ++j) { 165 | this.mapTable.set(i.toString() + JPS.sep + j.toString(), new PathPointData(i, j)); 166 | } 167 | } 168 | if (obstacles) this.updateMap(...obstacles); 169 | } 170 | 171 | /**@description 根据游戏对象获取格子*/ 172 | private getGridPositions(nodeData: GameObject): string[] { 173 | let vec2s: string[] = []; 174 | let width = nodeData.width; 175 | let height = nodeData.height; 176 | if (nodeData.angle === -90 || nodeData.angle === -270) { 177 | width = width + height; 178 | height = width - height; 179 | width = width - height; 180 | } 181 | let minX = nodeData.x - width * nodeData.anchorX; 182 | let maxX = nodeData.x + width * (1 - nodeData.anchorX); 183 | let minY = nodeData.y - height * nodeData.anchorY; 184 | let maxY = nodeData.y + height * (1 - nodeData.anchorY); 185 | let minPoint = this.getGridPositionRaw({x: minX, y: minY}); 186 | let w = this.getGridPositionRaw({x: maxX, y: minY}).x - minPoint.x + 1; 187 | let h = this.getGridPositionRaw({x: minX, y: maxY}).y - minPoint.y + 1; 188 | let startGridX = minPoint.x; 189 | let startGridY = minPoint.y; 190 | for (let i = 0, i1 = w; i < i1; ++i) { 191 | for (let j = 0, j1 = h; j < j1; ++j) { 192 | let key = (i + startGridX).toString() + JPS.sep + (startGridY + j).toString(); 193 | if (this.mapTable.get(key) === void 0) continue; //超出地图不做处理 194 | vec2s.push(key); 195 | } 196 | } 197 | return vec2s; 198 | } 199 | 200 | /**@description 根据游戏对象获取格子(可能不在地图中)*/ 201 | private getGridPositionRaw(v2: Vector2): Vector2 { 202 | return { 203 | x: Math.floor((v2.x - this.mapData.x) / this.mapData.gridLength), 204 | y: Math.floor((v2.y - this.mapData.y) / this.mapData.gridLength) 205 | }; 206 | } 207 | 208 | /**@description 根据游戏对象获取格子*/ 209 | public getGridPosition(v2: Vector2): PathPointData { 210 | return this.mapTable.get(JPS.getKey(this.getGridPositionRaw(v2))); 211 | } 212 | 213 | /**@description 更新地图信息*/ 214 | updateMap(...obstacles: GameObject[]) { 215 | for (const obstacle of obstacles) { 216 | if (obstacle.width * obstacle.height < 2) continue; //尺寸过小忽略 217 | for (const gridPositionKey of this.getGridPositions(obstacle)) { 218 | this.fixClosedListMap.set(gridPositionKey, this.mapTable.get(gridPositionKey)); 219 | } 220 | } 221 | } 222 | 223 | /**@description 更新地图信息*/ 224 | removeFixObstacle(...obstacles: GameObject[]) { 225 | for (const obstacle of obstacles) { 226 | for (const gridPositionKey of this.getGridPositions(obstacle)) { 227 | this.fixClosedListMap.delete(gridPositionKey); 228 | } 229 | } 230 | } 231 | 232 | /**@description 更新地图信息*/ 233 | removeAllObstacle() { 234 | this.fixClosedListMap.clear(); 235 | } 236 | 237 | //检查各自是否可走 238 | private isClear(point: Vector2) { 239 | const key = JPS.getKey(point); 240 | return this.mapTable.get(key) && !this.fixClosedListMap.get(key) 241 | } 242 | 243 | /**@description 自动寻找新路点并根据F值排序*/ 244 | private autoAddPathPoint() { 245 | //上 246 | let p0 = {x: this.nowPoint.x, y: this.nowPoint.y + 1}; 247 | //右 248 | let p1 = {x: this.nowPoint.x + 1, y: this.nowPoint.y}; 249 | //下 250 | let p2 = {x: this.nowPoint.x, y: this.nowPoint.y - 1}; 251 | //左 252 | let p3 = {x: this.nowPoint.x - 1, y: this.nowPoint.y}; 253 | let maybePoints: Vector2[] = [p0, p1, p2, p3]; 254 | if (this.model === models.tilt) { 255 | if (!this.isInClosedList(p0) && !this.isInClosedList(p1)) { 256 | //右上角 && 上和右不能有阻挡 257 | maybePoints.push({x: this.nowPoint.x + 1, y: this.nowPoint.y + 1}); 258 | } 259 | if (!this.isInClosedList(p2) && !this.isInClosedList(p1)) { 260 | //右下角 && 下和右不能有阻挡 261 | maybePoints.push({x: this.nowPoint.x + 1, y: this.nowPoint.y - 1}); 262 | } 263 | if (!this.isInClosedList(p0) && !this.isInClosedList(p3)) { 264 | //左上角 && 上和左不能有阻挡 265 | maybePoints.push({x: this.nowPoint.x - 1, y: this.nowPoint.y + 1}); 266 | } 267 | if (!this.isInClosedList(p2) && !this.isInClosedList(p3)) { 268 | //左下角 && 下和左不能有阻挡 269 | maybePoints.push({x: this.nowPoint.x - 1, y: this.nowPoint.y - 1}); 270 | } 271 | } 272 | 273 | let targetPointKey = JPS.getKey(this.targetPoint); 274 | for (const point of maybePoints) { 275 | let key = JPS.getKey(point); 276 | let pathPoint = this.mapTable.get(key); 277 | if (pathPoint === void 0) continue; 278 | //有障碍物在终点做特殊处理 279 | if (!this.isInClosedList(pathPoint) || key === targetPointKey) this.addToOpenList(pathPoint); 280 | } 281 | } 282 | 283 | forcedNeighbour(from: Vector2, direction: Vector2) { 284 | const {x, y} = from; 285 | const dx = direction.x; 286 | const dy = direction.y; 287 | const forced = [] 288 | if (dy === 0 && this.isClear({x: x + dx, y: y})) { 289 | //水平 290 | if (!this.isClear({x, y: y - 1})) { 291 | forced.push({x: x + dx, y: y - 1}); 292 | } 293 | if (!this.isClear({x, y: y + 1})) { 294 | forced.push({x: x + dx, y: y + 1}); 295 | } 296 | } else if (dx === 0 && this.isClear({x: x, y: y + dy})) { 297 | //垂直 298 | if (!this.isClear({x: x - 1, y: y})) { 299 | forced.push({x: x - 1, y: y + dy}); 300 | } 301 | if (!this.isClear({x: x + 1, y: y})) { 302 | forced.push({x: x + 1, y: y + dy}); 303 | } 304 | } else { 305 | if (this.isClear({x: x, y: y + dy})) { 306 | if (!this.isClear({x: x - dx, y: y})) { 307 | forced.push({x: x - dx, y: y + dy}); 308 | } 309 | } 310 | if (this.isClear({x: x - 1, y: y})) { 311 | if (!this.isClear({x: x, y: y - dy})) { 312 | forced.push({x: x + dx, y: y - dy}); 313 | } 314 | } 315 | } 316 | return forced.filter(v => this.isClear(v)); 317 | } 318 | 319 | cloneV2(p): Vector2 { 320 | return {x: p.x, y: p.y} 321 | } 322 | 323 | private up: Vector2 = {x: 0, y: 1} 324 | private right: Vector2 = {x: 1, y: 0} 325 | private down: Vector2 = {x: 0, y: -1} 326 | private left: Vector2 = {x: -1, y: 0} 327 | 328 | //水平 && 竖直搜索 329 | searchBase(JPoint: Vector2[], point: Vector2, dirs: Vector2[]) { 330 | //水平方向查找 331 | const ptr: { x: number, y: number, state: number }[] = [ 332 | {x: point.x, y: point.y, state: 1}, 333 | {x: point.x, y: point.y, state: 1}, 334 | {x: point.x, y: point.y, state: 1}, 335 | {x: point.x, y: point.y, state: 1} 336 | ]; 337 | for (const dir of dirs) { 338 | if (dir.y === 1) ptr[0].state = 0; 339 | if (dir.x === 1) ptr[1].state = 0; 340 | if (dir.y === -1) ptr[2].state = 0; 341 | if (dir.x === -1) ptr[3].state = 0; 342 | } 343 | while (true) { 344 | if (ptr[0].state === 0) { 345 | //上 346 | ptr[0].y += 1; 347 | if (!this.isClear(ptr[0])) { 348 | ptr[0].state = 1; 349 | } else if(ptr[0].x === this.targetPoint.x && ptr[0].y === this.targetPoint.y) { 350 | // 终点 351 | ptr[0].state = 1; 352 | if(this.nowPoint.x === point.x && this.nowPoint.y === point.y) { 353 | // 直接查找 354 | this.hasFindTarget = true; 355 | } else { 356 | // 通过该点可以找打终点 357 | JPoint.push(this.cloneV2(ptr[0])); 358 | } 359 | return; 360 | } else { 361 | if (this.forcedNeighbour(ptr[0], this.up).length) { 362 | //存在强制邻居 363 | JPoint.push(this.cloneV2(ptr[0])); 364 | } 365 | } 366 | } 367 | if (ptr[1].state === 0) { 368 | //右 369 | ptr[1].x += 1; 370 | if (!this.isClear(ptr[1])) { 371 | ptr[1].state = 1; 372 | continue; 373 | } else if(ptr[1].x === this.targetPoint.x && ptr[1].y === this.targetPoint.y) { 374 | // 终点 375 | ptr[1].state = 1; 376 | if(this.nowPoint.x === point.x && this.nowPoint.y === point.y) { 377 | // 直接查找 378 | this.hasFindTarget = true; 379 | } else { 380 | // 通过该点可以找打终点 381 | JPoint.push(this.cloneV2(ptr[1])); 382 | } 383 | return; 384 | } else { 385 | if (this.forcedNeighbour(ptr[1], this.right).length) { 386 | //存在强制邻居 387 | JPoint.push(this.cloneV2(ptr[1])); 388 | } 389 | } 390 | } 391 | if (ptr[2].state === 0) { 392 | //下 393 | ptr[2].y -= 1; 394 | if (!this.isClear(ptr[2])) { 395 | ptr[2].state = 1; 396 | continue; 397 | } else if(ptr[2].x === this.targetPoint.x && ptr[2].y === this.targetPoint.y) { 398 | // 终点 399 | ptr[2].state = 1; 400 | if(this.nowPoint.x === point.x && this.nowPoint.y === point.y) { 401 | // 直接查找 402 | this.hasFindTarget = true; 403 | } else { 404 | // 通过该点可以找打终点 405 | JPoint.push(this.cloneV2(ptr[2])); 406 | } 407 | return; 408 | } else { 409 | if (this.forcedNeighbour(ptr[2], this.down).length) { 410 | //存在强制邻居 411 | JPoint.push(this.cloneV2(ptr[2])); 412 | } 413 | } 414 | } 415 | if (ptr[3].state === 0) { 416 | //左 417 | ptr[3].x -= 1; 418 | if (!this.isClear(ptr[3])) { 419 | ptr[3].state = 1; 420 | continue; 421 | } else if(ptr[3].x === this.targetPoint.x && ptr[3].y === this.targetPoint.y) { 422 | // 终点 423 | ptr[3].state = 1; 424 | if(this.nowPoint.x === point.x && this.nowPoint.y === point.y) { 425 | // 直接查找 426 | this.hasFindTarget = true; 427 | } else { 428 | // 通过该点可以找打终点 429 | JPoint.push(this.cloneV2(ptr[3])); 430 | } 431 | return; 432 | } else { 433 | if (this.forcedNeighbour(ptr[3], this.left).length) { 434 | //存在强制邻居 435 | JPoint.push(this.cloneV2(ptr[3])); 436 | } 437 | } 438 | } 439 | for (const ptrElement of ptr) { 440 | if(ptrElement.x === this.targetPoint.x && ptrElement.y === this.targetPoint.y) { 441 | if(this.nowPoint.x === point.x && this.nowPoint.y === point.y) { 442 | // 直接查找 443 | this.hasFindTarget = true; 444 | } else { 445 | // 通过该点可以找打终点 446 | JPoint.push(this.cloneV2(ptrElement)); 447 | } 448 | return; 449 | } 450 | } 451 | if (ptr[0].state !== 0 && ptr[1].state !== 0 && ptr[2].state !== 0 && ptr[3].state !== 0) break; 452 | } 453 | } 454 | 455 | search45(arr: Vector2[], point: Vector2) { 456 | const allDir = [{x: 1, y: 1}, {x: 1, y: -1}, {x: -1, y: -1}, {x: -1, y: 1}]; 457 | const arr1 = []; 458 | for (const dir of allDir) { 459 | let v2 = this.cloneV2(point); 460 | let tag; 461 | while (this.isClear(v2) && 462 | (this.isClear({x: v2.x, y: v2.y + dir.y}) || this.isClear({x: v2.x + dir.x, y: v2.y}))) { 463 | if(v2.x === this.targetPoint.x && v2.y === this.targetPoint.y) { 464 | if(this.nowPoint.x === point.x && this.nowPoint.y === point.y) { 465 | // 直接查找 466 | this.hasFindTarget = true; 467 | } else { 468 | arr.push(this.cloneV2(v2)); 469 | } 470 | return; 471 | } 472 | if (tag && this.forcedNeighbour(v2, dir).length) { 473 | // 自身不搜索强制邻居 474 | arr.push(this.cloneV2(v2)); 475 | // 发现跳点不再搜索 476 | break; 477 | } 478 | tag = true; 479 | arr1.length = 0; 480 | this.searchBase(arr1, v2, [dir]); 481 | if(this.hasFindTarget) { 482 | // 发现终点 483 | if(!this.isInClosedList(v2)) { 484 | let pointData = new PathPointData(v2.x, v2.y); 485 | this.addToOpenList(pointData); 486 | this.nowPoint = this.mapTable.get(JPS.getKey(v2)) 487 | } 488 | return; 489 | } 490 | if(arr1.length > 0) { 491 | arr.push(this.cloneV2(v2)); 492 | } 493 | v2.x += dir.x; 494 | v2.y += dir.y; 495 | if(v2.x === this.targetPoint.x && v2.y === this.targetPoint.y) { 496 | // 终点 497 | if(this.nowPoint.x === point.x && this.nowPoint.y === point.y) { 498 | // 直接查找 499 | this.hasFindTarget = true; 500 | } else { 501 | arr.push(this.cloneV2(v2)); 502 | } 503 | return; 504 | } 505 | } 506 | } 507 | } 508 | 509 | /** 510 | * @description 寻路 511 | * @param {Vector2} bornPoint 出身点 512 | * @param {Vector2} targetPoint 目标点 513 | * @param {models} model 寻路模式 514 | * */ 515 | private hasFindTarget:boolean = false; 516 | public findGridPath(bornPoint: GameObject | Vector2, targetPoint: GameObject | Vector2, model: models): Vector2[] { 517 | this.hasFindTarget = false; 518 | this.clear(); 519 | this.model = model; //寻路模式 520 | let p1: PathPointData = this.getGridPosition(bornPoint); 521 | let p2: PathPointData = this.getGridPosition(targetPoint); 522 | if (!p1 || !p2 || 523 | this.fixClosedListMap.get(JPS.getKey(p1)) 524 | ) return []; //起点有问题 525 | 526 | this.nowPoint = this.bronPoint = this.mapTable.get(JPS.getKey(p1)); 527 | // 重置起点 528 | this.nowPoint.parent = null; 529 | this.targetPoint = this.mapTable.get(JPS.getKey(p2)); 530 | let paths: Vector2[] = []; //路径 531 | if (JPS.getKey(p1) === JPS.getKey(p2)) { 532 | //终点和起点重合 533 | paths.push(this.targetPoint); 534 | return paths; 535 | } 536 | let maxSearchAmount = 0; //重置搜寻次数 537 | 538 | //跳点 539 | const JPoint = []; 540 | while (!this.hasFindTarget) { 541 | this.addToClosedList(this.nowPoint); 542 | //水平方向查找 543 | if(!this.hasFindTarget) this.searchBase(JPoint, this.nowPoint, [{x: 1, y: 1}, {x: -1, y: -1}]); 544 | //45方向查找 545 | if(!this.hasFindTarget) this.search45(JPoint, this.nowPoint); 546 | 547 | if(this.hasFindTarget) { 548 | break; 549 | } 550 | for (const p of JPoint) { 551 | if(!this.isInClosedList(p)) { 552 | this.addToOpenList(p); 553 | } 554 | } 555 | JPoint.length = 0; 556 | this.nowPoint = this.removeMinFFromOpenList(); 557 | if (!this.nowPoint) return paths; //死路 558 | if(++maxSearchAmount > 666) break; 559 | } 560 | 561 | if(this.hasFindTarget) { 562 | let p = this.nowPoint; 563 | const paths = [this.targetPoint, p] 564 | while (p.parent) { 565 | paths.push(p.parent); 566 | p = p.parent; 567 | } 568 | return paths.reverse(); 569 | } 570 | return []; 571 | } 572 | 573 | /**@description 格子坐标转换为和地图同一坐标系的坐标 574 | * @param {Array} positions 格子坐标数组 575 | * @param {Vector2} anchor 各自坐标 576 | * @param {T} ctor 构造函数 577 | * */ 578 | public gridPositionConvertGameObjectPosition(positions: Vector2[], anchor: Vector2, ctor: V2): T[] { 579 | let res: T[] = []; 580 | for (const position of positions) { 581 | let x = position.x * this.mapData.gridLength + this.mapData.x + this.mapData.gridLength * anchor.x; 582 | let y = position.y * this.mapData.gridLength + this.mapData.y + this.mapData.gridLength * anchor.y; 583 | res.push(new ctor(x, y)); 584 | } 585 | return res; 586 | } 587 | 588 | /**@description 检测该点是否包含固定障碍物*/ 589 | public hasObstacle(v2: Vector2) { 590 | let res = true; 591 | try { 592 | res = !!this.fixClosedListMap.get(JPS.getKey(this.getGridPosition(v2))); 593 | } catch (e) { 594 | 595 | } 596 | return res; 597 | } 598 | 599 | /**@description 清理数据*/ 600 | private clear() { 601 | this.openList.length = 0; 602 | this.openListMap.clear(); 603 | this.closedListMap.clear(); 604 | this.bronPoint = null; 605 | this.targetPoint = null; 606 | this.nowPoint = null; 607 | } 608 | 609 | /**@description 计算F值*/ 610 | private F(p: PathPointData) { 611 | JPS.G(p); 612 | this.H(p); 613 | // p.F = p.G + p.H + p.K; 614 | p.F = p.G + p.H; 615 | } 616 | 617 | /**@description 计算到出生点的估值*/ 618 | private static G(p: PathPointData) { 619 | p.G = p.parent.G + Math.sqrt(Math.pow(p.x - p.parent.x, 2) + Math.pow(p.y - p.parent.y, 2)); 620 | } 621 | 622 | /**@description 计算到目标点的估值*/ 623 | private H(p: PathPointData) { 624 | p.H = Math.sqrt(Math.pow(this.targetPoint.x - p.x, 2) + Math.pow(this.targetPoint.y - p.y, 2)); 625 | } 626 | } 627 | -------------------------------------------------------------------------------- /Script/JPS.ts.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.1.0", 3 | "uuid": "7de52efd-6706-4d44-8bc2-8d12997bb697", 4 | "importer": "typescript", 5 | "isPlugin": false, 6 | "loadPluginInWeb": true, 7 | "loadPluginInNative": true, 8 | "loadPluginInEditor": false, 9 | "subMetas": {} 10 | } -------------------------------------------------------------------------------- /Texture.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.1.3", 3 | "uuid": "bc56be14-1739-4b97-b46f-0492f8d7d789", 4 | "importer": "folder", 5 | "isBundle": false, 6 | "bundleName": "", 7 | "priority": 1, 8 | "compressionType": {}, 9 | "optimizeHotUpdate": {}, 10 | "inlineSpriteFrames": {}, 11 | "isRemoteBundle": {}, 12 | "subMetas": {} 13 | } -------------------------------------------------------------------------------- /Texture/HelloWorld.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microcisco/jpsFindPath/a66370ef89b17b6d0bb9a632eff1a088cdbc20f9/Texture/HelloWorld.png -------------------------------------------------------------------------------- /Texture/HelloWorld.png.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "2.3.7", 3 | "uuid": "c9b414c5-dbf9-450a-8ad0-afb78347d623", 4 | "importer": "texture", 5 | "type": "sprite", 6 | "wrapMode": "clamp", 7 | "filterMode": "bilinear", 8 | "premultiplyAlpha": false, 9 | "genMipmaps": false, 10 | "packable": true, 11 | "width": 195, 12 | "height": 270, 13 | "platformSettings": {}, 14 | "subMetas": { 15 | "HelloWorld": { 16 | "ver": "1.0.6", 17 | "uuid": "84ff3a43-65d2-4062-8844-4ef5b12b0581", 18 | "importer": "sprite-frame", 19 | "rawTextureUuid": "c9b414c5-dbf9-450a-8ad0-afb78347d623", 20 | "trimType": "auto", 21 | "trimThreshold": 1, 22 | "rotated": false, 23 | "offsetX": 0, 24 | "offsetY": 0, 25 | "trimX": 0, 26 | "trimY": 0, 27 | "width": 195, 28 | "height": 270, 29 | "rawWidth": 195, 30 | "rawHeight": 270, 31 | "borderTop": 0, 32 | "borderBottom": 0, 33 | "borderLeft": 0, 34 | "borderRight": 0, 35 | "subMetas": {} 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Texture/singleColor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microcisco/jpsFindPath/a66370ef89b17b6d0bb9a632eff1a088cdbc20f9/Texture/singleColor.png -------------------------------------------------------------------------------- /Texture/singleColor.png.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "2.3.7", 3 | "uuid": "550c7cd8-d350-45df-a779-e49b8d8e1a94", 4 | "importer": "texture", 5 | "type": "sprite", 6 | "wrapMode": "clamp", 7 | "filterMode": "bilinear", 8 | "premultiplyAlpha": false, 9 | "genMipmaps": false, 10 | "packable": true, 11 | "width": 2, 12 | "height": 2, 13 | "platformSettings": {}, 14 | "subMetas": { 15 | "singleColor": { 16 | "ver": "1.0.6", 17 | "uuid": "bb53465d-ae17-4386-8e55-8beb050ccef9", 18 | "importer": "sprite-frame", 19 | "rawTextureUuid": "550c7cd8-d350-45df-a779-e49b8d8e1a94", 20 | "trimType": "auto", 21 | "trimThreshold": 1, 22 | "rotated": false, 23 | "offsetX": 0, 24 | "offsetY": 0, 25 | "trimX": 0, 26 | "trimY": 0, 27 | "width": 2, 28 | "height": 2, 29 | "rawWidth": 2, 30 | "rawHeight": 2, 31 | "borderTop": 0, 32 | "borderBottom": 0, 33 | "borderLeft": 0, 34 | "borderRight": 0, 35 | "subMetas": {} 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /creator.d.ts.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "2.0.2", 3 | "uuid": "d81be340-5c03-4c62-99ff-8cb230a732f7", 4 | "importer": "text", 5 | "subMetas": {} 6 | } -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microcisco/jpsFindPath/a66370ef89b17b6d0bb9a632eff1a088cdbc20f9/demo.gif -------------------------------------------------------------------------------- /demo.gif.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.3", 3 | "uuid": "24252b8d-dfff-420b-941f-4f31b35e4c2f", 4 | "importer": "asset", 5 | "subMetas": {} 6 | } -------------------------------------------------------------------------------- /global.d.ts: -------------------------------------------------------------------------------- 1 | declare module vv { 2 | //node边界框父节点名称 3 | export var boundary: string; 4 | //全部节点 5 | export var UICamera: cc.Node; 6 | export var GameCamera: cc.Node; 7 | export var Heroes: cc.Node; 8 | export var Enemies: cc.Node; 9 | export var Bullets: cc.Node; 10 | export var Props: cc.Node; 11 | export var Obstacles: cc.Node; 12 | export var Shadow: cc.Node; 13 | export var Blood: cc.Node; 14 | export var JumpChar: cc.Node; 15 | export var Abyss: cc.Node; 16 | export var UI: cc.Node; 17 | export var GameScene: cc.Node; 18 | export var LogicMap: cc.Node; 19 | export var Other: cc.Node; 20 | export var Trap: cc.Node; 21 | export var TrapOnBlood: cc.Node; 22 | export var Scent: cc.Node; 23 | export var Music: cc.Node; 24 | export var Leg: cc.Node; 25 | } -------------------------------------------------------------------------------- /global.d.ts.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "2.0.2", 3 | "uuid": "91353f6a-e438-4126-aa2c-9cd089b41638", 4 | "importer": "text", 5 | "subMetas": {} 6 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "lib": [ 5 | "dom", 6 | "es5", 7 | "es2015.promise", 8 | "es2015.collection" 9 | ], 10 | "target": "es5", 11 | "experimentalDecorators": true, 12 | "skipLibCheck": true 13 | }, 14 | "exclude": [ 15 | "node_modules", 16 | "library", 17 | "local", 18 | "temp", 19 | "build", 20 | "settings" 21 | ] 22 | } -------------------------------------------------------------------------------- /tsconfig.json.meta: -------------------------------------------------------------------------------- 1 | { 2 | "ver": "1.0.2", 3 | "uuid": "db1cb1a1-5c1a-49f3-8c2a-1c3e34235931", 4 | "importer": "json", 5 | "subMetas": {} 6 | } --------------------------------------------------------------------------------