微信小程序的2048小游戏 您所在的位置:网站首页 小程序2048数字消除怎么玩 微信小程序的2048小游戏

微信小程序的2048小游戏

2024-07-11 22:04| 来源: 网络整理| 查看: 265

微信目录集链接在此:

详细解析黑马微信小程序视频–【思维导图知识范围】难度★✰✰✰✰

不会导入/打开小程序的看这里:参考

让别人的小程序长成自己的样子-更换window上下颜色–【浅入深出系列001】

文章目录 本系列校训啥是2048微信小程序里的效果项目里的理论知识目录结构页面文件wxml小游戏的逻辑才是重点。 运行界面:总结:配套资源作业:

本系列校训

用免费公开视频,卷飞培训班哈人!打死不报班,赚钱靠狠干! 只要自己有电脑,前后项目都能搞!N年苦学无人问,一朝成名天下知!

啥是2048

很多人都玩过2048,我就比较老套,因为我一向看不上这类单机游戏。但是就在某一天泡脚的无聊时光,拿了媳妇儿的手机,左看看右点点,莫名打开了2048。嗯… 这真是一款打发无聊时光的 “good game”。通过滑动来使得每行或每列相邻并且相同的数字相加而得到一个最大的数字,最后的数字越大,得分越高!于是,我在想,是否能像魔方一样,有一定的套路来帮助我们决定每一步该往哪个方向滑动最佳,以便获得最好的成绩呢?

通过滑动来使得每行或每列相邻并且相同的数字相加 在这里插入图片描述这个游戏怎么玩好象就跟本文没有啥关系了。知道怎么玩就行了。这一次用微信小程序来实现,这种无聊小游戏真的是说不定怎么回事就能火。不信你看看“羊了个羊”,好了,本文章没有那么高级。先看效果图吧。

微信小程序里的效果

在这里插入图片描述 题外话: 其实我本来是想写一个简单一些的从后台取列表的小程序的。但是,找到了身边的一本书。沈顺天的《微信小程序项目开发实战》然后,去GIT上下载了这本书的代码: https://github.com/ssthouse/mini-program-development-code 不推荐!!严重的不推荐 书上的第五章的例子运行不出来,然后,我把各章的代码都运行一下。就感觉这个小游戏里还有一个移动的知识点。就写了本文了。 在这里插入图片描述 第五章的代码应该是抓这个头条的新闻里的页面的内容,但是代码有问题。而且页面又丑。完全就不想下手了。 在这里插入图片描述

在这里插入图片描述 就看到这个小游戏还能运行,就拿出来写写了。

项目里的理论知识

老生常谈的,先说说目录结构,不会导入项目的,打不开项目的。先看前面的文章 在这里插入图片描述

目录结构

app.json文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。 注意:

json配置中键名、键值必须使用双引号,不能使用单引号。以下配置中除了page字段是必需设置,其它项目为可选项。

只有两段,一个是pages,另一个是window 可以说是最简的小程序的app.json文件了

