Hello,I'm Shendi;
做了一个Web版的小游戏,也是我制作的第一个H5小游戏
更多实战内容请进入我的实战专栏: https://blog.csdn.net/qq_41806966/category_9656338.html
目录
简介
拥有俄罗斯方块的基本功能
方块颜色随机
掉落速度会随着时间增长而加速
直接落地
实现了暂停功能
实现了虚拟按键
下一个方块的显示
效果视频
首先上制作和效果视频---基本上看完视频就能了解到制作过程了
比较简单,麻烦的是方块的变换部分都需要自己一个个去实现(使用矩阵旋转效果不好)
H5俄罗斯方块
解析
整个项目只有两个文件一个 html 文件,一个 js 文件
主要的地方就是 canvas,如果对canvas不熟可以先看下这篇文章
https://blog.csdn.net/qq_41806966/article/details/103779839
游戏规则
- 宽: 10
- 高: 20
- 一横排满则消除
- 最后一个方块到了顶端则游戏结束
- 七个方块
为了更好地体验,方块下降速度应该随着时间增长而加速
页面的制作
整体页面只有一个 canvas 和 两个 div
两个 div 分别为暂停界面和结算界面
代码片段如下
html页面的js片段
上面代码就是提供了显示暂停界面和结束界面的方法
以及对应界面的按钮点击后做的操作,也就是 ui 方面的 js 代码
主要的是 game.init 这一行,初始化整个画布
绘制背景
我将绘制背景的方法放到了 game 对象中
上面的代码,前三行是绘制背景,黑色
然后绘制场景的四条线
接下来的代码就是绘制按键了
画布的初始化
我将关于游戏处理的一些方法都放到了 game 对象中
html 页面会执行 game对象的init方法,传递canvas对象
此方法会先判断canvas是否为空,后面重新开始游戏不需要再次传递参数了
并且将画布的context获取
当获取到画布和画笔后,会先绘制背景,然后绘制开始游戏
接下来给画布添加点击事件,用于点击虚拟按键(位置是自己通过输出试出来的)
最后会初始化一些变量,包括了分数,速度,时间,场景
当点击开始游戏的时候会执行 game对象的 run 方法
主要的操作都在 start 方法中
方块对象
我创建了两个方块对象,一个是当前方块,一个是下一个方块
提供了 spawn 方法用来生成方块信息
当前方块代码如下
当前方块的信息都是从下一个方块的信息拷贝
当生成了当前方块,会生成新的下一个方块
下一个方块多了颜色集合
在生成方块的时候,会生成一个随机的方块,生成位置是预定义的
在生成方块中有一个init方法用于初始化一些方块信息
然后就是一些固定的位置设置
游戏逻辑执行
start() 方法主要用于界面的渲染
当游戏开始后,我们需要一直刷新整个canvas
在 game 对象中有一个二维数组代表场景
我们的方块一开始是不在场景内的,当方块完成放置的时才会加入场景
也就是说,场景内只有已放置的方块信息,具体值是颜色信息
具体操作
- 绘制背景
- 绘制当前方块
- 绘制下一个方块
- 绘制现有方块
- 绘制时间,分数
- 自动下降
- 根据时间调整速度
- 递归
代码如下
/** 开启游戏 */
start: function() {
// 游戏执行逻辑
game.bg();
// 分数, 游戏事件
game.ctx.fillStyle = "white";
game.ctx.fillText("分数:" + game.scope, 120, 60);
game.ctx.fillText("坚持时间:" + Math.round(game.time), 250, 60);
// 渲染方块
game.ctx.fillStyle = cur.color;
for (let i = 0; i < cur.num; i++) {
game.ctx.fillRect(game.minX + game.size * cur.arrX[i], game.minY + game.size * cur.arrY[i], game.size, game.size);
};
// 渲染下一个方块
game.ctx.fillStyle = nextCur.color;
for (let i = 0; i < nextCur.num; i++) {
game.ctx.fillRect(game.minX + 180 + game.size * nextCur.arrX[i], game.minY + game.size * nextCur.arrY[i], game.size, game.size);
};
// 渲染现有方块
for (let i = 0; i < game.scene.length; i++) {
for (let j = 0; j < game.scene[i].length; j++) {
if (game.scene[i][j] != null) {
game.ctx.fillStyle = game.scene[i][j];
game.ctx.fillRect(game.minX + j * game.size, game.minY + i * game.size, game.size, game.size);
}
}
}
// 自动下降
if (game.num++ == game.speed) {
game.num = 0;
gameEnv.down();
// 调整速度, 最快为0.1s
if (game.speed != 2) {
game.speed = 10 - Math.round(game.time / 30);
}
}
game.time += 0.05;
// 游戏暂停则不继续
if (!game.isPause) setTimeout("game.start()", 50);
},
按键监听
交互事件(*)
封装成了一个对象 gameEnv
里面有 变换,加速,左,右,直接到底 的方法
思路
当我们触发左事件时,方块会向左移动,因为之前的设计是将当前方块作为一个单独的对象,所以我们只需要修改对象中的坐标位置就行
- 向左 x-1,当到边界不能往左
- 向右 x+1,与向左同
- 向下 y+1,当碰到其他方块或者到底部则完成放置
- 向上,变换 顺时针旋转90度,需要自己一个一个去实现(大部分都是这么做的),除去正方形,需要实现6*4=24个if块
- 直接到底,往下的操作需要判断,正好我们封装了向下的操作,我们只需要在向下方法中返回一个值,让我们知道是否放置完成就可以轻松实现此需求
结果判断,加分机制
当我们完成放置时,需要判断先判断游戏是否结束,然后判断是否有可以消除的方块,是则需要加分
如果游戏结束条件不成立,则开始下一个物体,并判断是否有可以消除的方块
- 加分机制
- 一行100
- 两行200
- 三行400
- 四行800
暂停游戏
在暂停方法中,会去调用一个名 pause 的方法
游戏结束
在线试玩
https://1711680493.github.io/Tetris/index.html
源码
在我的 github 中的 Tetris 中,可以点下方链接进入,查看里面的介绍获取
https://github.com/1711680493/Application
别忘了点 Star~