以前玩过2048游戏,从中发现规律,想到跟合成类游戏相似,知道为什么很相似吗,在这里,做一个数字合成游戏玩玩吧,感兴趣的话可以看看,这里给大家讲一讲数字合成游戏的开发过程。
文章目录
- 创建项目
- 页面布局
- 初始页面
- 游戏页面
- 游戏逻辑
- 加载模块
- 初始化画布
- 初始化游戏数据
- 绘制游戏状态
- 绘制网格
- 开始游戏
- 重新开始
- 触摸事件
- 游戏测试
创建项目
这里用HBuilderX开发工具来创建一个uniapp项目,
例如项目名填写uniapp_CompositeNumber
,依次选择如下图
- 选择新建uni-app项目
- 使用默认模板
- Vue版本选择 3
页面布局
新建好项目,会看到自动创建了一个初始页面文件,
初始页面
文件位置在pages/index/index.vue
,打开看看,
在页面布局中,对应的template
标签里添加一个按钮组件,按钮名叫进入游戏,
然后在script
标签里,添加一个按钮点击方法,实现打开游戏页面,
打开页面的代码很简单,自己能写出来吧,这里就不展开讲,
游戏页面
需要自己创建一个游戏页面,
页面文件在pages/game/game.vue
,打开接着写,
在页面布局中,对应的template
标签里添加,内容如下
<!--pages/game/game.wxml-->
<view class="page"><canvas type="2d" id="zs1028_csdn" class="canvas" bindtouchstart="onTouchStart" bindtouchmove="onTouchMove" bindtouchend="onTouchEnd" disable-scroll="{{true}}"/>
</view>
就这么简单,只放一个
canvas
组件即可,组件的一些属性不用说能看懂吧
写好后,要做出运行的游戏页面效果,就像如下图这样
看着是不是很像
2048
游戏呢,没错,与其不同的是从数字1开始计算,
实现思路,就是把两个相同的数字合成,如1+1=2
,计算规则n+n=2n
。
游戏逻辑
接下来,在script
标签里,写游戏逻辑,
加载模块
开始写初始化代码,先加载游戏模块,添加代码如下
// pages/game/game.js
import ZS1028_CSDN from '../../utils/zs1028_CSDN.js'
import Gesture from '../../utils/gesture.js'const app = getApp()Page({//.../*** 生命周期函数--监听页面初次渲染完成*/async onReady() {//...这里处理初始化},/*** 生命周期函数--监听页面卸载*/onUnload() {if(this.timer) clearTimeout(this.timer)this.game?.destroy()},/*** 以下是通过canvas的触摸事件来调用*/onTouchStart(e) {...},onTouchMove(e) {...},onTouchEnd(e) {...},
})
导入的两个模块,想必看过之前笔者发布过文章的读者会有点映像,
Gesture
,是一个处理触摸手势模块,有参考文章 关于手机中的触摸手势操作实现过程详解;
ZS1028_CSDN
,是一个游戏引擎框架模块,让游戏实现变得简单;
初始化画布
游戏大致的思路呢,是要先把画布初始化,然后绘制出来游戏画面,
也就是绘制网格,然后绘制一些数字在上面,
就在onReady()
方法里写,画布初始化的逻辑,代码如下
const { node: canvas, width, height } = await ZS1028_CSDN.query('#zs1028_csdn')
Object.assign(canvas, { width, height })
const game = ZS1028_CSDN.createMiniGameEngine({canvas,// isTest: true //游戏测试用途
})
this.game = game
初始化游戏数据
继续写下去,初始化游戏数据,代码如下,
//游戏状态数据
const gameState = {bottom: 38 //游戏标题底部位置
}
//游戏网格数据
const gridsData = {grids: [], //游戏网格列表cols: 5, //网格列数isNew: false, //是否出现新的数字
}
绘制游戏状态
接下来,调用游戏对象的绘制过程,
这是绘制游戏标题,显示游戏状态,代码如下
const that = this
//初始化游戏标题层
game.initTopBar({data: gameState,reset() {//重置数据的Object.assign(this.data,{scope: 0,best: app.getMaxScope(),timerNum: 300,})},redraw(data) {const { canvas, context: ctx, topBar } = datalet { scope, best, timerNum } = this.data//这里绘制游戏标题区域...}
})
绘制网格
接下来,绘制出来网格,代码如下
//添加游戏背景层,绘制网格
game.addBgObject({data: gridsData,reset() {const { grids } = this.data//...这里重置游戏网格数据//添加随机数字到网格for(let i=0;i<5;i++){this.addRandomGridValue()}},redraw(data) {const { canvas, context: ctx, topBar } = datalet { cols, grids, gridSize, isNew } = this.dataif (!this.cacheBgImg) {//...在这里画背景图片,也就是绘制网格,第一次就要画出来,导出图片,然后就直接用图片绘制来代替return}//...判断一个状态,如果要新的随机位置数字if (isNew) {this.addRandomGridValue()//添加好,就重置一下状态this.data.isNew = false}//这里先绘制背景图片(网格)ctx.drawImage(this.cacheBgImg, 0, 0, canvas.width, canvas.height)let r = gridSize / 2//...这里绘制网格中的数字grids.forEach(g => {if (g.value < 1) return//...绘制数字valuectx.fillText(g.value, g.x + g.relX + r, g.y + g.relY + r * 1.1)//...这之后就是绘制移动数字动画的,代码虽少,但不好理解})},methods: {addRandomGridValue() {//...自定义方法,实现添加随机位置的数}}
})
开始游戏
最后,准备就绪,开始游戏,代码如下
//将初始化数据存放好
this.gameData = {gameState,gridsData
}
//最后,调用此方法开始游戏
this.restart()
重新开始
写重新开始的逻辑很简单,
在开始游戏调用方法restart()
里有实现,代码如下
game.reset()
//...其它的初始化逻辑
game.run()
可见,重新开始游戏,只需调用游戏对象
game
的两个方法就可以了
触摸事件
接下来,处理画布canvas
触摸事件,让游戏与玩家交互,
用到了处理手势的模块,这实现会变得简单,
开始触摸时,记录下按下的点数据,
就是触摸开始点touch1
和移动到最后的点touch2
两个,代码如下
onTouchStart(e) {if (this.isGameEnd || this.startAnimating) returnthis.touch1 = e.touches[0]
},onTouchMove(e) {if (!this.touch1) returnthis.touch2 = e.touches[0]
},
触摸移动结束时,调用手势模块的方法,就能得出滑动的方向,
这样就知道往哪个方向移动,来处理网格里的一些数字移动,
实现移动的逻辑,加上动画,这会变得复杂一些,
仔细构思一下,就写了出来,代码如下
onTouchEnd(e) {if (this.touch1 && this.touch2) {//通过调用模块的方法获取let g = Gesture.touchesToG(this.touch1, this.touch2)let list = this.scanGrids(g)let gs = []let isReverse //是否反向排列//判断是哪个手势switch (g) {case Gesture.G.left:case Gesture.G.right:isReverse = truebreakcase Gesture.G.up:case Gesture.G.down:isReverse = falsebreakdefault:throw new Error('this is error')}//遍历一遍,将可移动的数字记录到gs列表中list.forEach(arr => gs.push(...this.calcMoveGrids(arr, isReverse)))//这里列表若不为空,就有移动的数字在里面if (gs.length > 0) {this.startAnimating = true//开始下一个的移动数字动画 this.nextAnimation(list,gs,isReverse,1)} else {//没有可移动的,可能有存在两个相邻的相同数字,需要调用合并数字的方法let scope = this.compositeNumber(list, isReverse)//当scope大于0,也就是有得分,表示合并成功,就执行移动数字动画if (scope > 0) {this.startAnimating = true//开始下一个的移动数字动画this.nextAnimation(list,gs,isReverse)}}}//最后,别忘了重置触摸点数据this.touch1 = undefinedthis.touch2 = undefined
},
别法算法想那么复杂,只要思路是对的,能实现出来的就没问题
游戏测试
写到这里,基本上就可以运行测试玩玩了,
看看合成数字的游戏效果吧,运行动图如下
想要改成
2048
游戏一样是可以的,只需要在新建的随机位置数字代码里修改1
为2
即可;
想要项目源码在点这里查看下载,或者直接点这里搜索:合成数字,在本博客站内请放心下载,感谢支持!
可能手机上看不到,请改用电脑浏览器查看;
如果搜索不到,只能在资源一栏慢慢找了(太多了不好找)