{ "pages": [ "pages/index/index", "pages/canvas-demo/index" ], "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle": "black" }, "sitemapLocation": "sitemap.json" } 页面文件wxml 2048 分数 {{currentScore}} 最高分 {{highestScore}} New Game! 小游戏的逻辑才是重点。 const regeneratorRuntime = require('../../lib/runtime') // eslint-disable-line //获取应用实例 const app = getApp() const board = require('./board') const gameManager = require('./game-manager') const MOVE_DIRECTION = board.MOVE_DIRECTION const MIN_OFFSET = 40; Page({ data: { motto: 'Hello World', // 棋盘 highestScore: 0, currentScore: 0, }, board: null, async onLoad() { await this.initCanvas() this.startGame() }, startGame() { this.board = new board.Board(this.canvas, this.context, this.canvasSize) this.board.startGame() this.setData({ currentScore: 0, highestScore: gameManager.getHighestScore() }) }, onStartNewGame() { this.startGame() }, canvasSize: null, canvas: null, context: null, async initCanvas() { this.canvas = await this.getCanvas() this.canvasSize = await this.getCanvasSize() this.context = this.canvas.getContext('2d') }, async getCanvasSize() { return new Promise((resolve, reject) => { wx.createSelectorQuery().select('#canvas') .boundingClientRect(function (rect) { resolve(rect['width']) }).exec() }) }, async getCanvas() { return new Promise(resolve => { wx.createSelectorQuery() .select('#canvas') .fields({ node: true, size: true, }) .exec((res) => { console.log('res', res[0]) const canvas = res[0].node resolve(canvas) }) }) }, // 用于判断滑动方向的属性值 touchStartX: 0, touchStartY: 0, touchEndX: 0, touchEndY: 0, onTouchStart(e) { const touch = e.touches[0] this.touchStartX = touch.clientX this.touchStartY = touch.clientY }, onTouchMove(e) { const touch = e.touches[0] this.touchEndX = touch.clientX this.touchEndY = touch.clientY }, onTouchEnd(e) { const offsetX = this.touchEndX - this.touchStartX const offsetY = this.touchEndY - this.touchStartY const moveVertical = Math.abs(offsetY) > Math.abs(offsetX) if (moveVertical) { if (offsetY console.log('move bottom') this.board.move(MOVE_DIRECTION.BOTTOM) } } else { if (offsetX console.log('move right'); this.board.move(MOVE_DIRECTION.RIGHT) } } this.setData({ currentScore: this.board.currentScore }); if (this.board.isGameOver()) { const highestScore = gameManager.getHighestScore() if (this.data.currentScore > highestScore) { gameManager.setHighestScore(this.data.currentScore) } wx.showModal({ title: '游戏结束', content: '再玩一次', showCancel: false, success: () => { this.startGame() } }) } if (this.board.isWinning()) { // 显示祝福语,可以继续玩 wx.showToast({ title: '达成2048成就', icon: 'success' }) } } })

这里的JS用了另一个包,来操作CANVAS, 这个包的代码比较长,大家去文章后面的链接里下载吧。 在这里插入图片描述

画块

