以前玩过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 } = data
let { 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 } = data
let { cols, grids, gridSize, isNew } = this.data
if (!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
//...绘制数字value
ctx.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) return
this.touch1 = e.touches[0]
},
onTouchMove(e) {
if (!this.touch1) return
this.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 = true
break
case Gesture.G.up:
case Gesture.G.down:
isReverse = false
break
default:
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 = undefined
this.touch2 = undefined
},
别法算法想那么复杂,只要思路是对的,能实现出来的就没问题
游戏测试
写到这里,基本上就可以运行测试玩玩了,
看看合成数字的游戏效果吧,运行动图如下
想要改成
2048
游戏一样是可以的,只需要在新建的随机位置数字代码里修改1
为2
即可;
想要项目源码在点这里查看下载,或者直接点这里搜索:合成数字,在本博客站内请放心下载,感谢支持!
可能手机上看不到,请改用电脑浏览器查看;
如果搜索不到,只能在资源一栏慢慢找了(太多了不好找)