原文地址:canvas实现俄罗斯方块

好久没使用canvas了,于是通过写小游戏“俄罗斯方块”再次熟悉下canvas,如果有一定的canvas基础,要实现还是不难的。实际完成的Demo请看:canvas俄罗斯方块

原理详解

看游戏最终界面,可知需要实现以下关键功能:

  1. 游戏面板,也就是12 * 20的方格,以及是否填充了方块信息;
  2. 运动方块,方块需要实现移动,变形的功能。

界面的实现

整个面板就是以左上角(0,0)为原点的坐标系,右上角(12,0)左下角(0,20)右下角(12,20),每个点的坐标位置都可以确定。是否已经填充方块,我们可以将每个方格看成一个数组元素,0表示没有,1表示已经填充。12 * 20 的面板使用两层数组,即用20个长度为12的数组实现。

var maps = [[0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,1,0,1,0], ...];

画出面板的代码,用最基础的canvas的api就能实现

	//格子
for(var i=0;i<12;i++){
for(var j=0;j<20;j++){
ctx.fillRect(i*40,j*40,40,40);
ctx.strokeRect(i*40,j*40,40,40);
if(this.maps[j][i]==1){//方格已经有填充内容
ctx.save();
ctx.lineWidth=4;
ctx.fillStyle='hsla(200,100%,50%,.5)';
ctx.strokeStyle='hsla(200,100%,50%,.9)';
ctx.fillRect(i*40,j*40,40,40);
ctx.strokeRect(i*40+2,j*40+2,38,38);
ctx.restore();
}
}
} //边框
ctx.lineWidth=4;
ctx.strokeStyle='hsla(0,100%,0%,.3)';
ctx.moveTo(0,0);
ctx.lineTo(0,20*40);
ctx.lineTo(12*40,20*40);
ctx.lineTo(12*40,0);
ctx.stroke();
ctx.restore();

方块的实现

游戏中用到以下 7 种图形

结合上面介绍的坐标系,数组 [x1, y1, x2, y2, x3, y3, x4, y4] 就是上面图形中4个点坐标的数据表现形式,7 种图形的坐标分别如下:

var Arr = [[4,0,4,1,5,1,6,1],[4,1,5,1,6,1,6,0],[4,0,5,0,5,1,6,1],[4,1,5,0,5,1,6,0],
[5,0,4,1,5,1,6,1],[4,0,5,0,6,0,7,0],[5,0,6,0,5,1,6,1]];

方块的移动,遍历整个数组,加上位移向量就行,非常简单

class Shape {
constructor(m){
this.m = Object.assign([],m);
}
move(x,y){ // 位移
var m = this.m,
l = m.length;
y = y||0; for (var i=0;i<l;i=i+2){
m[i]+=x;
m[i+1]+=y;
}
return this;
}

方块的旋转,俄罗斯方块里面方块除了左右和上下运动,还会旋转,不是吗?稍微思考下就知道,这不过就是矩阵变换而已,也就是每次图形绕中心点旋转90度。我这里用数组第三个点作为图形变换的中心点,当然这样处理不够完善。

class Shape {
transform(){//二维矩阵变换
var m =this.m,
l = m.length,
c = Math.ceil(l/2),
x = m[c],
y = m[c+1],
cos = Math.cos(Math.PI/2),
sin = Math.sin(Math.PI/2); for (var i=0;i<l;i=i+2){
if(i == c) continue;
var mx = m[i]- x,
my = m[i+1] - y,
nx = mx*cos - my*sin,
ny = my*cos + mx*sin;
m[i]=x+nx;
m[i+1]=y+ny;
}
return this;
}

边界条件

主要包括如下三个方面

  1. 方块位置不能超出界面的判断;
  2. 方块到达底部或放置完成的判断;
  3. 游戏结束的判断。

遍历数组 (1)任意一个点y坐标为19时表示到达了底部;(2)获取该坐标的y+1位置在maps的信息,如果为1表示已经填充。这两种情况下,运动方块的周期结束,将该方块的坐标填充到maps对应的数组里面即可。

如果坐标的y+1已经有填充,同时当前坐标小于1,即已经在界面的顶部了,那么表示游戏结束。

var isEnd = false,isOver=false,x,y;
for(var i=0,sl=that.shape.m.length;i<sl;i=i+2){
x=that.shape.m[i];
y=that.shape.m[i+1];
if(y >= 19){ // 到了底部
isEnd = true;break;
}
if(that.maps[y+1][x]==1){ // y+1位置已经填充
isEnd = true;
if(y <= 1){isOver=true;} // 游戏结束
break;
}
}

方块运动周期结束时检测每一层是否满格,以及满格后的处理。某项数组全部元素都为1则表示已经满格,那么删除该项数组,同时列表头再压入一项每个元素都为0的数组即可。

checkPoint(){
var that = this,
maps = that.maps; for(var i=0,l=maps.length;i<l;i++){
if(Math.min.apply(null,maps[i]) == 1){// 表示该层已经满格
that.maps.splice(i,1);
that.score+=10; // 增加分数
that.maps.unshift([0,0,0,0,0,0,0,0,0,0,0,0]);
}
}
return this;
}

绑定事件

主要就是绑定keydown事件,要注意的是左移和右移事件包括了边界判断

bindEvent(){
var that = this;
document.addEventListener('keydown',function(e){
switch(e.keyCode){
case 13: //enter
cancelAnimationFrame(that.timer);
that.init().update();
break;
case 80: //p
that.pause = !that.pause;
break;
case 40: //down
that.d = 0.5;
break;
case 37: //left
var over = false,
maps = that.maps,
shape = that.shape,
m = shape.m;
for(var i=0,l=m.length;i<l;i=i+2){
if(m[i]<=0 || maps[m[i+1]][m[i]-1] == 1){
over = true;break;
}
}
if(!over) shape.move(-1,0);
break;
case 39: //right
var over = false,
shape = that.shape,
maps = that.maps,
m = shape.m;
for(var i=0,l=m.length;i<l;i=i+2){
if(m[i]>=11 || maps[m[i+1]][m[i]+1] == 1){
over = true;break;
}
}
if(!over) shape.move(1,0);
break;
case 32: //space
that.shape.transform();
break;
}
},false);
}

总结

这里面实现了俄罗斯方块的最基本功能,还有关卡等功能点并没有实现,同时该demo仍然有不完善的地方需要修正。

canvas实现俄罗斯方块的更多相关文章