const regeneratorRuntime = require('../../lib/runtime') // eslint-disable-line const MATRIX_SIZE = 4 const PADDING = 8 const MOVE_DIRECTION = { LEFT: 0, TOP: 1, RIGHT: 2, BOTTOM: 3 } const COLOR_MAP = { 0: {color: '#776e65', bgColor: '#EEE4DA40'}, 2: {color: '#776e65', bgColor: '#eee4da'}, 4: {color: '#776e65', bgColor: '#ede0c8'}, 8: {color: '#f9f6f2', bgColor: '#f2b179'}, 16: {color: '#f9f6f2', bgColor: '#f59563'}, 32: {color: '#f9f6f2', bgColor: '#f67c5f'}, 64: {color: '#f9f6f2', bgColor: '#f65e3b'}, 128: {color: '#f9f6f2', bgColor: '#edcf72'}, 256: {color: '#f9f6f2', bgColor: '#edcc61'}, 512: {color: '#f9f6f2', bgColor: '#edc850'}, 1024: {color: '#f9f6f2', bgColor: '#edc53f'}, 2048: {color: '#f9f6f2', bgColor: '#edc22e'} } class Point { constructor(rowIndex, columnIndex) { this.rowIndex = rowIndex this.columnIndex = columnIndex } } class Cell { constructor(value) { this.value = value // 是否新建方块 this.isNew = false // 移动距离 this.moveStep = 0 } newStatus(newStatus) { if (newStatus !== undefined) { this.isNew = newStatus return this } return this.isNew } } module.exports.MOVE_DIRECTION = MOVE_DIRECTION function printMatrix(matrix) { for (let row of matrix) { const values = row.map(cell => cell.value) console.log(values.join(' ')) } } class Board { constructor(canvas, context, canvasSize) { this.matrix = [] this.currentScore = 0 this.fillEmptyMatrix() this.canvas = canvas this.context = context this.canvasSize = canvasSize this.CELL_SIZE = (canvasSize - (5 * PADDING)) / MATRIX_SIZE } fillEmptyMatrix() { for (let i = 0; i row.push(new Cell(0)) } this.matrix.push(row) } } randomIndex() { return Math.floor(Math.random() * MATRIX_SIZE) } startGame() { // 初始化两个cell for (let i = 0; i const movedMatrix = [] for (let i = 0; i if (matrix[i][j].value !== 0) { matrix[i][j].moveStep += j - row.length row.push(matrix[i][j]) } } while (row.length const context = this.context const canvasSize = this.canvasSize const matrix = this.matrix const CELL_SIZE = this.CELL_SIZE context.clearRect(0, 0, canvasSize, canvasSize) this.drawBgCells() for (let rowIndex = 0; rowIndex // 画出当前矩形 const moveStep = matrix[rowIndex][colIndex].moveStep const startPoint = { x: (PADDING + colIndex * (CELL_SIZE + PADDING)), y: PADDING + rowIndex * (CELL_SIZE + PADDING) } switch (direction) { case MOVE_DIRECTION.LEFT: startPoint.x += moveStep * (CELL_SIZE + PADDING) * (1 - process) break case MOVE_DIRECTION.RIGHT: startPoint.x -= moveStep * (CELL_SIZE + PADDING) * (1 - process) break case MOVE_DIRECTION.TOP: startPoint.y += moveStep * (CELL_SIZE + PADDING) * (1 - process) break case MOVE_DIRECTION.BOTTOM: startPoint.y -= moveStep * (CELL_SIZE + PADDING) * (1 - process) break } this.drawCell( startPoint.x, startPoint.y, matrix[rowIndex][colIndex], process ) } } } drawBgCells() { const context = this.context context.globalAlpha = 1 for (let rowIndex = 0; rowIndex context.fillStyle = 'rgba(238, 228, 218, 0.35)' this.drawRoundSquare( PADDING + colIndex * (this.CELL_SIZE + PADDING), PADDING + rowIndex * (this.CELL_SIZE + PADDING), this.CELL_SIZE ) context.fill() } } } drawCell(x, y, cell, process) { const text = cell.value if (text === 0) return const context = this.context context.globalAlpha = cell.isNew ? process * process : 1 context.fillStyle = COLOR_MAP[text].bgColor this.drawRoundSquare(x, y, this.CELL_SIZE) context.fill() context.fillStyle = COLOR_MAP[text].color context.font = '40px Clear Sans' context.textAlign = 'center' context.textBaseline = 'middle' context.fillText( text, x + this.CELL_SIZE / 2, y + this.CELL_SIZE / 2 ) } drawRoundSquare(startX, startY, size) { const point1 = { x: startX, y: startY } const points = { point1, point2: { x: point1.x + size, y: point1.y }, point3: { x: point1.x + size, y: point1.y + size }, point4: { x: point1.x, y: point1.y + size } } const context = this.context context.beginPath() context.moveTo((points.point1.x + points.point2.x) / 2, (points.point1.y + points.point2.y) / 2) context.arcTo(points.point2.x, points.point2.y, points.point3.x, points.point3.y, 12) context.arcTo(points.point3.x, points.point3.y, points.point4.x, points.point4.y, 12) context.arcTo(points.point4.x, points.point4.y, points.point1.x, points.point1.y, 12) context.arcTo(points.point1.x, points.point1.y, points.point2.x, points.point2.y, 12) context.closePath() } drawWithAnimation(direction) { let process = 0 const draw = () => { this.drawBoard(process / 100, direction) if (process // 将cell数据复位 for (let row of this.matrix) { for (let cell of row) { cell.newStatus(false) cell.moveStep = 0 } } } } draw() } move(direction) { if (!this.canMove(direction)) { console.log('该方向不可用') return } const rotatedMatrix = this.transformMatrixToDirectionLeft(this.matrix, direction) const leftMovedMatrix = this.moveValidNumToLeft(rotatedMatrix) this.matrix = this.reverseTransformMatrixFromDirectionLeft(leftMovedMatrix, direction) // 相同数字合并 for (let i = 0; i if (leftMovedMatrix[i][j].value > 0 && leftMovedMatrix[i][j].value === leftMovedMatrix[i][j + 1].value) { leftMovedMatrix[i][j].value *= 2; leftMovedMatrix[i][j].newStatus(true) this.currentScore += leftMovedMatrix[i][j].value; leftMovedMatrix[i][j + 1].value = 0; } } } const againMovedMatrix = this.moveValidNumToLeft(leftMovedMatrix) this.matrix = this.reverseTransformMatrixFromDirectionLeft(againMovedMatrix, direction) // 增加一个新数字 const emptyPoints = this.getEmptyCells(); if (emptyPoints.length !== 0) { const emptyPoint = emptyPoints[Math.floor(Math.random() * emptyPoints.length)] const cell = Math.random() case MOVE_DIRECTION.LEFT: return matrix case MOVE_DIRECTION.TOP: return this.rotateMultipleTimes(matrix, 3); case MOVE_DIRECTION.RIGHT: return this.rotateMultipleTimes(matrix, 2); case MOVE_DIRECTION.BOTTOM: return this.rotateMatrix(matrix); default: return matrix } } reverseTransformMatrixFromDirectionLeft(matrix, direction) { switch (direction) { case MOVE_DIRECTION.LEFT: return matrix case MOVE_DIRECTION.TOP: return this.rotateMultipleTimes(matrix, 1); case MOVE_DIRECTION.RIGHT: return this.rotateMultipleTimes(matrix, 2); case MOVE_DIRECTION.BOTTOM: return this.rotateMultipleTimes(matrix, 3); default: return matrix } } rotateMultipleTimes(matrix, rotateNum) { let newMatrix = matrix while (rotateNum > 0) { newMatrix = this.rotateMatrix(newMatrix) rotateNum-- } return newMatrix } // 顺时针旋转90° rotateMatrix(matrix) { const rotatedMatrix = [] for (let i = 0; i row.push(matrix[j][i]) } rotatedMatrix.push(row) } return rotatedMatrix } canMove(direction) { const rotatedMatrix = this.transformMatrixToDirectionLeft(this.matrix, direction) // 根据direction, 改为向左判断 for (let i = 0; i // 如果有两个连着相等的,可以滑动 if (rotatedMatrix[i][j].value > 0 && rotatedMatrix[i][j].value === rotatedMatrix[i][j + 1].value) { return true; } // 如果有数字左边有0,可以滑动 if (rotatedMatrix[i][j].value === 0 && rotatedMatrix[i][j + 1].value > 0) { return true; } } } return false } isGameOver() { return !this.canMove(MOVE_DIRECTION.LEFT) && !this.canMove(MOVE_DIRECTION.TOP) && !this.canMove(MOVE_DIRECTION.RIGHT) && !this.canMove(MOVE_DIRECTION.BOTTOM) } getEmptyCells() { const emptyCells = [] for (let i = 0; i if (this.matrix[i][j].value === 0) { emptyCells.push(new Point(i, j)) } } } return emptyCells } isWinning() { let max = 0 const winNum = 2048 for (let row of this.matrix) { for (let cell of row) { max = Math.max(cell, max) } if (max > winNum) { return false } } return max === winNum } } module.exports.Board = Board

