main.back.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. import Support from "./base/support";
  2. // import Animation from "./base/animation";
  3. //
  4. let support = new Support()
  5. // let animation = new Animation()
  6. var board = new Array();
  7. var score = 0;
  8. var topScore = 0;
  9. var hasConflicted = new Array();
  10. var direction = {
  11. left: 1,
  12. up: 2,
  13. down: 3,
  14. right: 4
  15. };
  16. // import Player from './player/index'
  17. // import Support from '../js/base/support'
  18. /**
  19. * 底层背景, 读取屏幕的宽高, 设置棋盘边长
  20. */
  21. let context = canvas.getContext('2d')
  22. var bgw = canvas.width
  23. var bgh = canvas.height
  24. console.log(bgw, bgh)
  25. var bdsl = 0.92 * bgw
  26. let startX //触摸时的坐标
  27. let startY
  28. let x //滑动的距离
  29. let y
  30. let aboveY = 0 // 设一个全局变量记录上一次内部块滑动的位置
  31. /**
  32. * 游戏主函数
  33. */
  34. export default class Main {
  35. constructor() {
  36. this.backGround()
  37. // 维护当前requestAnimationFrame的id
  38. this.aniId = 0
  39. this.restart()
  40. }
  41. backGround() {
  42. context.fillStyle = '#F0F0F0'
  43. context.fillRect(0, 0, bgw, bgh)
  44. context.fillStyle = '#8F7A66'
  45. context.fillRect(0.05 * bgw, 50, 0.2 * bgw, 0.16 * bgw)
  46. context.fillStyle = '#BAAB9E'
  47. context.fillRect(0.3 * bgw, 50, 0.3 * bgw, 0.16 * bgw)
  48. context.fillStyle = '#F7921E'
  49. context.fillRect(0.65 * bgw, 50, 0.3 * bgw, 0.16 * bgw)
  50. context.fillStyle = 'white'
  51. context.font = "30px Arial"
  52. context.fillText("重玩", 0.07 * bgw, 50 + 0.1 * bgw);
  53. context.font = "20px Arial"
  54. context.fillText("最高分数", 0.35 * bgw, 50 + 0.06 * bgw);
  55. context.fillText("当前分数", 0.7 * bgw, 50 + 0.06 * bgw);
  56. // 棋盘背景
  57. context.fillStyle = '#BBADA0'
  58. context.fillRect(0.04 * bgw, 0.45 * bgw, bdsl, bdsl)
  59. }
  60. restart() {
  61. //初始化棋盘格
  62. this.init();
  63. //在随机两个格子生成数字
  64. this.generateOneNumber();
  65. this.generateOneNumber();
  66. this.updateBoardView();
  67. score = 0;
  68. // canvas.removeEventListener(
  69. // 'touchstart',
  70. // this.touchHandler
  71. // )
  72. // this.bg = new BackGround(ctx)
  73. // this.player = new Player(ctx)
  74. // this.gameinfo = new GameInfo()
  75. // this.music = new Music()
  76. // this.bindLoop = this.loop.bind(this)
  77. this.hasEventBind = false
  78. // 清除上一局的动画
  79. // window.cancelAnimationFrame(this.aniId);
  80. // this.aniId = window.requestAnimationFrame(
  81. // this.bindLoop,
  82. // canvas
  83. // )
  84. // 监听滑动事件
  85. canvas.addEventListener('touchstart', this.touchStart.bind(this), false);
  86. canvas.addEventListener('touchmove', this.touchMove.bind(this), false);
  87. canvas.addEventListener('touchend', this.touchEnd.bind(this), false);
  88. }
  89. init() {
  90. for (var i = 0; i < 4; i++) {
  91. for (var j = 0; j < 4; j++) {
  92. context.fillStyle = '#CCC0B3'
  93. context.fillRect(support.getPostionLeft(i, j) + 0.03 * bgw, support.getPostionTop(i, j) + 0.44 * bgw, 0.214 * bdsl, 0.214 * bdsl)
  94. }
  95. }
  96. //初始化棋盘
  97. for (var i = 0; i < 4; i++) {
  98. board[i] = new Array();
  99. hasConflicted[i] = new Array();
  100. for (var j = 0; j < 4; j++) {
  101. board[i][j] = 0;
  102. hasConflicted[i][j] = false;
  103. }
  104. }
  105. console.log(board);
  106. //更新面板
  107. this.updateBoardView();
  108. }
  109. updateBoardView() {
  110. // context.clearRect(0.04*bgw, 0.45*bgw, bdsl, bdsl) //更新之前先删除元素
  111. // context.fillRect(0.04*bgw, 0.45*bgw, bdsl, bdsl)
  112. for (var i = 0; i < 4; i++) {
  113. for (var j = 0; j < 4; j++) {
  114. //重新生成16个矩形, 并添加到容器中
  115. var offScreenCanvas = wx.createCanvas()
  116. var offContext = offScreenCanvas.getContext('2d')
  117. if (board[i][j] == 0) {
  118. offContext.fillStyle = '#CCC0B3'
  119. offContext.fillRect(support.getPostionLeft(i, j) + 0.04 * bgw, support.getPostionTop(i, j) + 0.44 * bgw, 0.214 * bdsl, 0.214 * bdsl)
  120. // 绘制无字空图
  121. context.drawImage(offScreenCanvas, 0, 0)
  122. } else {
  123. //根据数字颜色设置器背景色
  124. offContext.fillStyle = support.getBackgroundColorByNum(board[i][j])
  125. offContext.fillRect(support.getPostionLeft(i, j) + 0.04 * bgw, support.getPostionTop(i, j) + 0.44 * bgw, 0.214 * bdsl, 0.214 * bdsl)
  126. //设置前景字颜色
  127. offContext.fillStyle = support.getPreColorByNum(board[i][j])
  128. //显示数字(文字)
  129. offContext.font = "18px Arial"
  130. offContext.fillText(support.getShowTextByNum(board[i][j]), support.getPostionLeft(i, j) + 0.05 * bgw, support.getPostionTop(i, j) + 0.55 * bgw);
  131. context.drawImage(offScreenCanvas, 0, 0)
  132. hasConflicted[i][j] = false;
  133. }
  134. }
  135. }
  136. }
  137. generateOneNumber() {
  138. if (support.isNoSpace(board)) {
  139. return false;
  140. }
  141. //随机一个位置
  142. var randx = parseInt(Math.floor(Math.random() * 4));
  143. var randy = parseInt(Math.floor(Math.random() * 4));
  144. //判断生成的坐标是否合理(无值,位置即可使用)
  145. while (true) {
  146. if (board[randx][randy] === 0)
  147. break;
  148. //若果该坐标存在了值,即不合理,继续生成随机一个位置
  149. randx = parseInt(Math.floor(Math.random() * 4));
  150. randy = parseInt(Math.floor(Math.random() * 4));
  151. }
  152. //随机一个数字
  153. var randNum = Math.random() < 0.4 ? 2 : 4;
  154. board[randx][randy] = randNum;
  155. showNumberWithAnimation(randx, randy, randNum);
  156. return true;
  157. }
  158. /**
  159. * 滑动处理 1, 左滑; 2, 上滑, 3, 右滑; 4, 下滑
  160. */
  161. slideDirection(numm) {
  162. switch (numm) {
  163. case 1: //left
  164. if (this.moveLeft()) {
  165. setTimeout(this.generateOneNumber, 210);
  166. setTimeout(this.isGameOver, 300);
  167. }
  168. break;
  169. case 2: //up
  170. if (this.moveUp()) {
  171. setTimeout(this.generateOneNumber, 210);
  172. setTimeout(this.isGameOver, 300);
  173. }
  174. break;
  175. case 3: //right
  176. if (this.moveRight()) {
  177. setTimeout(this.generateOneNumber, 210);
  178. setTimeout(this.isGameOver, 300);
  179. }
  180. break;
  181. case 4: //down
  182. if (this.moveDown()) {
  183. setTimeout(this.generateOneNumber, 210);
  184. setTimeout(this.isGameOver, 300);
  185. }
  186. break;
  187. default:
  188. break;
  189. }
  190. }
  191. moveLeft() {
  192. if (!support.canMove(board, direction.left))
  193. return false;
  194. //左移
  195. for (var i = 0; i < 4; i++) {
  196. for (var j = 1; j < 4; j++) {
  197. if (board[i][j] !== 0) {
  198. for (var k = 0; k < j; k++)
  199. //可以一次移动多个格子
  200. if (board[i][k] == 0 && support.noBlockHorizontal(i, k, j, board)) {
  201. //move
  202. // showMoveAnimation(i, j, i, k);
  203. board[i][k] = board[i][j];
  204. board[i][j] = 0;
  205. continue;
  206. } else if (board[i][k] == board[i][j] && support.noBlockHorizontal(i, k, j, board) && !hasConflicted[i][k]) {
  207. //move
  208. // showMoveAnimation(i, j, i, k);
  209. //add
  210. board[i][k] += board[i][j];
  211. board[i][j] = 0;
  212. // var element = $("#grid-cell-" + i + k);
  213. // anp(element, board[i][k])
  214. score += board[i][k];
  215. this.updateScore(score);
  216. // updateTopScore(score);
  217. continue;
  218. }
  219. }
  220. }
  221. }
  222. setTimeout(this.updateBoardView, 200); //等待200在执行更新面板操作,避免动画效果被冲掉
  223. return true
  224. }
  225. moveRight() {
  226. if (!support.canMove(board, direction.right))
  227. return false;
  228. //右移
  229. for (var i = 3; i >= 0; i--) {
  230. for (var j = 2; j >= 0; j--) {
  231. //该位置不等于0即可进行移动
  232. if (board[i][j] != 0)
  233. for (var k = 3; k > j; k--) {
  234. //如果可以一次移动多个格子
  235. if (board[i][k] == 0 && support.noBlockHorizontal(i, j, k, board)) {
  236. //move
  237. // showMoveAnimation(i, j, i, k);
  238. board[i][k] = board[i][j];
  239. board[i][j] = 0;
  240. continue;
  241. } else if (board[i][k] == board[i][j] && support.noBlockHorizontal(i, j, k, board) && !hasConflicted[i][k]) {
  242. //move
  243. // showMoveAnimation(i, j, i, k);
  244. //add
  245. board[i][k] += board[i][j];
  246. board[i][j] = 0;
  247. score += board[i][k];
  248. // var element = $("#grid-cell-" + i + k);
  249. // anp(element, board[i][k])
  250. this.updateScore(score);
  251. // updateTopScore(score);
  252. continue;
  253. }
  254. }
  255. }
  256. }
  257. setTimeout(this.updateBoardView, 200); //等待200在执行更新面板操作,避免动画效果被冲掉
  258. return true
  259. }
  260. /**
  261. 先判断第一列*/
  262. moveUp() {
  263. if (!support.canMove(board, direction.up))
  264. return false;
  265. for (var i = 0; i < 4; i++) {
  266. for (var j = 1; j < 4; j++) {
  267. //该位置不为0即可进行移动
  268. if (board[j][i] != 0) {
  269. for (var k = 0; k < j; k++) {
  270. if (board[k][i] == 0 && support.noBlockVectal(i, k, j, board)) {
  271. //move
  272. // showMoveAnimation(j, i, k, i);
  273. board[k][i] = board[j][i];
  274. board[j][i] = 0;
  275. continue;
  276. } else if (board[k][i] == board[j][i] && support.noBlockVectal(i, k, j, board) && !hasConflicted[k][i]) {
  277. //move
  278. // showMoveAnimation(j, i, k, i);
  279. board[k][i] += board[j][i];
  280. board[j][i] = 0;
  281. score += board[k][i];
  282. // var element = $("#grid-cell-" + k + i);
  283. // anp(element, board[k][i])
  284. this.updateScore(score);
  285. continue;
  286. }
  287. }
  288. }
  289. }
  290. }
  291. setTimeout(this.updateBoardView, 200); //等待200在执行更新面板操作,避免动画效果被冲掉
  292. return true
  293. }
  294. /**
  295. 先判断第一列*/
  296. moveDown() {
  297. if (!support.canMove(board, direction.down))
  298. return false;
  299. for (var i = 3; i >= 0; i--) {
  300. for (var j = 2; j >= 0; j--) {
  301. //该位置不为0即可进行移动
  302. if (board[j][i] != 0) {
  303. for (var k = 3; k > j; k--) {
  304. if (board[k][i] == 0 && support.noBlockVectal(i, j, k, board)) {
  305. //move
  306. // showMoveAnimation(j, i, k, i);
  307. board[k][i] = board[j][i];
  308. board[j][i] = 0;
  309. continue;
  310. } else if (board[k][i] == board[j][i] && support.noBlockVectal(i, j, k, board) && !hasConflicted[k][i]) {
  311. //move
  312. // showMoveAnimation(j, i, k, i);
  313. board[k][i] += board[j][i];
  314. board[j][i] = 0;
  315. score += board[k][i];
  316. // var element = $("#grid-cell-" + k + i);
  317. // anp(element, board[k][i])
  318. this.updateScore(score);
  319. continue;
  320. }
  321. }
  322. }
  323. }
  324. }
  325. // this.updateBoardView()
  326. setTimeout(this.updateBoardView, 200); //等待200在执行更新面板操作,避免动画效果被冲掉
  327. return true
  328. }
  329. isGameOver() {
  330. if (support.isNoSpace(board) && !support.canMoveALL(board)) {
  331. this.gameOver();
  332. }
  333. }
  334. gameOver() {
  335. alert("游戏结束!");
  336. }
  337. touchStart(e) { //触摸开始
  338. e.preventDefault();
  339. var touch = e.touches[0];
  340. startX = touch.pageX; //刚触摸时的坐标
  341. startY = touch.pageY; //刚触摸时的坐标
  342. }
  343. touchMove(e) { //滑动
  344. e.preventDefault();
  345. var touch = e.touches[0];
  346. x = touch.pageX - startX; //滑动的距离
  347. y = touch.pageY - startY; //滑动的距离
  348. }
  349. touchEnd(e) { //手指离开屏幕
  350. // console.log(x);
  351. // console.log(y);
  352. var xy = Math.abs(x) - Math.abs(y);
  353. var d = 0;
  354. if (xy > 0) {
  355. if (x >= 0) {
  356. d = 3;
  357. } else {
  358. d = 1;
  359. }
  360. } else {
  361. if (y >= 0) {
  362. d = 4;
  363. } else {
  364. d = 2;
  365. }
  366. }
  367. this.slideDirection(d);
  368. }
  369. /**
  370. *
  371. * 更新最新分数和最高分数
  372. */
  373. updateScore(score) {
  374. // $("#score").text(score);
  375. if (topScore < score) {
  376. // $("#top_score").text(score);
  377. topScore = score;
  378. return true;
  379. } else {
  380. return true;
  381. // $("#top_score").text(topScore);
  382. }
  383. }
  384. // 游戏结束后的触摸事件处理逻辑
  385. // touchEventHandler(e) {
  386. // e.preventDefault()
  387. // let x = e.touches[0].clientX
  388. // let y = e.touches[0].clientY
  389. // let area = this.gameinfo.btnArea
  390. // if (x >= area.startX &&
  391. // x <= area.endX &&
  392. // y >= area.startY &&
  393. // y <= area.endY)
  394. // this.restart()
  395. // }
  396. }
  397. /********************* animation */
  398. function showNumberWithAnimation(randx, randy, randNum) {
  399. var offScreenCanvas = wx.createCanvas()
  400. var offContext = offScreenCanvas.getContext('2d')
  401. offContext.fillStyle = support.getBackgroundColorByNum(randNum)
  402. offContext.fillRect(support.getPostionLeft(randx, randy) + 0.03 * bgw, support.getPostionTop(randx, randy) + 0.44 * bgw, 0.22 * bdsl, 0.214 * bdsl)
  403. offContext.fillStyle = support.getPreColorByNum(randNum)
  404. offContext.font = "18px Arial"
  405. //显示数字
  406. offContext.fillText(support.getShowTextByNum(randNum), support.getPostionLeft(randx, randy) + 0.05 * bgw, support.getPostionTop(randx, randy) + 0.55 * bgw)
  407. context.drawImage(offScreenCanvas, 0, 0)
  408. // numberCell.animate({
  409. // width: cellSideLength,
  410. // height: cellSideLength,
  411. // top: getPostionTop(randx, randy),
  412. // left: getPostionLeft(randx, randy)
  413. // }, 100);
  414. }