  1. canvas版《俄罗斯方块》

    试玩(没有考虑兼容低版本浏览器): See the Pen Canvas俄罗斯方块 by 王美建 (@wangmeijian) on CodePen. ************************ ...

  2. Canvas俄罗斯方块

    写在前面 潜水博客园多年,从未写过博客.最近才注册博客,遂将很久前写的俄罗斯方块分享出来.第一次写博客,不喜勿喷... 游戏说明 游戏操作:J向左,L向右,I旋转,K快速下降 游戏基于HTML can ...

  3. canvas 俄罗斯方块

    <!doctype html> <html> <body> <canvas id="can" width="360px" ...

  4. x01.Tetris: 俄罗斯方块

    最强大脑有个小孩玩俄罗斯方块游戏神乎其技,那么,就写一个吧,玩玩而已. 由于逻辑简单,又作了一些简化,所以代码并不多. using System; using System.Collections.G ...

  5. 【自己给自己题目做】:如何在Canvas上实现魔方效果

    最终demo -> 3d魔方 体验方法: 浮动鼠标找到合适的位置,按空格键暂停 选择要翻转的3*3模块,找到相邻两个正方体,鼠标点击第一个正方体,并且一直保持鼠标按下的状态直到移到第二个正方体后 ...

  6. H5版俄罗斯方块(2)---游戏的基本框架和实现

    前言: 上文中谈到了H5版俄罗斯方块的需求和目标, 这次要实现一个可玩的版本. 但饭要一口一口吃, 很多东西并非一蹴而就. 本文将简单实现一个可玩的俄罗斯方块版本. 下一步会引入AI, 最终采用coc ...

  7. [原创]html5_PC游戏_图片俄罗斯方块

    PC游戏_图片俄罗斯方块 以前的了,快一年了... 使用了离线canvas复制的方法,启动预览效果需要服务器支持 另外,AC娘图片可以自己做加载功能,这样游戏图片显示更顺畅 效果: --- 代码: h ...

  8. 自己写了个H5版本的俄罗斯方块

    在实习公司做完项目后,实在无聊.就用H5写了几个游戏出来玩一下.从简单的做起,就搞了个经典的俄罗斯方块游戏. 先上效果: 上面的数字是得分,游戏没有考虑兼容性,只在chrome上测试过,不过大部分现代 ...

  9. H5实现俄罗斯方块(一)

    这几天一直忙于公司的项目,涉及到流程问题,(有时间会写成博客的)...一直没有更新... 为了更加巩固js的基础,自己封装类似于JQuery的操作库来对dom进行操作. 一:前度页面的绘制. < ...

随机推荐

  1. orderBy新写法

    通常,我们处理排序规则的处理方法是在sql 语句中order by create_time desc, 但是这时我们需要从控制器中一步步找到该方法,操作多. 我们试着将业务逻辑拆分到控制器 中, 把排 ...

  2. Commandline OpenVPN client on Mac OSX with macports

    http://www.tuicool.com/articles/FjuyQj  注:文中有些内容做了修改,特别是那个配置文件,不能直接抄着用. Most people use TunnelBrick ...

  3. PHP基础(一)--字符串函数大盘点(基础篇)

    参考地址http://php.net/manual/zh/ref.strings.php addcslashes - 以 C 语言风格使用反斜线转义字符串中的字符    string addcslas ...

  4. Rafy 开源贡献中心 - 组织成立,并试运行一月小结

    背景 最近两年,工作中虽然大量使用了 Rafy 框架作为各个产品.项目的开发框架.我是 2015 年的年中加入现在这家公司的,由于我个人工作太忙的缘故,一直没怎么编码,Rafy 框架底层的核心成长也比 ...

  5. unity零基础开始学习做游戏(六)背景给我“滚”~

    -------小基原创,转载请给我一个面子 一望无际的...空旷场景,看着实在是难受,不如添加些背景吧.如果要真的想好好设计关卡背景的话,最好是做一个地图编辑器,不过做开发工具毕竟有点点复杂且枯燥,以 ...

  6. phone number

    problem description: you should change the given digits string into possible letter string according ...

  7. RabbitMQ 安装 Your installed version of Erlang (6.2) is too old. Please install a more recent version.

    windows安装RabbitMQ时在安装完Erlang语言开发包后,再安装RabbitMQ时报错: Your installed version of Erlang (6.2) is too old ...

  8. NS3系列——eclipse + NS3环境搭建

    1. 安装NS3 (1)在 ubuntu12.04 中安装 ns3.20,首先要安装一下各种依赖软件: sudo apt-get install gcc g++ pythonsudo apt-get ...

  9. java 23种设计模式教程

    设计模式分类 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 行为型模 ...

  10. 导航狗IT周报-2018年05月18日

    原文链接:https://www.daohanggou.cn/2018/05/18/it-weekly-8/ DDoS专题 最近Web安全里的一个热点就是包括阮一峰博客在内的多个教育类IT网站被DDo ...