游戏里常见的最高分

const HIGHEST_SCORE_KEY = 'highest_score' const DEFAULT_HIGHEST_SCORE = 0 function setHighestScore(score) { if (score setHighestScore, getHighestScore } 运行界面:

在这里插入图片描述

提示:如果一不小心出错 这个时候,Ctrl+Z (这个快捷键有必要记住) 基本上80%以上的编辑器程序都是用这个快捷方式恢复到前一步正确的代码。 如果在恢复这个错之前,把这个错误的截图,并保存,查看几下那就更好了。面对页面出错不是大惊小怪,而是看看是啥错误信息,那你基本具备了向高手迈进的姿势了。

总结:

如果按着书一步一步的学习,那真的不知道啥时候才能做出一个比较完整的小程序。 在这里插入图片描述 但是有了【小程序花园】这个系列之后,就不一样了。基本的知识点一看,就可以迅速的搭建出自己的相应的小程序。 这个小游戏其实并不简单。真的要自己写出来。那差不多得3年以上的老程序员。这个思路其实,跟是不是小程序没有太多的关系。都是取得CANVAS之后,大量的算法。 你要是真的能看下去的话,你会发现,其实语言,工具的那一层都不是难度。年轻的时候,可以多花点时间做一些烧脑的算法的练习,等到过了35岁了,可能你会感觉心有余而力不足了。 可以参考《详细解读java的连连看游戏的源代码–【课程设计】》 在这里插入图片描述 在这里插入图片描述

在这里插入图片描述

配套资源

微信小程序的2048小游戏–【小程序千寻】 https://download.csdn.net/download/dearmite/88210296

作业:

1 下载配套资源阅读里面的代码,加界面的其它元素,让它不这么丑(难度★★★★✫)



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有