有做过俄罗斯方块游戏小程序的经验,这次有做了一个消灭方块的游戏,实现过程很顺利,游戏看着和之前做的俄罗斯方块游戏很像,这里调整了玩法,试玩感觉还可以,接下来给大家讲一讲消灭方块游戏开发过程。
俄罗斯方块游戏文章 【俄罗斯方块】单机游戏-微信小程序项目开发入门
文章目录
- 小程序
- 初始页面
- 游戏页面
- 游戏逻辑
- 游戏背景
- 游戏方块
- 开始游戏
- 选择方块
- 拖动方块
- 消灭方块
- 游戏测试
这里的消灭方块游戏,也叫方块消消乐游戏,
小程序
用微信开发工具打开,新建一个小程序项目,例如项目名miniprogram-BoxDesalination
,
如下图,依次选择即可
- AppID 选自己申请的测试号
- 不使用云服务(不免费)
- JavaScript - 基础模板
这里选创建小程序项目,因为这开发比小游戏项目开发难度低了不少,很适合新手学习
初始页面
初始页面文件位置在/pages/index/index
,
在页面index.wxml
布局文件中添加按钮,添加内容如下,点击按钮进入游戏,
<view>
<button type="default" bindtap="onClickKey" data-key="enter">进入游戏</button>
</view>
然后在页面index.js
逻辑文件中添加进入游戏的点击事件
Component({
methods: {
// 事件处理函数
onClickKey(e) {
wx.navigateTo({
url: '/pages/game/game',
})
}
}
}
现在这个时间点,微信开发工具自动创建的小程序项目的初始页面跟旧版的不同了,
初始页面以前是用页面Pages
对象,
现在发现是用的自定义组件Component
展示,添加的方法是在methods
里面的
游戏页面
创建一个游戏页面,文件位置在/pages/game/game
,
打开页面game.wxml
布局文件,布局内容如下
<!--pages/game/game.wxml-->
<view class="page">
<canvas class="canvas" type="2d" id="zs1028_csdn" bindtouchstart="onTouchStart" bindtouchmove="onTouchMove" bindtouchend="onTouchEnd" disable-scroll="{{true}}"></canvas>
</view>
只需要放一个组件canvas就好
游戏逻辑
接下来,准备写游戏逻辑,首先思考如何初始化页面,
打开页面game.js
逻辑文件,在里面的onReady()
方法里写初始化代码,得到一个canvas
// pages/game/game.js
import ZS1028_CSDN from '../../utils/zs1028_CSDN.js'
import BLOCK from '../../utils/block.js'
const app = getApp()
Page({
/**
* 生命周期函数--监听页面初次渲染完成
*/
async onReady() {
const { node:canvas, width, height } = await ZS1028_CSDN.query('#zs1028_csdn')
Object.assign(canvas, { width, height })
//创建小游戏引擎(框架)对象,传入canvas
const game = ZS1028_CSDN.createMiniGameEngine({
canvas,
// isTest: true //性能测试用途
})
this.game = game
// 初始化游戏数据...
// 背景和网格数据
const bgGridsData = {...}
// 所有的方块数据
const blocksData = {...}
// 游戏状态数据
const stateData = {...}
// 初始化游戏数据都放到gameData中,方便下次获取
this.gameData = {
bgGridsData,
blocksData,
stateData
}
// 调用这个会在画布中划分一块区域在顶部显示游戏状态
game.initTopBar({
data:stateData,
reset(){...},
redraw(data){...}
})
// 将上面的方法都加入到游戏引擎对象中...
game.addBgObject({
data:bgGridsData,
reset(){...},
redraw(data){...},
methods:{...}
})
game.addBgObject({
data:blocksData,
reset(){...},
redraw(data){...},
methods:{...}
})
// 调用开始游戏方法
this.restart()
},
/**
* 以下都是触摸产生事件调用的方法
*/
onTouchStart(e) {...},
onTouchMove(e) {...},
onTouchEnd(e) {...},
)}
看上面,用了两个模块,省了很多代码,这样实现和读代码很容易;
- 模块
ZS1028_CSDN
,是小游戏引擎(框架)对象,154行代码;- 模块
BLOCK
,是封装了方块的一些处理方法,186行代码;
游戏背景
初始化的游戏背景对象是bgGridsData
,如下代码,看看有哪些数据
const bgGridsData = {
grids1:[],//上面的网格
grids2:[],//下面的网格
cols: 20,//网格列数
isShowGrids: false //是否展示网格,调试用途,默认不展示
}
将背景对象添加到game
对象的属性data
中,
如下代码,在方法redraw()
实现绘制背景
game.addBgObject({
data:bgGridsData,
reset(){...}, //这里是可实现重置背景数据的方法
redraw(data){
const { topBar, canvas, context:ctx } = data
// 如果没有背景图片,就需要绘制出来,也是背景初始化的逻辑
if (!this.cacheImg) {
//省略更多...在这里实现绘制背景和网格
//绘制好了,就导出为图像对象
let img = canvas.createImage()
img.onload = () => this.cacheImg = img
img.src = canvas.toDataURL()
//最后要处理保存背景数据...
return
}
// 有背景图像了,这里就把图像绘制出来
ctx.drawImage(this.cacheImg,0,0,canvas.width,canvas.height)
// 这里判断初始化的网格大小
if (bgGridsData.gridSize>0) {
// 设定方块的颜色
ctx.strokeStyle = '#000000'
ctx.fillStyle = '#000000'
// 上面的网格有数据以后
this.data.grids1.forEach((grid)=>{
if (!grid.isBlock) return
//有方块的话,就调用方块模块的绘制方法,绘制出来方块
BLOCK.drawBlockAtGrid(ctx,bgGridsData.gridSize,grid.x,grid.y)
})
}
},
methods:{
//类似组件的方法...都在这里添加实现,在内部调用
}
})
网格背景图像是静态的,可以当作缓存来绘制,
未变化的图形是不建议重新初始化处理的,这会消耗CPU计算资源
游戏方块
初始化游戏方块的是在blocksData
对象里,
如下代码,看看有哪些数据
const blocksData = {
blocks:[],// 所有方块列表数据
// 选择方块的
select:{
index:-1, // 执行方块列表数据的索引
// 点击开始点
startPoint:{
x:-1,
y:-1
},
// 拖动位置点
movePoint:{
x:-1,
y:-1
},
// 位置变化差
offsetX:0,
offsetY:0
}
}
能看懂上面的一些定义吗,看到后面就会知道有什么用了吧
将方块对象添加到game
对象的属性data
中,
如下代码,在方法redraw()
实现绘制所有方块
const that = this
game.addBgObject({
data:blocksData,
//重置方法
reset(){
const { blocks } = this.data
blocks.length = 0
//调用下面的方法,分别设置三个随机方块在下面的网格中,传入的是索引
that.setRandomBlock()
that.setRandomBlock(1)
that.setRandomBlock(2)
},
redraw(data){
const {canvas,context:ctx} = data
const {blocks,select}=this.data
// 遍历所有方块
blocks.forEach((block,index)=>{
let offsetX=0
let offsetY=0
//如果选择了下面网格的一个方块
if (index==select.index){
//调用模块的方法,查找此方块的索引
let gIndex = BLOCK.findIndexFormGrid(bgGridsData.cols,block,0)
//计算方块的开始点和结束点
let startPoint = ...
let endX = ...
let endY = ...
//此处省略了...
//再绘制选中的方块背景...
ctx.strokeStyle = '#000000'
ctx.fillStyle = '#777777'
ctx.beginPath()
ctx.rect(startPoint.x,startPoint.y,endX,endY)
ctx.fill()
ctx.stroke()
//调用模块的更新选择方法,就是改变select.offsetX和select.offsetY
BLOCK.updateSelectBlockLocation(this.data.select)
//拖动改变了位置
offsetX = this.data.select.offsetX
offsetY = this.data.select.offsetY
//获取下面方块在网格的数据
let grid = bgGridsData.grids2[block.index]
if (grid) {
//调用模块的方法,获取拖动的方块在上面投影出来网格的方块
let mapBlock = BLOCK.findMappingBlock(bgGridsData.cols,bgGridsData.gridSize,bgGridsData.grids1,block,grid.x+offsetX,grid.y+offsetY)
//如果有的话,就绘制出来
if (mapBlock) {
ctx.strokeStyle = '#000000'
ctx.fillStyle = '#999999'
//调用此方法绘制方块mapBlock,方法是在下面的methods定义的
this.drawBlock(ctx,bgGridsData.grids1,mapBlock)
}
//最后将投影出来的方块存到起
this.data.mapBlock = mapBlock
}
}
ctx.strokeStyle = '#000000'
ctx.fillStyle = '#000000'
//调用此方法绘制方块block,方法是在下面的methods定义的
this.drawBlock(ctx,bgGridsData.grids2,block,offsetX,offsetY)
})
},
methods:{
drawBlock(ctx,grids,block,offsetX=0,offsetY=0){
//方块有个属性list,这里记录方块的每一块相对坐标位置
block.list.forEach((g,i)=>{
//此处省略了...绘制方块的每一块
})
}
}
})
开始游戏
在开始的游戏方法里,调用game
的方法run()
即可,
在调用游戏开始前,需要调用reset()
就可以重置游戏数据,代码如下
restart() {
const {game}=this
const {stateData}=this.gameData
//关闭定时器
this.closeTimer()
//重置游戏
game.reset()
//运行游戏
game.run()
//定时更新
this.timer = setInterval(()=>{
stateData.timerNum--
if (stateData.timerNum==0){
stateData.isGameEnd = true
this.closeTimer()
app.setMaxScope(stateData.scope)
wx.showModal({
title: '系统提示',
content: '游戏结束!当前得分'+stateData.scope,
showCancel: true,
cancelText: '返回游戏',
confirmText: '重新开始',
complete: (res) => {
if (res.confirm) {
this.restart()
}
}
})
return
}
},1100)
},
写到这里,游戏基本就可以运行了,界面如下图
还没完呢,需要实现游戏交互,在触摸事件里实现
选择方块
开始触摸时,会调用方法onTouchStart(e)
,
代码如下,这里实现选择底部的方块
onTouchStart(e) {
const touch = e.touches[0]
const { bgGridsData, blocksData, stateData } = this.gameData
//先判断游戏是否结束
if (stateData.isGameEnd) return
//获取触摸到方块的索引
let blockIndex = blocksData.blocks.findIndex(block=>{
return block.list.find((g,i)=>{
//...调用模块的方法,查找触摸到的方块索引
let index = BLOCK.findIndexFormGrid(bgGridsData.cols,block,i)
let grid = bgGridsData.grids2[index + block.index]
//判断指定网格位置
return grid.x<touch.x && grid.x+bgGridsData.gridSize>=touch.x && grid.y<touch.y && grid.y+bgGridsData.gridSize >= touch.y
})
})
//如果没有触摸到,重置选择返回
if (blockIndex<0) {
blocksData.select.index = -1
return
}
//执行到这里,就是触摸到了,设置以下选择数据
blocksData.select.index = blockIndex
Object.assign(blocksData.select.startPoint,{
x: touch.x,
y: touch.y
})
},
看上面的代码,游戏交互的实现,只需要自己实现修改游戏数据就可以了,
具体的绘制逻辑,之前就有讲过,当数据变化,绘制的状态也会跟着变化
拖动方块
触摸移动时,也就是拖动操作,会调用方法onTouchMove(e)
,
代码如下,这里实现拖动方块
onTouchMove(e) {
const touch = e.touches[0]
const { bgGridsData, blocksData } = this.gameData
if (blocksData.select.index<0) return
//选择到方块,然后移动,就是拖动方块的操作了,边移动边更新它的位置
Object.assign(blocksData.select.movePoint,{
x: touch.x,
y: touch.y
})
},
消灭方块
不再触摸时,也就是拖动取消了,会调用方法onTouchEnd(e)
,
代码如下,这里实现放置方块
onTouchEnd(e) {
const { bgGridsData, blocksData, stateData } = this.gameData
if (blocksData.select.index<0) return
const { select, mapBlock } = blocksData
//如果有投影出来的方块
if (mapBlock) {
//这里就处理,把投影的方块设置到上面的网格中,就真的放置上去了
mapBlock.list.forEach((value,index)=>{
if (value<1) return
let gIndex = BLOCK.findIndexFormGrid(bgGridsData.cols,mapBlock,index)
let grid = bgGridsData.grids1[gIndex + mapBlock.index]
grid.isBlock = true
})
//放置好了,接下来,再出一个随机方块
this.setRandomBlock(select.index)
//调用模块的方法,算出消灭方块的数量,同时会修改网格的方块数据(清空操作)
let count = BLOCK.decreaseBlocksFormGrids(bgGridsData.grids1,bgGridsData.cols)
if (count>0) {
//更新游戏状态,加分,加时间
stateData.scope += count
stateData.timerNum += 60
//弹出提示
wx.showToast({
title: `消灭方块,加60秒`,
icon: 'none'
})
}
}
//以下是重置选择数据
select.index = -1
Object.assign(select.startPoint, {
x: -1,
y: -1
})
Object.assign(select.movePoint, {
x: -1,
y: -1
})
},
还有对象game
有个方法game.initTopBar()
,是初始化顶部显示的游戏状态,看看游戏效果里有,
其它方法,以及模块的一些方法,这里不多讲了,不是重点,
建议看源代码吧,代码不多,值得研究学习
游戏测试
写到这里,方块消消乐游戏就算完成了,可以运行编译测试,
运行效果图如下,点鼠标拖动底部的方块,任选一个,拖放到上面的框中,
- 当某行或某列没有留空的话,就会被消灭了,会奖励时间;
- 底部出现的方块是随机的,玩家根据自己的想法去拖放方块,
- 看谁消灭的多,得分就越高哦,同时会记录下来;
想看项目源码的前往下载请点这里查找,若不方便查找请在右侧输入关键词方块消消乐搜索即可,本博客站内请放心下载,感谢支持!
可能手机上看不到下载点,请改用电脑浏览器查看