session_controller.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. //距离比例
  2. const UP = 1
  3. const DOWN = 2
  4. const LEFT = 3
  5. const RIGHT = 4
  6. const RATIO = 0.6
  7. const NUM = 2
  8. cc.Class({
  9. extends: cc.Component,
  10. properties: {
  11. //是否可操作
  12. enable:{
  13. default:true,
  14. visible:false //编辑器属性管理器不可见
  15. },
  16. //当前进行reset的chunk的个数
  17. _reset:0,
  18. /**
  19. * resetChunk操作不一定触发refresh操作, refresh期数不一定+=1
  20. * 但一次reset(一系列resetChunk)操作只能触发一次refresh操作, 关系
  21. */
  22. //记录refresh操作的期数
  23. _term:0,
  24. score:{
  25. default:0,
  26. //visible:false, //编辑器属性管理器不可见
  27. visible:true, //编辑器属性管理器设置为可见
  28. },
  29. chunkPrefab:{
  30. default :null,
  31. type : cc.Prefab
  32. },
  33. //分数
  34. scoreNum:0
  35. },
  36. //初始化sessionCrl
  37. init:function(col, row){
  38. this._col = col
  39. this._row = row
  40. },
  41. //初始化子节点
  42. initChunk:function(chunk, col, row, type){
  43. chunk.x = chunk.width * col + chunk.width * 0.5 ;
  44. chunk.y = chunk.height * row + chunk.height * 0.5 ;
  45. chunk.type = type ;
  46. chunk.col = col ;
  47. chunk.row = row ;
  48. //刷新spirte
  49. chunk.controller.flush();
  50. //添加特效
  51. chunk.scaleX = 0 ;
  52. chunk.scaleY = 0 ;
  53. chunk.runAction(cc.scaleTo(0.6, 1, 1).easing(cc.easeCubicActionIn())) ;
  54. chunk.enable = true ; //chunk explode后会被设置为false
  55. },
  56. //复位节点
  57. resetChunk:function(chunk, col, row){
  58. var down ;
  59. var left ;
  60. var right ;
  61. var x = chunk.width * col + chunk.width * 0.5 ;
  62. var y = chunk.height * row + chunk.height * 0.5 ;
  63. //设置正确的位置
  64. chunk.col = col ;
  65. chunk.row = row ;
  66. //如果位置不正确则进行归位
  67. if(chunk.x != x || chunk.y != y){
  68. //_reset 计数+1
  69. this._reset += 1;
  70. //传入当前reset完成前时的term校验reset最多只触发一次refresh
  71. chunk.runAction(cc.sequence(cc.moveTo(0.4, x, y).easing(cc.easeCubicActionIn()), cc.callFunc(function(target, term){
  72. //可能该chunk已经被其他resetChunk流程引爆
  73. if(chunk.enable){
  74. //reset结束或再次进行消除判断
  75. let result = {col:0, row:0, up:0, down:0, left:0, right:0, success:false};
  76. result.col = chunk.col ;
  77. result.row = chunk.row ;
  78. // chunk result
  79. if((down = this.checkDown(result.col, result.row, chunk.type)) >= NUM){
  80. result.down = down ;
  81. result.success = true ;
  82. }
  83. left = this.checkLeft(result.col, result.row, chunk.type) ;
  84. right = this.checkRight(result.col, result.row, chunk.type) ;
  85. if((left + right) >= NUM){
  86. result.left = left ;
  87. result.right = right ;
  88. result.success = true ;
  89. }
  90. if(result.success){
  91. //此次reset触发refresh操作
  92. //但只能触发一次
  93. //如果已经触发过便无法再次触发
  94. if(this._term == term){
  95. this._term += 1 ;
  96. //如果还要简介递归调用则_reset += 1 ;
  97. this._reset += 1 ;
  98. this._map[result.col][result.row].controller.callback(this.refresh, this) ;
  99. }
  100. this.clear(result) ;
  101. }
  102. }
  103. //reset完成后计数-1
  104. this._reset -= 1 ;
  105. //_reset计数为0,reset流程结束,允许下次操作
  106. if(this._reset == 0){
  107. this.enable = true ;
  108. }
  109. },this, this._term))) ;
  110. }
  111. },
  112. //创建子节点
  113. createChild:function(width, height, col, row){
  114. var chunk = cc.instantiate(this.chunkPrefab)
  115. //初始化chunk 宽高
  116. chunk.width = width
  117. chunk.height = height
  118. //将节点的动画播组件设置为自身属性方便使用
  119. chunk.controller = chunk.getComponent("chunk_controller")
  120. //设置 chunk为触摸事件的最初目标
  121. chunk.on(cc.Node.EventType.TOUCH_START,function(event){})
  122. chunk.on(cc.Node.EventType.TOUCH_MOVE,function(event){})
  123. chunk.on(cc.Node.EventType.TOUCH_END,function(event){})
  124. chunk.on(cc.Node.EventType.TOUCH_CANCEL,function(event){})
  125. this.node.addChild(chunk)
  126. this.initChunk(chunk, col, row, this.randomType(col, row))
  127. return chunk
  128. },
  129. checkUp(col, row, type){
  130. var result = 0;
  131. for(let r = row +1; r < this._row ; r++){
  132. if(this._map[col][r].type == type){
  133. result += 1;
  134. }else{
  135. break ;
  136. }
  137. }
  138. return result ;
  139. },
  140. checkDown(col, row, type){
  141. var result = 0 ;
  142. for(let r = row-1; r >= 0; r--){
  143. if(this._map[col][r].type == type){
  144. result += 1;
  145. }else{
  146. break;
  147. }
  148. }
  149. return result ;
  150. },
  151. checkLeft(col, row, type){
  152. var result = 0 ;
  153. for (let c = col-1; c >= 0;c--){
  154. if(this._map[c][row].type == type){
  155. result += 1;
  156. }else{
  157. break ;
  158. }
  159. }
  160. return result ;
  161. },
  162. checkRight(col, row, type){
  163. var result = 0 ;
  164. for (let c = col+1; c < this._col; c++){
  165. if(this._map[c][row].type == type){
  166. result += 1;
  167. }else{
  168. break ;
  169. }
  170. }
  171. return result ;
  172. },
  173. //执行清除
  174. clear:function(result){
  175. if(result.success){
  176. //up
  177. for(let r = 1; r <= result.up; r++){
  178. this.score += 1 ;
  179. this._map[result.col][result.row + r].controller.explode();
  180. }
  181. //down
  182. for(let r = 1; r <= result.down; r++){
  183. this.score += 1 ;
  184. this._map[result.col][result.row - r].controller.explode();
  185. }
  186. //core
  187. this.score += 2 ;
  188. this._map[result.col][result.row].controller.explode() ;
  189. //left
  190. for(let c = 1; c <= result.left; c++){
  191. this.score += 1;
  192. this._map[result.col - c][result.row].controller.explode();
  193. }
  194. //right
  195. for(let c = 1; c <= result.right; c++){
  196. this.score += 1;
  197. this._map[result.col + c][result.row].controller.explode();
  198. }
  199. }
  200. },
  201. //清除结束后调用该回调
  202. refresh:function(event){
  203. for(let col = 0; col < this._col; col++){
  204. for(let row = 0; row < this._row; row++){
  205. if(this._map[col][row].enable){
  206. this.resetChunk(this._map[col][row], col, row) ;
  207. }else{
  208. this._map[col].push(this._map[col].splice(row, 1)[0])
  209. this.initChunk(this._map[col][this._row - 1], col, this._row - 1, this.randomType2(col, this._row - 1)) ;
  210. row -= 1;
  211. }
  212. }
  213. }
  214. //间接递归调用完成后_reset += 1
  215. this._reset -= 1 ;
  216. //此次消除后,没有需要复位的chunk,直接允许下次操作
  217. if(this._reset == 0){
  218. this.enable = true ;
  219. }
  220. },
  221. //清除逻辑
  222. exec:function(chunk, direction){
  223. var other ;
  224. var up ;
  225. var down ;
  226. var left ;
  227. var right ;
  228. var cresult = {col:0, row:0, up:0, down:0, left:0, right:0, success:false};
  229. var oresult = {col:0, row:0, up:0, down:0, left:0, right:0 ,success:false};
  230. oresult.col = chunk.col ;
  231. oresult.row = chunk.row ;
  232. switch(direction){
  233. case UP:
  234. other = this._map[chunk.col][chunk.row+1]
  235. cresult.col = other.col ;
  236. cresult.row = other.row ;
  237. // chunk result
  238. if (( up = this.checkUp(cresult.col, cresult.row, chunk.type)) >= NUM){
  239. cresult.up = up ;
  240. cresult.success = true ;
  241. }
  242. left = this.checkLeft(cresult.col, cresult.row, chunk.type)
  243. right = this.checkRight(cresult.col, cresult.row, chunk.type)
  244. if(left + right >= NUM){
  245. cresult.left = left ;
  246. cresult.right = right ;
  247. cresult.success = true ;
  248. }
  249. // other result
  250. if ((down = this.checkDown(oresult.col, oresult.row, other.type)) >= NUM){
  251. oresult.down = down ;
  252. oresult.success = true ;
  253. }
  254. left = this.checkLeft(oresult.col, oresult.row, other.type)
  255. right = this.checkRight(oresult.col, oresult.row, other.type)
  256. if(left + right >= NUM){
  257. oresult.left = left ;
  258. oresult.right = right ;
  259. oresult.success = true ;
  260. }
  261. break;
  262. case DOWN:
  263. other = this._map[chunk.col][chunk.row-1]
  264. cresult.col = other.col ;
  265. cresult.row = other.row ;
  266. // chunk result
  267. if((down = this.checkDown(cresult.col, cresult.row, chunk.type)) >= NUM){
  268. cresult.down = down ;
  269. cresult.success = true ;
  270. }
  271. left = this.checkLeft(cresult.col, cresult.row, chunk.type)
  272. right = this.checkRight(cresult.col, cresult.row, chunk.type)
  273. if(left + right >= NUM){
  274. cresult.left = left ;
  275. cresult.right = right ;
  276. cresult.success = true ;
  277. }
  278. // other result
  279. if((up = this.checkUp(oresult.col, oresult.row, other.type)) >= NUM){
  280. oresult.up = up ;
  281. oresult.success = true ;
  282. }
  283. left = this.checkLeft(oresult.col, oresult.row, other.type)
  284. right = this.checkRight(oresult.col, oresult.row, other.type)
  285. if(left + right >= NUM){
  286. oresult.left = left ;
  287. oresult.right = right ;
  288. oresult.success = true ;
  289. }
  290. break;
  291. case LEFT:
  292. other = this._map[chunk.col-1][chunk.row]
  293. cresult.col = other.col ;
  294. cresult.row = other.row ;
  295. // chunk result
  296. up = this.checkUp(cresult.col, cresult.row, chunk.type)
  297. down = this.checkDown(cresult.col, cresult.row, chunk.type)
  298. if(up + down >= NUM){
  299. cresult.up = up ;
  300. cresult.down = down ;
  301. cresult.success = true ;
  302. }
  303. if((left = this.checkLeft(cresult.col, cresult.row, chunk.type)) >= NUM){
  304. cresult.left = left ;
  305. cresult.success = true ;
  306. }
  307. // other result
  308. up = this.checkUp(oresult.col, oresult.row, other.type)
  309. down = this.checkDown(oresult.col, oresult.row, other.type)
  310. if(up + down >= NUM){
  311. oresult.up = up ;
  312. oresult.down = down ;
  313. oresult.success = true ;
  314. }
  315. if((right = this.checkRight(oresult.col, oresult.row, other.type)) >= NUM){
  316. oresult.right = right ;
  317. oresult.success = true
  318. }
  319. break;
  320. case RIGHT:
  321. other = this._map[chunk.col+1][chunk.row]
  322. cresult.col = other.col ;
  323. cresult.row = other.row ;
  324. // chunk result
  325. up = this.checkUp(cresult.col, cresult.row, chunk.type)
  326. down = this.checkDown(cresult.col, cresult.row, chunk.type)
  327. if(up + down >= NUM){
  328. cresult.up = up ;
  329. cresult.down = down ;
  330. cresult.success = true ;
  331. }
  332. if((right = this.checkRight(cresult.col, cresult.row, chunk.type)) >= NUM){
  333. cresult.right = right ;
  334. cresult.success = true
  335. }
  336. // other result
  337. up = this.checkUp(oresult.col, oresult.row, other.type)
  338. down = this.checkDown(oresult.col, oresult.row, other.type)
  339. if(up + down >= NUM){
  340. oresult.up = up ;
  341. oresult.down = down ;
  342. oresult.success = true ;
  343. }
  344. if((left = this.checkLeft(oresult.col, oresult.row, other.type)) >= NUM){
  345. oresult.left = left ;
  346. oresult.success = true ;
  347. }
  348. break;
  349. }
  350. //进行消除
  351. if(cresult.success || oresult.success){
  352. //执行交换逻辑
  353. this._map[chunk.col][chunk.row] = other;
  354. this._map[other.col][other.row] = chunk ;
  355. other.col = oresult.col ;
  356. other.row = oresult.row ;
  357. chunk.col = cresult.col ;
  358. chunk.row = cresult.row ;
  359. chunk.runAction(cc.moveTo(0.4, other.position));
  360. other.runAction(cc.sequence(cc.moveTo(0.4, chunk.position), cc.callFunc(function(){
  361. //调用refresh时先设置_reset += 1 ;
  362. this._reset += 1 ;
  363. //先设置清除回调
  364. if(cresult.success){
  365. this._map[cresult.col][cresult.row].controller.callback(this.refresh, this) ;
  366. }else {
  367. this._map[oresult.col][oresult.row].controller.callback(this.refresh,this) ;
  368. }
  369. this.clear(cresult)
  370. this.clear(oresult)
  371. //分数统计
  372. let scoreLabel = cc.find("Canvas/Background/score").getComponent(cc.Label);
  373. scoreLabel.string = this.scoreNum += 1;
  374. },this)));
  375. }else{
  376. //未成功则执行一段来回交换的动画,并在动画结束后结束,允许再次设置选择点
  377. chunk.runAction(cc.sequence(cc.moveTo(0.4, other.position), cc.delayTime(0.1), cc.moveTo(0.3, chunk.position)));
  378. other.runAction(cc.sequence(cc.moveTo(0.4, chunk.position), cc.delayTime(0.1), cc.moveTo(0.3, other.position), cc.callFunc(function(){
  379. this.enable = true ;
  380. }, this)));
  381. }
  382. },
  383. onTouchStart:function(event){
  384. if(this.enable){
  385. if(event.target != this.node){
  386. this.enable = false
  387. this._point.selected = true
  388. this._point.position = event.getLocation()
  389. //选中chunk特效添加
  390. event.target.scaleX *= 1.1
  391. event.target.scaleY *= 1.1
  392. }
  393. }
  394. },
  395. recover: function(event){
  396. //被选择chunk特效取消
  397. event.target.scaleX = 1
  398. event.target.scaleY = 1
  399. //选择点归零
  400. this._point.selected = false
  401. this._point.position = cc.Vec2(0,0)
  402. },
  403. onTouchMove:function(event){
  404. if(this._point.selected){
  405. var touchPos = event.getLocation()
  406. var hdistance = (touchPos.x - this._point.position.x) * (touchPos.x - this._point.position.x)
  407. var vdistance = (touchPos.y - this._point.position.y) * (touchPos.y - this._point.position.y)
  408. var distance = hdistance + vdistance ;
  409. var direction ;
  410. //如果触摸距离超过判定距离,则触发操作
  411. if(distance > this._max){
  412. if (hdistance > vdistance){
  413. if (touchPos.x > this._point.position.x){
  414. direction = RIGHT
  415. }else{
  416. direction = LEFT
  417. }
  418. }else{
  419. if (touchPos.y > this._point.position.y){
  420. direction = UP
  421. }else{
  422. direction = DOWN
  423. }
  424. }
  425. //终止对此次touch选择点的操作, clear this._point
  426. this.recover(event)
  427. if ((event.target.row == 0 && direction == DOWN) || (event.target.row == this._row-1 && direction == UP) || (event.target.col == 0 && direction == LEFT) || (event.target.col == this._col-1 && direction == RIGHT)){
  428. //超出边界,不能进行消除,直接再次允许设置选择点
  429. this.enable = true
  430. }else{
  431. //开始消除逻辑吧
  432. this.exec(event.target, direction)
  433. }
  434. }
  435. }
  436. },
  437. //触摸结束
  438. onTouchEnd:function(event){
  439. if(this._point.selected){
  440. //终止对此次touch选择点的操作, clear this._point
  441. this.recover(event)
  442. //允许再次设置选择点
  443. this.enable = true
  444. }
  445. },
  446. //触摸被中断取消
  447. onTouchCancel:function(event){
  448. if(this._point.selected){
  449. //终止对此次touch选择点的操作, clear this._point
  450. this.recover(event)
  451. //允许再次设置选择点
  452. this.enable = true
  453. }
  454. },
  455. //随机chunk的类型(load)
  456. randomType:function(col,row){
  457. var up ; //上面chunk的类型
  458. var left ; //左边chunk的类型
  459. var result ; //最终生成方块的类型
  460. if (col > 0 ){
  461. left = this._map[col-1][row].type
  462. }
  463. if (row > 0){
  464. up = this._map[col][row-1].type
  465. }
  466. do{
  467. result = Math.round((Math.random()*5))+1
  468. }while(result == up || result == left) ;
  469. return result
  470. },
  471. //随机chunk的类型(复用)
  472. randomType2:function(col,row){
  473. var up ; //上面chunk的类型
  474. var down ; //下面chunk的类型
  475. var left ; //左边chunk的类型
  476. var right ; //右边chunk的类型
  477. var result ; //最终生成方块的类型
  478. if((row < this._row - 1) && this._map[col][row + 1].enable){
  479. up = this._map[col][row + 1].type ;
  480. }
  481. if (row > 0){
  482. down = this._map[col][row - 1].type ;
  483. }
  484. if (col > 0 ){
  485. left = this._map[col - 1][row].type ;
  486. }
  487. if ((col < this._col - 1) && this._map[col+1][row].enable){
  488. right = this._map[col + 1][row].type ;
  489. }
  490. do{
  491. result = Math.round((Math.random()*5))+1
  492. }while(result == up || result == down || result == left || result == right) ;
  493. return result ;
  494. },
  495. onLoad :function(){
  496. //计算每个chunk的size
  497. var width = this.node.width / this._col
  498. var height = this.node.height / this._row
  499. //初始化chunk—map
  500. this._map = new Array(this._col)
  501. for (let col = 0 ; col < this._col ; col++){
  502. this._map[col] = new Array(this._row)
  503. for ( let row = 0 ; row < this._row; row ++){
  504. this._map[col][row] = this.createChild(width, height,col, row)
  505. }
  506. }
  507. //初始化 touch-move-max-distance
  508. this._max = (width * width + height * height) * RATIO
  509. //初始化 touch-point
  510. this._point = {
  511. selected:false,
  512. position:cc.Vec2(0,0)
  513. }
  514. //初始化touch事件监听
  515. this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this)
  516. this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this)
  517. this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this)
  518. this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this)
  519. }
  520. });