当前位置:网站首页>大道至简 html + js 实现最朴实的小游戏俄罗斯方块
大道至简 html + js 实现最朴实的小游戏俄罗斯方块
2020-11-06 21:04:00 【kingapple】
前言
老实说这其实这是自己写的第二个俄罗斯方块。
本次的重写,除了复习一下以前自己写的代码的同时,也加有了一些新的思考。
其中最重要的一个目的就是渲染层与逻辑层在代码层面的分离(重新设计代码)。
——最终效果图如下。
正题
来看下一下俄罗斯方块的一些概念与逻辑
一、方块
最传统的俄罗斯方块,只有7个方块。
通常由T、I、Z、S、L、J、O这7个字母代替。
转换成代码如下。
shaps = {
'I': [
[1, 1, 1, 1],
],
'L': [
[1, 1, 1],
[1, 0, 0],
],
'J': [
[1, 1, 1],
[0, 0, 1],
],
'Z': [
[1, 1, 0],
[0, 1, 1],
],
'S': [
[0, 1, 1],
[1, 1, 0],
],
'T': [
[1, 1, 1],
[0, 1, 0],
],
'O': [
[1, 1],
[1, 1],
],
};
enumShaps = {
'I': [
[[0,0],[1,0],[2,0],[3,0]],
[[1,-1],[1,0],[1,1],[1,2]],
],
'L':[
[[0,0],[1,0],[2,0],[0,1]],
[[0,0],[1,0],[1,1],[1,2]],
[[2,0],[0,1],[1,1],[2,1]],
[[0,0],[0,1],[0,2],[1,2]],
],
'J':[
[[0,0],[1,0],[2,0],[2,1]],
[[1,0],[1,1],[1,2],[0,2]],
[[0,0],[0,1],[1,1],[2,1]],
[[0,0],[1,0],[0,1],[0,2]],
],
'Z':[
[[0,0],[1,0],[1,1],[2,1]],
[[1,0],[1,1],[0,1],[0,2]],
],
'S':[
[[1,0],[2,0],[0,1],[1,1]],
[[0,0],[0,1],[1,1],[1,2]],
],
'T':[
[[0,0],[1,0],[2,0],[1,1]],
[[1,-1],[1,0],[1,1],[0,0]],
[[0,0],[1,0],[2,0],[1,-1]],
[[1,-1],[1,0],[1,1],[2,0]],
],
'O':[
[[1,0],[2,0],[1,1],[2,1]],
],
};
上面代码有两组方块。(矩阵型,没举型)
两者没有直接联系,是旋转方块衍生的两种思路。
两者最大的区别在于,第一组矩阵型方块的旋转需要相关算法进行换算,相对复杂。
而第二组,已经将美中方块的旋转结果枚举出来,更佳便于理解。
第一种方块选装
let shapData = shaps['T']
// 用算法旋转矩阵
shapData = matirx2dRotation(shapData)
const shapRender = (vector) => {
// 与枚举型略有不同
}
第二种方块旋转
// 比如下面代码接可以直接去除T方块的其中一个旋转数据
// 这个数据中的各个矢量再加上方块的场景中的方块偏移量就是方块的渲染数据了
const shapData = enumShaps['T'][1]
// vector 偏移量(就是方块在场景中的位置信息)
const shapRender = (vector) => {
return shapData.map(([x, y]) => [x + X, y + Y]);
}
以上完整代码在底部仓库地址中
二、碰撞与逻辑
标准的情况,场景中只有唯一一个方块收到玩家操作。
玩家操作的方块在游戏开始后便生成并交与玩家控制权。
玩家控制的方块,每当玩家操作反馈后进行碰撞逻辑的检测。
这里的操作反馈主要是方块左、右、下移动与旋转。
- 方块是否溢出场景(场景左右与底部边界碰撞)
- 方块是否碰撞场景中静止的方块
每次游戏心跳间隔,还需要将当前玩家控制的方块下降一格。
其中不论是玩家主动方块下降或是游戏心跳间隔中自动将方块下降。都需要检测是否与场景底部或其它静止方块发生碰撞与否。
如果碰撞成立,则将当前方块加入静止方块序列。
这时候就可以执行小方块的逻辑。
消玩方块后需要将空缺出来的位置补上。
最后生成一个新的方块加入到场景中。
新的方块进入场景的同时,需要立即检测与静止方块的碰撞。如果为真则游戏是否game over。
// 方块静止逻辑
const isShapDead = vector => {
// ...如果为真便加入到静止方块的序列
}
// 是否溢出场景
// 不需要检测顶部
const isOverFlow = vectors => {
const [width, height] = screenSize;
return vectors.some(([x, y]) => {
return x < 0 || x >= width || y >= height;
});
}
// 是否发生碰撞
const isShapHit = vectors => {
// ...
}
// 游戏是否失败
const isGameOver = data => {
// 方块初始位置矢量
const [, y] = vector;
if (y <= 0 && isShapHit(data)) {
return true;
}
return false;
}
以上完整代码在底部仓库地址中
三、渲染层与逻辑层分离
每一次游戏心跳,与每一次用户操作反馈会触发渲染
或许是做前后端分离有些时日了,多少受了虚拟dom的一点影响。
重新设计的代码,将游戏的整个过程虚拟化。
只在每一个心跳(类似游戏中帧的概念)或者用户每次主动操作后才会推送游戏虚拟数据到渲染层,由渲染层实现渲染逻辑。
// TetrisJS 整个游戏的逻辑代码
const TJS = new TetrisJS({
screenSize,
intervals: 1000,
});
// update 的回调函中接受渲染请求的推送
TJS.update(() => {
// TJS.map就是游戏的虚拟数据
renderGame(TJS.map)
});
const renderGame = data => {
// render 渲染逻辑
}
最后上仓库代码(以上代码基于此)https://github.com/applelee/tetris-js.git
老代码(慎点)https://github.com/applelee/tetris-js-old.git
版权声明
本文为[kingapple]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/1243524/blog/4540920
边栏推荐
- Common algorithm interview has been out! Machine learning algorithm interview - KDnuggets
- ES6 essence:
- DRF JWT authentication module and self customization
- [C / C + + 1] clion configuration and running C language
- What is the side effect free method? How to name it? - Mario
- Cglib 如何实现多重代理?
- Electron application uses electronic builder and electronic updater to realize automatic update
- 教你轻松搞懂vue-codemirror的基本用法:主要实现代码编辑、验证提示、代码格式化
- Wechat applet: prevent multiple click jump (function throttling)
- It's easy to operate. ThreadLocal can also be used as a cache
猜你喜欢
ES6学习笔记(五):轻松了解ES6的内置扩展对象
每个前端工程师都应该懂的前端性能优化总结:
axios学习笔记(二):轻松弄懂XHR的使用及如何封装简易axios
2019年的一个小目标,成为csdn的博客专家,纪念一下
keras model.compile Loss function and optimizer
I've been rejected by the product manager. Why don't you know
The road of C + + Learning: from introduction to mastery
前端工程师需要懂的前端面试题(c s s方面)总结(二)
NLP model Bert: from introduction to mastery (1)
[C / C + + 1] clion configuration and running C language
随机推荐
Python download module to accelerate the implementation of recording
Flink的DataSource三部曲之一:直接API
5.4 static resource mapping
Using consult to realize service discovery: instance ID customization
The difference between gbdt and XGB, and the mathematical derivation of gradient descent method and Newton method
Network security engineer Demo: the original * * is to get your computer administrator rights! 【***】
The choice of enterprise database is usually decided by the system architect - the newstack
Analysis of query intention recognition
Python + appium automatic operation wechat is enough
一篇文章带你了解CSS3圆角知识
JVM memory area and garbage collection
Installing the consult cluster
The data of pandas was scrambled and the training machine and testing machine set were selected
一篇文章带你了解CSS 渐变知识
6.2 handleradapter adapter processor (in-depth analysis of SSM and project practice)
Thoughts on interview of Ali CCO project team
axios学习笔记(二):轻松弄懂XHR的使用及如何封装简易axios
Natural language processing - BM25 commonly used in search
git rebase的時候捅婁子了,怎麼辦?線上等……
Construction of encoder decoder model with keras LSTM