我第三个动画游戏终于可以玩了,^_^。

试玩

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 的方式更加容易组织代码,结构也更干净、更一致。

这个游戏花了我几个小时来做转换,总结:

seajs 实际使用上,可能会碰到的问题:

使用


// 网格单位长度, 默认 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://github.com/ambar/Tetris

转载于:https://www.cnblogs.com/ambar/archive/2011/10/26/html5-canvas-game-tetris.html

Canvas 游戏——俄罗斯方块相关推荐

  1. HTML5 Canvas游戏开发实战 PDF扫描版

    HTML5 Canvas游戏开发实战主要讲解使用HTML5 Canvas来开发和设计各类常见游戏的思路和技巧,在介绍HTML5 Canvas相关特性的同时,还通过游戏开发实例深入剖析了其内在原理,让读 ...

  2. 鸿蒙小游戏-俄罗斯方块

    作者:225王宗振 前言 为了更好地熟练掌握鸿蒙手机应用开发,查阅资料和算法尝试开发鸿蒙小游戏--俄罗斯方块. 概述 完成鸿蒙小游戏APP在手机上的编译在项目中所使用到的软件为DevEco Studi ...

  3. python tkinter火柴人_用Python实现童年小游戏俄罗斯方块!别说还挺好玩!

    原标题:用Python实现童年小游戏俄罗斯方块!别说还挺好玩! 前言 大三上学期的程序设计实训大作业,挑了其中一个我认为最简单的的<图书管理系统>来写.用python写是因为py有自带的G ...

  4. 《HTML5 Canvas游戏开发实战》——2.1 绘制基本图形

    本节书摘来自华章计算机<HTML5 Canvas游戏开发实战>一书中的第2章,第2.1节,作者:张路斌著, 更多章节内容可以访问云栖社区"华章计算机"公众号查看. 2. ...

  5. canvas游戏篇 - 贪吃蛇

    截图如下: HTML 代码如下: <!DOCTYPE html> <html> <head><meta charset="UTF-8"&g ...

  6. HTML5 canvas游戏工作原理

    HTML5已经不是一个新名词.它看上去很cool,有很多feature,大多数人普遍看好它的发展.对于我来说,最感兴趣的是它的canvas标签,可以结合Javascript来绘制游戏画面. 我们可以在 ...

  7. C语言游戏: 俄罗斯方块(Tetris)@兼谈程序优化方法 [源码+exe下载]

    消除重复:如何将程序逻辑与数据分开? ----俄罗斯方块(Tetris)@兼谈程序优化方法 背景提示: 1,数据,是程序设计的根本.因为任何程序都可以看作是一组数据,和作用于其上的一组操作,这也是面向 ...

  8. 原生js小游戏——俄罗斯方块

    还记得童年时期的小游戏俄罗斯方块吗?我发现用js就可以写出来 页面效果如下: 具体代码如下: 首先展示css样式: .c {margin: 1px;width: 19px;height: 19px;b ...

  9. Java语言实现经典游戏俄罗斯方块

    使用Java语言编写的经典游戏俄罗斯方块,能够调整游戏难度.加快下落速度.左右旋转方块等全部功能.(代码已集成在一个class内,如下所示,点击即可运行.内容水平有限,欢迎指正批评.) 演示视频 ht ...

最新文章

  1. OpenCV和Python动手操作计算机视觉学习教程
  2. 如何判断一个字符串在JavaScript中是否包含某个字符?
  3. SVN的搭建及使用(三)用TortoiseSVN修改文件,添加文件,删除文件,以及如何解决冲突,重新设置用户名和密码等...
  4. python按钮点击按一次触发一次_家里有个“按钮开关”能救命,必须每个月按一次,学会受用一生!...
  5. boxfilter 函数
  6. Neo4j:Cypher – Neo.ClientError.Statement.TypeError:不知道如何添加Double和String
  7. Gartner:2020年全球IaaS公有云服务市场增长40.7%
  8. 前后端分离,如何解决跨域(代理模式)、路由拦截(进入页面需要登录)以及请求拦截(登录TOKEN失效)等问题(初学者)
  9. Struts2中我所遇到的内存溢出(java.lang.OutOfMemoryError)异常错误介绍
  10. Unity3d读取.csv文件
  11. 从零开始--系统深入学习android(实践-让我们开始写代码-新手指南-3.Hello,本地化)...
  12. 数据分析工具有哪些类型
  13. 数字信号处理--7.4--数字滤波器
  14. python字符串与列表与运算_what's the python之基本运算符及字符串、列表、元祖、集合、字典的内置方法...
  15. 【C# 练习】C# 程序设计实用教程(第2版)黄兴荣
  16. Python+Opencv身份证号码区域提取及识别
  17. 调通sina33下的AP6212A0(WIFI+BT)V1.2
  18. win10下git报fatal: open /dev/null or dup failed解决办法(附null.sys文件下载)
  19. 横版过关游戏开发-碰撞检测
  20. JavaScript代码优化 --- 长期更新

热门文章

  1. 【Python正则表达式】网址合法性检测
  2. TIDB在伴鱼的实践
  3. Java异常的根类似_Java异常的根类是
  4. vue渲染html代码
  5. 气质的培养教程(哈佛管理世界)
  6. js设计模式之观察者模式和订阅发布模式
  7. win10自带记事本的编码问题
  8. C语言实现Nim游戏
  9. 某侦察队接到一项紧急任务,要求在A、B、C、D、E、F六个队员中尽可能多地挑若干人,但有以下限制条件
  10. TFRecord教程、原理及用法