这是一个仿俄罗斯方块小游戏的微信小程序,只需要写一小段代码就实现出来了,有兴趣的同学完全可以自己动手开发,来看看实现过程是怎样的呢,边写边做,一起来回忆小时候玩过的经典俄罗斯方块游戏吧。
💡 给读者一个小小提示 需要有HTML和CSS基础 还有JavaScript基础 电脑有安装好微信小程序开发工具
满足以上三个条件就能看懂接下来的一些内容了
创建小程序
首先,打开微信小程序开发工具,如下图所示,
新建一个小程序项目minigame-tetris,就选择小程序,注意不要选择使用云服务和模板,然后点确定即可,
这时项目在开发者工具中自动创建好了,会发现生成的文件不会太多,这是为方便精简项目源码,避免新建的项目自动生成一大堆对新手来说不懂的东西,此项目开发对新手非常友好的!
页面设计
在项目根目录下,打开一个页面布局文件,文件路径为pages/index/index.wxml ,如下图所示,这是我们要做的页面显示效果,准备编写布局标签实现它吧 可能新手想不太明白,那么说下原理,整个页面的布局只用到了一个画布Canvas 组件和两个图片image ,然后设置css 样式层层叠加放置就可以实现效果,布局文件内容参考如下,简单就好!
<view class="container">
<view class="canvas-box">
<image src="{{bgImg}}" class="canvas-bg" />
<image src="{{foreImg}}" class="canvas-bg" />
<canvas type="2d" id="canv" class="canvas"></canvas>
</view>
<view class="footer">
<view class="btngroup">
</view>
</view>
</view>
页面逻辑
接下来,想到需要编写游戏的逻辑,这下会不会感到难写了,以我们对俄罗斯方块游戏互动逻辑的了解,似乎实现起来不太难吧,别担心,站在巨人的肩膀上,看看怎么写得呢,
打开文件路径为pages/index/index.js ,开始编写代码,如下所示,理清一下逻辑,一边写一边思考
const canvasId = 'canv';
Page({
data:{
context:{},
bgImg:'',
},
onLoad(){
wx.createSelectorQuery().in(this).select(`#${canvasId}`).fields({
size:true, node:true
},res=>{
const canvas = res.node;
canvas.width = res.width;
canvas.height = res.height;
const ctx = canvas.getContext('2d');
Object.assign(this.data.context,{ canvas, ctx });
const base64 = this.initGrid();
this.initTimer();
this.setData({
bgImg: base64
});
}).exec()
},
onUnload(){
},
initGrid(){
},
initTimer(){
},
onclickkey(e){
},
onclickend(){
}
})
初始化
初始化方法initGrid() ,这里面做的是初始化一些属性,和绘制背景图,还有网格数据,大致的实现逻辑如下,可以这样理解,游戏中的一些方块都是有自己位置的,需要网络来作为参照物,定方位
import Tetris from '../../static/utils/tetris';
Page({
data:{
context:{},
tetris:null,
},
initGrid(){
const { ctx, canvas } = this.data.context;
const cols = 28;
const gs = Math.trunc(canvas.width/cols);
const rows = Math.trunc(canvas.height/gs);
const padding = Math.trunc(canvas.width%cols/2);
Object.assign(this.data.context,{ padding, gs, rows, cols });
const tetris = new Tetris({rows,cols});
ctx.save();
ctx.fillStyle='#000000';
ctx.strokeStyle='#fff';
ctx.rect(0,0,canvas.width,canvas.height);
ctx.fill();
ctx.fillStyle='#fff';
ctx.strokeStyle='#000';
ctx.beginPath();
ctx.rect(padding,0,cols*gs,rows*gs);
ctx.fill();
ctx.stroke();
ctx.restore();
this.data.tetris = tetris;
const data = canvas.toDataURL();
ctx.clearRect(0,0,canvas.width,canvas.height);
return data;
},
}
定时刷新
初始化定时器方法initTimer() ,这方法做的是让游戏运动起来的意思,因为是用定时器实现刷新游戏状态的,如果对此不太了解,那么实现过程会是难以理解的,这个实现逻辑是较复杂的,大致代码如下
const TIME = 900;
Page({
data:{
foreImg:'',
tetris:null,
timer:null,
isContinue:true,
downKey:null,
speed:1,
score:0,
time:0,
},
refresh(offset = 0){
},
gameEnd(){
},
drawGrid(g,fill){
},
initTimer(){
const { tetris } = this.data;
let tetri = tetris.createReadomTetris();
const redraw=()=>{
const { ctx, canvas } = this.data.context;
const { isContinue, downKey, speed, score, time } = this.data;
if(isContinue && !downKey){
let offset = 1;
if(this.refresh(offset)){
if(tetri.gt==0){
this.gameEnd();
return;
}
tetris.joinGrids(tetri);
let scope = tetris.clearFillGrids();
tetri = tetris.createReadomTetris();
let grids = tetris.getGrids(true);
ctx.clearRect(0,0,canvas.width,canvas.height);
grids.forEach(g=>this.drawGrid(g,true));
this.setData({
foreImg: canvas.toDataURL(),
score: score+scope,
});
ctx.clearRect(0,0,canvas.width,canvas.height);
}else{
tetri.gt+=offset;
}
}
canvas.requestAnimationFrame(()=>{
let t = Math.trunc(TIME*speed);
this.data.timer = setTimeout(redraw,t);
this.setData({
time:time+t
})
});
};
redraw();
},
}
完善细节
上面讲得一些的方法都是比较详细的,应该能看得明白吧,对了,那个模块文件只需要实现一些方法就可以了,文件路径为/static/utils/tetris.js ,具体怎样写得,参考代码大致如下
const COLS = 4;
const RetrisMini = [
[0,1,5,9],[0,1,2,5],[0,4,8,12],[0,1,4,5],[2,4,5,6],[1,4,5,9],[0,1,2,3],[0,4,8,9],[1,4,5,6],[0,1,2,4],[0,4,5,8]
];
export default class Tetris{
#grids;
#cols;
#rows;
#coordis;
#tetri;
constructor(config){
const { rows, cols } = config;
const grids = new Array(rows*cols);
for(let i=0; i<rows; i++){
for(let j=0; j<cols; j++){
grids[i*cols+j]={ l:j, t:i };
}
}
this.#grids=grids;
this.#cols=cols;
this.#rows=rows;
this.#coordis=[];
}
moveTetriAtHorizontal(l,success){
}
getGrids(filter){
}
getGridsIndex(l,t){
}
joinGrids(titri,l,t){
}
clearFillGrids(){
let scope=0;
return scope;
}
isIntoTetris(g){
return true;
}
isTouchTetris(titri,l,t){
}
createCoordis(cs){
}
createReadomTetris(){
}
getTetris(){
return this.#tetri;
}
rotateRightAngle(success){
}
}
💡一个问题 可能有注意到了,代码中的RetrisMini 是什么东西,看不懂正常,来解说一下,第一个[0,1,5,9] ,表格形式填充如下,仔细看一看,好像是一个方块形状的图案
这就是基本方块形状,方便后面绘制的,
还有一些实现细节,剩下的方法这里就不讲了,由于篇幅有限,没法在这里将每个实现细节都讲得清楚,项目代码写得是不多,就讲到这了,请自己动手完善,相信自己,努力就会有收获。
如果想要看完整项目源码的请"点击这里",点击进去展开资源一栏往下仔细找一找就有了。
运行小程序
下面是游戏项目源码运行的效果动图,是否心动了呢,欢迎尝试,项目源码完整,运行无问题,请放心下载学习,谢谢!
💡关于游戏剧情 俄罗斯方块游戏原本是没有剧情的,让本人想起来了,跟两个神话故事有异曲同工之妙呢,分别是《精卫填海》和《女娲补天》故事,这故事来做游戏剧情好像可以,还有其它剧情吗,这里不多说了,剧情怎么写,请自己脑补。
|