Canvas 游戏——俄罗斯方块
我第三个动画游戏终于可以玩了,^_^。
试玩
Demo:http://ambar.github.com/Tetris/
截图
起源
- 俄羅斯方塊
- Tetris
所得
如何实现
由于 wikipedia 的素材很像砖块,我代码里就把 Tetromino 称为了砖块(brick),整个拼板称为墙面(wall)——分别对应了游戏中玩家控制目标和地图。
变形
首先观察 " J " 形状转置(T)和旋转(R)的图形,零表示空心部位,非零实心部位:
J =>
1,0,0
1,1,1T =>
1,1
0,1
0,1R =>
1,1
1,0
1,0
转置即每一行变成了目标的每一列。再比较转置和旋转的图形,可以发现,它们的区别在于每一行的元素顺序是相反的,这对应的数组方法很明晰了,即 pop 和 unshift ,实现:
// 用二维数组表示'形状'
var shape_array = [[1,0,0],[1,1,1],]// 转置,行列交换
var transpose = function(ary){var ret = [], row, rows = ary.length, cols = ary[0].length;cols.times(function(y){ret.push(row = [])rows.times(function(x){row.push(ary[x][y])})})return ret;
}// 向右旋转(顺时针),每行生成列元素时顺序相反
var rotate = function(ary){var ret = [], row, rows = ary.length, cols = ary[0].length;cols.times(function(y){ret.push(row = [])rows.times(function(x){row.unshift(ary[x][y])})})return ret;
}
这时,再看看向左旋转的图形,与转置图形比较可以显然看出来,把转置后 行的顺序逆转 就可以了,即可用现成的数组的 reverse 方法:
/* 逆时针旋转图示
0,1
0,1
1,1
*/// 逆时针旋转算法
var rotate_anticlockwise = function(ary){return transpose(ary).reverse();
}
我开始的游戏是用的逆时针旋转,我以为这更自然。试玩了一下网上其他的游戏实现,结果都是顺时针的 =_= 。
砖块定义
我定义了三个主要属性:
- position : 左下角参照坐标
- parts : 每个可见部分坐标
- shape : 形状
/*
* 以一个形状(二维数组)的左下角为参照位置,把它映射成一个位置列表(一维数组)。零为空位,全部舍弃
* @pos {vector}
* @shape {array}
*/
var mapShape = function(pos,shape) {var ret = [], rows = shape.length, cols = shape[0].length;rows.times(function(x){cols.times(function(y){shape[rows-x-1][y] && ret.push( pos.add( V([y,-x]) ) )});});return ret;
}
若某砖块的参照坐标为Vector[3,4],shape 为上面演示的 J,它的 parts 则为:
// parts = mapShape( V([3,4]), shape_ary ) =>
[ Vector[3,4], Vector[4,4], Vector[5,4], Vector[3,3] ]
有了恰当的属性定义之后,移动和拼到墙面就是轻而易举的了。
地图
地图关系存储及碰撞部分,结构也和上面的形状一样,使用二维数组。
首先要注意的是屏幕上的坐标系统和数组不是直接对应的:
screen : {x,y}
┏━━━x
┃
yarray : [x][y]
┏━━━y
┃
x
屏幕上的点转置才能对应上数组的元素。
我游戏的前半程是这样存储的:
map[p.x][p.y] = type;
点 p 与地图数组元素一 一对应,这样用起来很爽,但是有两个缺点:
- 观察或打印结构不方便,需要转置地图数组。(如果拼板是 20*10,此时地图结构是的 10*20)
- 检测消行不方便,也要转置列为行。
因此,在后半程,改正了过来:
map[p.y][p.x] = type;
消行
我用的一种相当简易的做法,毫无特效——直接删除一行,再用充满零元素的模板行塞到地图头部:
function eraseRow(idx) {this.map.splice(idx,1);this.map.unshift(this.tmplRow);
}
碰撞
es5 的 some 方法最适合处理这个,直接接受上面的 parts 参数就好:
function collideWith(vectors) {var map = this.map, height = this.height;return vectors.some(function(v) {var row = map[v.y];return v.y >= height || (row && row[v.x]);})
}
细节
- 明暗变化的颜色,用HSL比RGB方便太多了。
- 画多边形时,斜线会有黑色的锯齿,可以再在上面画一条线段解决。
- canvas 绘制文字消耗太大,尤其是firefox。一定要用的话,新建一个 canvas 层做背景,文字绘制到它上面,并用CSS定位把它到主画布下面。
- 未开户硬件加速的情况下,仅仅绘制普通图形,半屏之后也很卡——解决办法,用 getImageData 缓存绘制过的图形。
AMD
游戏代码后期改用 AMD 方式组织,加载器挑选了国人写的 seajs 。
AMD 是 CommonJS 倡议的模块定义方式,干掉了老套的用全局变量做命名空间的形式。 与老式的命名空间相比,AMD 的方式更加容易组织代码,结构也更干净、更一致。
- 如果一个模块是一组功能的集合,就用 exports
- 如果一个模块是一个单一的类,就用 module.exports
- 模块定义(define函数)的第一个参数‘模块名’是完全无意义的。我开始为了能够简单的合并文件,就全部命名了一遍,后面发现太麻烦——因为你要引用它时,就可能不得不打开文件去找它取了什么名字,这很悲剧。后面就自然的全部改了。
文件的摆放层次 就是就是你的命名空间,这应该是 AMD 隐含的核心理念。
- 循环引用。seajs 会报一个警告,仔细检查可以排除。但是,不排除也可以工作。有点纠结,现在的折衷做法是导出了一个全局变量 TetrisGame。
- define 第二个依赖参数也可能会出现模块引用的奇怪问题。同样是循环引用,但没有错误提示什么的,加载的模块也没有加载到——许久之后,提示超时了。
使用
// 网格单位长度, 默认 40
// TetrisGame.unit = 20;// 显示网格线, 默认 true
// TetrisGame.showGrid = false;// 主题类型 ["classic", "window", "bubble"], 默认 classic
// TetrisGame.theme = 'window';// canvas,列数,行数,缩放
TetrisGame.init('#tetris-game',10,20,1);
// TetrisGame.init('#tetris-game',10,20,.5);
查看或下载
转载于:https://www.cnblogs.com/ambar/archive/2011/10/26/html5-canvas-game-tetris.html
Canvas 游戏——俄罗斯方块相关推荐
- HTML5 Canvas游戏开发实战 PDF扫描版
HTML5 Canvas游戏开发实战主要讲解使用HTML5 Canvas来开发和设计各类常见游戏的思路和技巧,在介绍HTML5 Canvas相关特性的同时,还通过游戏开发实例深入剖析了其内在原理,让读 ...
- 鸿蒙小游戏-俄罗斯方块
作者:225王宗振 前言 为了更好地熟练掌握鸿蒙手机应用开发,查阅资料和算法尝试开发鸿蒙小游戏--俄罗斯方块. 概述 完成鸿蒙小游戏APP在手机上的编译在项目中所使用到的软件为DevEco Studi ...
- python tkinter火柴人_用Python实现童年小游戏俄罗斯方块!别说还挺好玩!
原标题:用Python实现童年小游戏俄罗斯方块!别说还挺好玩! 前言 大三上学期的程序设计实训大作业,挑了其中一个我认为最简单的的<图书管理系统>来写.用python写是因为py有自带的G ...
- 《HTML5 Canvas游戏开发实战》——2.1 绘制基本图形
本节书摘来自华章计算机<HTML5 Canvas游戏开发实战>一书中的第2章,第2.1节,作者:张路斌著, 更多章节内容可以访问云栖社区"华章计算机"公众号查看. 2. ...
- canvas游戏篇 - 贪吃蛇
截图如下: HTML 代码如下: <!DOCTYPE html> <html> <head><meta charset="UTF-8"&g ...
- HTML5 canvas游戏工作原理
HTML5已经不是一个新名词.它看上去很cool,有很多feature,大多数人普遍看好它的发展.对于我来说,最感兴趣的是它的canvas标签,可以结合Javascript来绘制游戏画面. 我们可以在 ...
- C语言游戏: 俄罗斯方块(Tetris)@兼谈程序优化方法 [源码+exe下载]
消除重复:如何将程序逻辑与数据分开? ----俄罗斯方块(Tetris)@兼谈程序优化方法 背景提示: 1,数据,是程序设计的根本.因为任何程序都可以看作是一组数据,和作用于其上的一组操作,这也是面向 ...
- 原生js小游戏——俄罗斯方块
还记得童年时期的小游戏俄罗斯方块吗?我发现用js就可以写出来 页面效果如下: 具体代码如下: 首先展示css样式: .c {margin: 1px;width: 19px;height: 19px;b ...
- Java语言实现经典游戏俄罗斯方块
使用Java语言编写的经典游戏俄罗斯方块,能够调整游戏难度.加快下落速度.左右旋转方块等全部功能.(代码已集成在一个class内,如下所示,点击即可运行.内容水平有限,欢迎指正批评.) 演示视频 ht ...
最新文章
- OpenCV和Python动手操作计算机视觉学习教程
- 如何判断一个字符串在JavaScript中是否包含某个字符?
- SVN的搭建及使用(三)用TortoiseSVN修改文件,添加文件,删除文件,以及如何解决冲突,重新设置用户名和密码等...
- python按钮点击按一次触发一次_家里有个“按钮开关”能救命,必须每个月按一次,学会受用一生!...
- boxfilter 函数
- Neo4j:Cypher – Neo.ClientError.Statement.TypeError:不知道如何添加Double和String
- Gartner:2020年全球IaaS公有云服务市场增长40.7%
- 前后端分离,如何解决跨域(代理模式)、路由拦截(进入页面需要登录)以及请求拦截(登录TOKEN失效)等问题(初学者)
- Struts2中我所遇到的内存溢出(java.lang.OutOfMemoryError)异常错误介绍
- Unity3d读取.csv文件
- 从零开始--系统深入学习android(实践-让我们开始写代码-新手指南-3.Hello,本地化)...
- 数据分析工具有哪些类型
- 数字信号处理--7.4--数字滤波器
- python字符串与列表与运算_what's the python之基本运算符及字符串、列表、元祖、集合、字典的内置方法...
- 【C# 练习】C# 程序设计实用教程(第2版)黄兴荣
- Python+Opencv身份证号码区域提取及识别
- 调通sina33下的AP6212A0(WIFI+BT)V1.2
- win10下git报fatal: open /dev/null or dup failed解决办法(附null.sys文件下载)
- 横版过关游戏开发-碰撞检测
- JavaScript代码优化 --- 长期更新