app.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. import Element from './runtime/element'
  2. const screenWidth = window.innerWidth
  3. const screenHeight = window.innerHeight
  4. import BackGround from './runtime/background'
  5. import Login from './runtime/login'
  6. import GameInfo from './runtime/gameinfo'
  7. import Music from './runtime/music'
  8. let ctx = canvas.getContext('2d')
  9. const scalx = screenWidth / 375
  10. const scaly = screenHeight / 667
  11. const numberY = 6; //行
  12. const numberX = 6; //
  13. const imgW = 47.5 * scalx;
  14. const imgH = 46.5 * scaly;
  15. const ceilX = 45 * scalx;
  16. const ceilY = 128 * scaly;
  17. const fixedW = 95;
  18. const animal = [0, 1, 2, 3, 4]; //元素种类
  19. const BG_IMG_SRC = 'images/bg.jpg'
  20. const BG_IMG_SRC2 = 'images/play.png'
  21. let minute = 0; //控制动画速度
  22. export default class App {
  23. constructor() {
  24. this.aniId = 0
  25. this.boxData = []; // 消消乐数据
  26. this.startCoordinates = [0, 0]; // 开始的坐标位置
  27. this.endCoordinates = [0, 0]; // 结束的坐标位置
  28. this.clickbox = []; // 点击的方块位置
  29. this.click = 0;
  30. this.isSwaping = false;
  31. this.isClear = false;
  32. this.boxArray = {}
  33. this.speed = 0;
  34. this.anB = 0;
  35. this.maxx = 0;
  36. this.repeat = false;
  37. this.score = {
  38. num: 0,
  39. animal: 0
  40. }
  41. this.hoverImage = {
  42. animal: 0,
  43. x: 0,
  44. y: 0
  45. };
  46. this.hoverSpeed = 0;
  47. this.timer = 0;
  48. this.fill = false;
  49. this.w = 0;
  50. this.draw = false;
  51. this.restart();
  52. }
  53. restart() {
  54. this.login = new Login()
  55. this.bindLoop = this.loop.bind(this)
  56. this.bg = new BackGround(ctx, BG_IMG_SRC);
  57. this.bg2 = new BackGround(ctx, BG_IMG_SRC2);
  58. this.ele = new Element(ctx);
  59. this.gameinfo = new GameInfo(ctx);
  60. this.bindLoop = this.loop.bind(this);
  61. this.music = new Music();
  62. canvas.removeEventListener(
  63. 'touchstart',
  64. this.touchHandler
  65. )
  66. this.aniId = window.requestAnimationFrame(
  67. this.bindLoop,
  68. canvas
  69. )
  70. }
  71. step1() {
  72. ctx.clearRect(0, 0, canvas.width, canvas.height)
  73. this.bg.render(ctx);
  74. this.login.render(ctx);
  75. this.touchHandler = this.touchEventHandler.bind(this)
  76. canvas.addEventListener('touchstart', this.touchHandler)
  77. }
  78. touchEventHandler(e) {
  79. e.preventDefault()
  80. let x = e.touches[0].clientX
  81. let y = e.touches[0].clientY
  82. let area = this.login.btnArea
  83. if (x >= area.startX &&
  84. x <= area.endX &&
  85. y >= area.startY &&
  86. y <= area.endY) {
  87. this.secenceChange()
  88. }
  89. }
  90. secenceChange() {
  91. canvas.removeEventListener(
  92. 'touchstart',
  93. this.touchHandler
  94. )
  95. this.boxArray = {}
  96. window.cancelAnimationFrame(this.aniId);
  97. console.log(this.aniId)
  98. this.up = this.update.bind(this)
  99. this.bgupdate()
  100. this.aniId = window.requestAnimationFrame(this.up, canvas)
  101. this.music.secen2()
  102. }
  103. initEvent() {
  104. canvas.addEventListener('touchstart', this.touchHandlerStart.bind(this))
  105. canvas.addEventListener('touchmove', this.touchHanderMove.bind(this))
  106. canvas.addEventListener('touchend', this.touchEnd.bind(this))
  107. }
  108. touchHandlerStart(e) {
  109. if (this.fill) {
  110. return;
  111. }
  112. e.preventDefault()
  113. this.isSwaping = false
  114. this.repeat = false;
  115. this.boxArray = {}
  116. let x = e.touches[0].clientX - ceilX
  117. let y = e.touches[0].clientY - ceilY
  118. this.draw = false
  119. if (x > 0 && y > 0 && x < (imgW * numberX + ceilX) && y < imgH * numberY + ceilY) {
  120. this.startCoordinates = [x, y];
  121. this.clickbox[0] = Math.ceil(x / imgW) - 1
  122. this.clickbox[1] = Math.ceil(y / imgH) - 1
  123. let col = this.clickbox[1]
  124. let row = this.clickbox[0]
  125. this.hoverImage = {
  126. animal: this.boxData[row][col].animal,
  127. x: row,
  128. y: col
  129. }
  130. console.log("start1")
  131. setTimeout(() => {
  132. this.hover();
  133. this.date1 = new Date();
  134. }, 0);
  135. }
  136. //点击重玩区域
  137. this.againPalyArea(e)
  138. }
  139. hover() {
  140. this.bgupdate();
  141. this.boxData.forEach((item, x) => {
  142. item.forEach((it, y) => {
  143. this.ele.render(ctx, it['animal'] * fixedW, 0, imgW * x + ceilX, imgH * y + ceilY);
  144. })
  145. })
  146. this.ele.renderHover(ctx, this.hoverImage.animal * 95, 0, imgW * this.hoverImage.x + ceilX, imgH * this.hoverImage.y + ceilY);
  147. }
  148. againPalyArea(e) {
  149. let x = [],
  150. y = [];
  151. x[0] = 214 * scalx;
  152. x[1] = 214 * scalx + 100 * scalx;
  153. y[0] = screenHeight - 107 * scaly;
  154. y[1] = screenHeight - 36 * scaly;
  155. //点击重玩区域
  156. if (e.touches[0].clientX > x[0] && e.touches[0].clientY > y[0] && e.touches[0].clientX < x[1] && e.touches[0].clientY < y[1]) {
  157. this.secenceChange()
  158. }
  159. }
  160. //交换
  161. touchHanderMove(e) {
  162. this.date2 = new Date();
  163. console.log((this.date2 - this.date1) * 3600 / 24 * 60 * 60, "start2")
  164. e.preventDefault()
  165. let x = e.touches[0].clientX - ceilX
  166. let y = e.touches[0].clientY - ceilY
  167. this.endCoordinates = [x, y];
  168. //点击 交换区域
  169. if (x > 0 && y > 0 && x < (ceilX + imgW * numberX) && y < ceilY + imgH * numberY) {
  170. this.swap() //交换位置
  171. this.isReapet();
  172. if (this.repeat) {
  173. this.isSwaping = true;
  174. if (this.draw) return
  175. this.music.playswapAudio()
  176. this.drawBlock();
  177. }
  178. }
  179. }
  180. touchEnd(e) {
  181. window.requestAnimationFrame(() => {
  182. if (this.isSwaping) {
  183. this.clear();
  184. this.down();
  185. this.fillBlock();
  186. }
  187. }, canvas)
  188. }
  189. //
  190. drawBlock() {
  191. this.bgupdate();
  192. this.draw = true;
  193. this.boxData.forEach((item, x) => {
  194. item.forEach((it, y) => {
  195. this.ele.render(ctx, it['animal'] * fixedW, 0, imgW * x + ceilX, imgH * y + ceilY);
  196. })
  197. })
  198. }
  199. //swap 二二交换
  200. swap() {
  201. const moveX = this.endCoordinates[0] - this.startCoordinates[0];
  202. const moveY = this.endCoordinates[1] - this.startCoordinates[1];
  203. const col = this.clickbox[0]; //y
  204. const row = this.clickbox[1]; //x
  205. if (Math.abs(moveX) > Math.abs(moveY) && moveX > 0) { // 从左到右
  206. let tmp = this.boxData[col + 1][row];
  207. this.boxData[col + 1][row] = this.boxData[col][row];
  208. this.boxData[col][row] = tmp;
  209. } else if (Math.abs(moveX) > Math.abs(moveY) && moveX < 0) { // 从右到左
  210. let tmp = this.boxData[col - 1][row]
  211. this.boxData[col - 1][row] = this.boxData[col][row];
  212. this.boxData[col][row] = tmp;
  213. } else if (Math.abs(moveY) > Math.abs(moveX) && moveY > 0) { // 从上到下
  214. let tmp = this.boxData[col][row + 1]
  215. this.boxData[col][row + 1] = this.boxData[col][row];
  216. this.boxData[col][row] = tmp;
  217. } else if (Math.abs(moveY) > Math.abs(moveX) && moveY < 0) { // 从下到上
  218. let tmp = this.boxData[col][row - 1]
  219. this.boxData[col][row - 1] = this.boxData[col][row];
  220. this.boxData[col][row] = tmp;
  221. }
  222. }
  223. bgupdate() {
  224. ctx.clearRect(0, 0, screenWidth, screenHeight);
  225. this.bg2.render(ctx, 0, 0, 2, 2);
  226. this.gameinfo.renderGameScore(ctx)
  227. }
  228. downgame() {
  229. this.bgupdate();
  230. this.boxData.forEach((item, x) => {
  231. item.forEach((it, y) => {
  232. if (this.boxData[x][y]['match'] > 0) {
  233. // this.ele.render(ctx,it['animal']*fixedW,0,imgW*x+ceilX,imgH*y+ceilY,true);
  234. if (this.score.animal == it['animal']) {
  235. this.score.num++;
  236. }
  237. let key = x + '' + y
  238. this.boxArray[key] = {
  239. x: imgW * x + ceilX,
  240. y: ceilY + imgH * y,
  241. animal: animal[Math.floor(Math.random() * 5)],
  242. match: 0
  243. }
  244. this.maxx = this.max(y, this.maxx)
  245. } else {
  246. this.ele.render(ctx, it['animal'] * fixedW, 0, imgW * x + ceilX, imgH * y + ceilY);
  247. }
  248. })
  249. })
  250. this.gameinfo.renderImage(ctx, this.score.num)
  251. console.log(this.score.num, "xxxxxxxxxxx")
  252. }
  253. //隐藏要消灭的元素
  254. clear() {
  255. this.bgupdate();
  256. this.boxData.forEach((item, x) => {
  257. item.forEach((it, y) => {
  258. if (this.boxData[x][y]['match'] > 0) {
  259. this.ele.render(ctx, it['animal'] * fixedW, 0, imgW * x + ceilX, imgH * y + ceilY, true);
  260. } else {
  261. this.ele.render(ctx, it['animal'] * fixedW, 0, imgW * x + ceilX, imgH * y + ceilY);
  262. }
  263. })
  264. })
  265. }
  266. //检测是否重复
  267. isReapet() {
  268. this.boxData.forEach((item, x) => {
  269. item.forEach((it, y) => {
  270. let vb = x + 2 < numberX && this.boxData[x][y]['animal'] == this.boxData[x + 1][y]['animal'] && this.boxData[x + 1][y]['animal'] == this.boxData[x + 2][y]['animal'];
  271. let vy = y + 2 < numberY && this.boxData[x][y]['animal'] == this.boxData[x][y + 2]['animal'] && this.boxData[x][y + 1]['animal'] == this.boxData[x][y + 2]['animal'];
  272. if (vb) {
  273. ++this.boxData[x][y].match;
  274. ++this.boxData[x + 1][y].match;
  275. ++this.boxData[x + 2][y].match;
  276. }
  277. if (vy) {
  278. ++this.boxData[x][y].match;
  279. ++this.boxData[x][y + 1].match;
  280. ++this.boxData[x][y + 2].match;
  281. }
  282. if (vb || vy) {
  283. this.repeat = true;
  284. }
  285. })
  286. })
  287. }
  288. //方块下落
  289. down() {
  290. for (let x = numberY - 1; x > -1; x--) { //行
  291. for (let y = 0; y < numberX; y++) { //列
  292. if (this.boxData[y][x].match) {
  293. for (let k = x - 1; k > -1; k--) {
  294. if (this.boxData[y][k].match == 0) {
  295. let temp = this.boxData[y][k];
  296. this.boxData[y][k] = this.boxData[y][x]
  297. this.boxData[y][x] = temp;
  298. break;
  299. }
  300. }
  301. }
  302. }
  303. }
  304. this.downgame();
  305. }
  306. fillBlock() {
  307. this.fill = true;
  308. for (let key in this.boxArray) {
  309. this.ele.renderBoom(ctx, this.speed * 93, 0, this.boxArray[key].x, this.boxArray[key].y);
  310. if (this.isauto) {
  311. this.music.playisAudio()
  312. } else {
  313. this.music.playclearAudio()
  314. }
  315. this.ele.render(ctx, this.boxArray[key]['animal'] * fixedW, 0, this.boxArray[key].x, minute - parseInt((this.maxx + 1) * imgH) + this.boxArray[key].y)
  316. }
  317. this.loopBlock();
  318. }
  319. max(a, b) {
  320. return a > b ? a : b
  321. }
  322. loopBlock() {
  323. this.anB = window.requestAnimationFrame(() => {
  324. minute += 4;
  325. if (minute < parseInt((this.maxx + 1) * imgH)) {
  326. this.clear()
  327. ++this.speed
  328. this.fillBlock()
  329. } else {
  330. window.cancelAnimationFrame(this.anB);
  331. this.clear()
  332. for (let key in this.boxArray) {
  333. console.log(key, "key11")
  334. let ma = this.boxArray[key]['animal'] * fixedW
  335. this.ele.render(ctx, ma, 0, this.boxArray[key].x, this.boxArray[key].y)
  336. let x = key.substring(0, 1);
  337. let y = key.substring(1, 2);
  338. this.boxData[x][y]['animal'] = this.boxArray[key]['animal']
  339. this.boxData[x][y]['match'] = this.boxArray[key]['match']
  340. }
  341. minute = 0;
  342. this.isauto = false
  343. this.speed = 0;
  344. this.repeat = false;
  345. this.isReapet()
  346. console.log(this.boxData, this.repeat, "下落")
  347. if (this.repeat) {
  348. this.boxArray = {}
  349. setTimeout(() => {
  350. this.clear()
  351. this.down()
  352. this.isauto = true;
  353. this.fillBlock()
  354. }, 1000)
  355. } else {
  356. this.fill = false
  357. }
  358. }
  359. }, canvas)
  360. }
  361. touchHanderEnd(e) {
  362. e.preventDefault();
  363. canvas.removeEventListener('touchstart', this.touchHandlerStart.bind(this))
  364. canvas.removeEventListener('touchmove', this.touchHanderMove.bind(this))
  365. }
  366. update() {
  367. this.enemyGenerate();
  368. this.initEvent();
  369. this.gameinfo.renderImage(ctx, this.score.num)
  370. }
  371. loop() {
  372. this.step1();
  373. this.aniId = window.requestAnimationFrame(this.bindLoop, canvas)
  374. }
  375. /**
  376. * 随机方块生成逻辑
  377. * 帧数取模定义成生成的频率
  378. * 左边和左边的左边
  379. * 下边和下边的下边
  380. */
  381. enemyGenerate() {
  382. this.boxData = [];
  383. for (let i = 0; i < numberX; i++) {
  384. for (let j = 0; j < numberY; j++) {
  385. if (j == 0) this.boxData[i] = new Array(numberY)
  386. this.boxData[i][j] = {
  387. animal: animal[Math.floor(Math.random() * 5)],
  388. match: 0
  389. }
  390. while (i > 1 && this.boxData[i][j]['animal'] == this.boxData[i - 2][j]['animal'] || j > 1 && this.boxData[i][j]['animal'] == this.boxData[i][j - 2]['animal']) this.boxData[i][j]['animal'] = animal[Math.floor(Math.random() * 4)]
  391. }
  392. }
  393. this.boxData.forEach((item, x) => {
  394. item.forEach((it, y) => {
  395. this.ele.render(ctx, it['animal'] * fixedW, 0, imgW * x + ceilX, imgH * y + ceilY);
  396. })
  397. })
  398. }
  399. }