main.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. import BackGround from './base/background'
  2. import Support from "./base/support"
  3. wx.setPreferredFramesPerSecond(12)
  4. wx.showShareMenu()
  5. let ctx = canvas.getContext('2d')
  6. var w = canvas.width
  7. var h = canvas.height
  8. var csl = 0.18 * w
  9. var fsz = 0.07 * w
  10. var fontstyle = fsz + "px 楷体"
  11. let sp = new Support(w, h)
  12. var board = new Array();
  13. var score = 0;
  14. var topScore = 0;
  15. var hasConflicted = new Array();
  16. var direction = {
  17. left: 1,
  18. up: 2,
  19. down: 3,
  20. right: 4
  21. };
  22. let startX //触摸时的坐标
  23. let startY
  24. let x //滑动的距离
  25. let y
  26. /**
  27. * 游戏主函数
  28. */
  29. export default class Main {
  30. constructor() {
  31. // 维护当前requestAnimationFrame的id
  32. this.aniId = 0
  33. this.restart()
  34. // 激活重启按钮事件
  35. wx.onTouchStart(this.touchEventHandler.bind(this))
  36. // 开启滑动事件监听
  37. wx.onTouchStart(this.touchStart)
  38. wx.onTouchMove(this.touchMove)
  39. wx.onTouchEnd(this.touchEnd.bind(this))
  40. }
  41. restart() {
  42. // console.log(w, h)
  43. this.bg = new BackGround(ctx, w, h)
  44. // 获取本地存储的最高分数(若有)
  45. wx.getStorage({
  46. key: "topScore",
  47. success(res) {
  48. // console.log(res.data)
  49. topScore = res.data
  50. }
  51. })
  52. // 重置当前分数
  53. score = 0;
  54. // 显示新分数
  55. this.updateScore(score)
  56. // 初始化棋盘格
  57. this.init();
  58. // 在随机两个格子生成数字
  59. this.generateOneNumber();
  60. this.generateOneNumber();
  61. // 更新游戏面板
  62. this.render();
  63. }
  64. init() {
  65. for (var i = 0; i < 4; i++) {
  66. for (var j = 0; j < 4; j++) {
  67. ctx.fillStyle = '#CCC0B3'
  68. ctx.fillRect(sp.getPostionLeft(i, j), sp.getPostionTop(i, j), csl, csl)
  69. }
  70. }
  71. //初始化棋盘
  72. for (var i = 0; i < 4; i++) {
  73. board[i] = new Array();
  74. hasConflicted[i] = new Array();
  75. for (var j = 0; j < 4; j++) {
  76. board[i][j] = 0;
  77. hasConflicted[i][j] = false;
  78. }
  79. }
  80. // console.log(board);
  81. //更新面板
  82. this.render();
  83. }
  84. // 棋盘重绘
  85. render() {
  86. // 清空棋盘, 重新刷新
  87. ctx.clearRect(20.04 * w, 50 + 0.3 * w, 0.92 * w, 0.92 * w);
  88. ctx.fillStyle = '#BBADA0'
  89. ctx.fillRect(0.04 * w, 50 + 0.3 * w, 0.92 * w, 0.92 * w)
  90. for (var i = 0; i < 4; i++) {
  91. for (var j = 0; j < 4; j++) {
  92. if (board[i][j] == 0) {
  93. // 绘制无字空图
  94. ctx.fillStyle = '#CCC0B3'
  95. ctx.fillRect(sp.getPostionLeft(i, j), sp.getPostionTop(i, j), csl, csl)
  96. } else {
  97. // 根据数字颜色设置器背景色
  98. ctx.fillStyle = sp.getBackgroundColorByNum(board[i][j])
  99. ctx.fillRect(sp.getPostionLeft(i, j), sp.getPostionTop(i, j), csl, csl)
  100. // 设置文字颜色, 大小, 字体, 对其方式
  101. ctx.fillStyle = sp.getPreColorByNum(board[i][j])
  102. // 显示数字(文字)
  103. ctx.font = fontstyle
  104. ctx.textAlign = "left"
  105. ctx.textBaseline = "top"
  106. // 获取文字
  107. var st = sp.getShowTextByNum(board[i][j])
  108. // 将4字分两行绘制(有5字的份为前3后2)
  109. var st2 = st.slice(-2)
  110. var st1 = st.slice(0, st.length - 2)
  111. ctx.fillText(st1, sp.getPostionLeft(i, j) + 0.02 * w, sp.getPostionTop(i, j) + 0.01 * w);
  112. ctx.fillText(st2, sp.getPostionLeft(i, j) + 0.02 * w, sp.getPostionTop(i, j) + fsz + 0.02 * w);
  113. hasConflicted[i][j] = false;
  114. }
  115. }
  116. }
  117. }
  118. generateOneNumber() {
  119. if (sp.isNoSpace(board)) {
  120. return false;
  121. }
  122. //随机一个位置
  123. var randx = parseInt(Math.floor(Math.random() * 4));
  124. var randy = parseInt(Math.floor(Math.random() * 4));
  125. //判断生成的坐标是否合理(无值,位置即可使用)
  126. while (true) {
  127. if (board[randx][randy] === 0)
  128. break;
  129. //若果该坐标存在了值,即不合理,继续生成随机一个位置
  130. randx = parseInt(Math.floor(Math.random() * 4));
  131. randy = parseInt(Math.floor(Math.random() * 4));
  132. }
  133. //随机一个数字
  134. var randNum = Math.random() < 0.6 ? 2 : 4;
  135. board[randx][randy] = randNum;
  136. // showNumberWithAnimation(randx, randy, randNum);
  137. this.render()
  138. return true;
  139. }
  140. /**
  141. * 滑动处理 1, 左滑; 2, 上滑, 3, 右滑; 4, 下滑
  142. */
  143. slideDirection(numm) {
  144. switch (numm) {
  145. case 1: //left
  146. if (this.moveLeft()) {
  147. setTimeout(this.generateOneNumber.bind(this), 210);
  148. setTimeout(this.isGameOver.bind(this), 300);
  149. }
  150. break;
  151. case 2: //up
  152. if (this.moveUp()) {
  153. setTimeout(this.generateOneNumber.bind(this), 210);
  154. setTimeout(this.isGameOver.bind(this), 300);
  155. }
  156. break;
  157. case 3: //right
  158. if (this.moveRight()) {
  159. setTimeout(this.generateOneNumber.bind(this), 210);
  160. setTimeout(this.isGameOver.bind(this), 300);
  161. }
  162. break;
  163. case 4: //down
  164. if (this.moveDown()) {
  165. setTimeout(this.generateOneNumber.bind(this), 210);
  166. setTimeout(this.isGameOver.bind(this), 300);
  167. }
  168. break;
  169. default:
  170. break;
  171. }
  172. }
  173. moveLeft() {
  174. if (!sp.canMove(board, direction.left))
  175. return false;
  176. //左移
  177. for (var i = 0; i < 4; i++) {
  178. for (var j = 1; j < 4; j++) {
  179. if (board[i][j] !== 0) {
  180. for (var k = 0; k < j; k++)
  181. //可以一次移动多个格子
  182. if (board[i][k] == 0 && sp.noBlockHorizontal(i, k, j, board)) {
  183. //move
  184. // showMoveAnimation(i, j, i, k);
  185. board[i][k] = board[i][j];
  186. board[i][j] = 0;
  187. continue;
  188. } else if (board[i][k] == board[i][j] && sp.noBlockHorizontal(i, k, j, board) && !hasConflicted[i][k]) {
  189. //move
  190. // showMoveAnimation(i, j, i, k);
  191. //add
  192. board[i][k] += board[i][j];
  193. board[i][j] = 0;
  194. // var element = $("#grid-cell-" + i + k);
  195. // anp(element, board[i][k])
  196. score += board[i][k];
  197. this.updateScore(score)
  198. continue;
  199. }
  200. }
  201. }
  202. }
  203. setTimeout(this.render, 200); //等待200在执行更新面板操作,避免动画效果被冲掉
  204. return true
  205. }
  206. moveRight() {
  207. if (!sp.canMove(board, direction.right))
  208. return false;
  209. //右移
  210. for (var i = 3; i >= 0; i--) {
  211. for (var j = 2; j >= 0; j--) {
  212. //该位置不等于0即可进行移动
  213. if (board[i][j] != 0)
  214. for (var k = 3; k > j; k--) {
  215. //如果可以一次移动多个格子
  216. if (board[i][k] == 0 && sp.noBlockHorizontal(i, j, k, board)) {
  217. //move
  218. // showMoveAnimation(i, j, i, k);
  219. board[i][k] = board[i][j];
  220. board[i][j] = 0;
  221. continue;
  222. } else if (board[i][k] == board[i][j] && sp.noBlockHorizontal(i, j, k, board) && !hasConflicted[i][k]) {
  223. //move
  224. // showMoveAnimation(i, j, i, k);
  225. //add
  226. board[i][k] += board[i][j];
  227. board[i][j] = 0;
  228. score += board[i][k];
  229. // var element = $("#grid-cell-" + i + k);
  230. // anp(element, board[i][k])
  231. this.updateScore(score)
  232. continue;
  233. }
  234. }
  235. }
  236. }
  237. setTimeout(this.render, 200); //等待200在执行更新面板操作,避免动画效果被冲掉
  238. return true
  239. }
  240. /**
  241. 先判断第一列*/
  242. moveUp() {
  243. if (!sp.canMove(board, direction.up))
  244. return false;
  245. for (var i = 0; i < 4; i++) {
  246. for (var j = 1; j < 4; j++) {
  247. //该位置不为0即可进行移动
  248. if (board[j][i] != 0) {
  249. for (var k = 0; k < j; k++) {
  250. if (board[k][i] == 0 && sp.noBlockVectal(i, k, j, board)) {
  251. //move
  252. // showMoveAnimation(j, i, k, i);
  253. board[k][i] = board[j][i];
  254. board[j][i] = 0;
  255. continue;
  256. } else if (board[k][i] == board[j][i] && sp.noBlockVectal(i, k, j, board) && !hasConflicted[k][i]) {
  257. //move
  258. // showMoveAnimation(j, i, k, i);
  259. board[k][i] += board[j][i];
  260. board[j][i] = 0;
  261. score += board[k][i];
  262. // var element = $("#grid-cell-" + k + i);
  263. // anp(element, board[k][i])
  264. this.updateScore(score);
  265. continue;
  266. }
  267. }
  268. }
  269. }
  270. }
  271. setTimeout(this.render, 200); //等待200在执行更新面板操作,避免动画效果被冲掉
  272. return true
  273. }
  274. /**
  275. 先判断第一列*/
  276. moveDown() {
  277. if (!sp.canMove(board, direction.down))
  278. return false;
  279. for (var i = 3; i >= 0; i--) {
  280. for (var j = 2; j >= 0; j--) {
  281. //该位置不为0即可进行移动
  282. if (board[j][i] != 0) {
  283. for (var k = 3; k > j; k--) {
  284. if (board[k][i] == 0 && sp.noBlockVectal(i, j, k, board)) {
  285. //move
  286. // showMoveAnimation(j, i, k, i);
  287. board[k][i] = board[j][i];
  288. board[j][i] = 0;
  289. continue;
  290. } else if (board[k][i] == board[j][i] && sp.noBlockVectal(i, j, k, board) && !hasConflicted[k][i]) {
  291. //move
  292. // showMoveAnimation(j, i, k, i);
  293. board[k][i] += board[j][i];
  294. board[j][i] = 0;
  295. score += board[k][i];
  296. // var element = $("#grid-cell-" + k + i);
  297. // anp(element, board[k][i])
  298. this.updateScore(score);
  299. continue;
  300. }
  301. }
  302. }
  303. }
  304. }
  305. // this.render()
  306. setTimeout(this.render, 200) //等待200在执行更新面板操作,避免动画效果被冲掉
  307. return true
  308. }
  309. isGameOver() {
  310. if (sp.isNoSpace(board) && !sp.canMoveAll(board)) {
  311. this.gameOver()
  312. }
  313. }
  314. gameOver() {
  315. // 本地存储最高分数
  316. wx.setStorage({
  317. key: "topScore",
  318. data: topScore
  319. })
  320. // 棋盘中出现 游戏结束!C2B6AB
  321. ctx.fillStyle = '#F7921E'
  322. ctx.fillRect(0.2 * w, 50 + 0.56 * w, 0.6 * w, 0.4 * w)
  323. ctx.fillStyle = 'white'
  324. ctx.font = "40px 微软雅黑"
  325. ctx.textAlign = "center"
  326. ctx.textBaseline = "middle"
  327. ctx.fillText("游戏结束!", 0.5 * w, 50 + 0.76 * w);
  328. console.log("游戏结束!")
  329. // alert("游戏结束!")
  330. }
  331. /**
  332. * 滑动处理 touchStart 记录起点; touchMove 记录x,y方向分别移动的距离; touchEnd 判断移动方向
  333. */
  334. touchStart(e) {
  335. var touch = e.touches[0]
  336. startX = touch.pageX //刚触摸时的坐标
  337. startY = touch.pageY //刚触摸时的坐标
  338. }
  339. touchMove(e) { //滑动
  340. var touch = e.touches[0]
  341. x = touch.pageX - startX //滑动的距离
  342. y = touch.pageY - startY //滑动的距离
  343. }
  344. touchEnd(e) { //手指离开屏幕
  345. // console.log(x)
  346. // console.log(y)
  347. var xy = Math.abs(x) - Math.abs(y)
  348. var d = 0
  349. if (xy > 0) {
  350. if (x >= 0) {
  351. d = 3
  352. } else {
  353. d = 1
  354. }
  355. } else {
  356. if (y >= 0) {
  357. d = 4
  358. } else {
  359. d = 2
  360. }
  361. }
  362. this.slideDirection(d)
  363. }
  364. /**
  365. *
  366. * 更新最新分数和最高分数
  367. */
  368. updateScore(score) {
  369. // 清除去原分数
  370. ctx.clearRect(0.28 * w, 50 + 0.08 * w, 0.32 * w, 0.08 * w);
  371. ctx.fillStyle = '#BAAB9E'
  372. ctx.fillRect(0.28 * w, 50 + 0.08 * w, 0.32 * w, 0.08 * w)
  373. ctx.clearRect(0.64 * w, 50 + 0.08 * w, 0.32 * w, 0.08 * w);
  374. ctx.fillStyle = '#F7921E'
  375. ctx.fillRect(0.64 * w, 50 + 0.08 * w, 0.32 * w, 0.08 * w)
  376. if (topScore < score) {
  377. topScore = score;
  378. }
  379. // 显示新分数
  380. ctx.fillStyle = 'white'
  381. ctx.font = "20px 微软雅黑"
  382. ctx.textAlign = "center"
  383. ctx.textBaseline = "top"
  384. ctx.fillText(score, 0.8 * w, 50 + 0.08 * w);
  385. ctx.fillText(topScore, 0.44 * w, 50 + 0.08 * w);
  386. return true;
  387. }
  388. /**
  389. * 游戏结束激活处理事件
  390. */
  391. touchEventHandler(e) {
  392. var touch = e.touches[0]
  393. var cx = touch.clientX
  394. var cy = touch.clientY
  395. var area = this.bg.btnArea
  396. if (cx >= area.startX &&
  397. cx <= area.endX &&
  398. cy >= area.startY &&
  399. cy <= area.endY) {
  400. this.restart()
  401. }
  402. }
  403. }