自己做的俄罗斯方块(js + canvas)

大宝贱 2012-02-11 12:39:45
一直纠结要不要发上来,对js不熟悉,对HTML5也只是知道个名称而已,css就更不会了。感觉有点班门弄斧的味道,让各位大虾,大牛们见笑了。之所以要做这个游戏,源于自己一直想做游戏软件,之所以采用js是因为方便,不用安装什么编译器,用editplus直接写,用浏览器运行就OK了(不喜欢太复杂的东东)。代码一次发不完,只好分开发了,正好重新回顾一下,这些天每天都写一点,写着写着就写完了........
(PS:没有做过浏览器兼容测试,我自己是在chrome上运行的,同事说ff也可以)。

最开始,我是看到网上说canvas标签是能做动画,我本来想做一个网页3D的东东,但是资料显示canvas目前就只能做2D的,虽然也搜索到了老外做的3D的例子,但都是伪3D的,而且设计到算法也是很复杂,就放弃了。然后买了一本书,看看用canvas能搞些啥,看了几天也就是画一些基本图形,其中我最喜欢画矩形了,因为简单啊。画圆的话书里面讲的是什么贝塞尔曲线,彻底蒙鸟。然后画着画着,就想把他做成一个类,于是乎,这个游戏的第一个类Rect就诞生了,当然最初没有这么多东西,都是后面慢慢加上去的。

再然后,我就用了for循环去画一些小矩形做颜色渐变的练习,当画满整个canvas标签时,我发现这个有点像地图了,那一个个小矩形就想地图上的坐标一样。发现这一点很兴奋,立刻想到了贪吃蛇游戏(那个游戏只实现了基本功能,连计分功能都没有,不算完整就不发了),于是地图类map就这样被设计出来了,在写俄罗斯方块的时候又增加了刷新refresh功能。

接着就开始着手俄罗斯方块类的设计,这个花了几天时间因为那几天在看软件设计模式中的简单工厂模式,考虑到扩展性,如果多加几种俄罗斯方块,代码怎么设计才改动最少。最终得出的结论是用继承,也就是说把左移,右移,旋转等公用方法写在父类里面,多增加一种方块的话我只需要增加一个类定义出它的形状就可以了。

另一个花时间比较多的是旋转的算法,网上大致有两种算法,一种是用数组画出所有选择后的图形,直接调用,一种是根据坐标旋转。前者简单,但是麻烦。后者的算法我没看懂。最后通过将各种俄罗斯方块(出了“田”和竖条)都画到一个3 * 3的地图里,我打算利用矩阵旋转的方法来实现,还是因为简单啊,呵呵。公式是这样的:a[j][2 - i] = a[i][j] 就能把一个二维矩阵旋转一下,而俄罗斯方块由四个Rect组成,每个Rect的x,y就相当于i,j了,x = y; y = 2 - x 就行了,而且把第一个Rect定义为中心的话,只需要计算出另外3个Rect的坐标即可。但是在实际测试中,却失败了,旋转后各个Rect就飞了。原来,矩阵里面的i,j都是从0,0开始的,而我的俄罗斯方块随着下降左移右移,坐标早就不知道偏移到哪去了,这个使我郁闷了很久,不过后来一想,先按照矩阵旋转的算法算完之后,再加上偏移量就可以了哇。通过中心的那个Rect的坐标计算出偏移量也是很方便的。最后写完代码发现,核心代码也就10来行。不过竖条不在3*3范围内,但是我那个算法也能把竖条旋转了,这个是我没想到的,感觉很意外。

//用于画地图的方块类
function Rect(x,y,size,context) {
this.x = x;
this.y = y;
this.size = size;
//是否着色的标志,由游戏控制类来改写
this.issetcolor = false;
this.color = "";
this.context = context;
}
//画边框,用于画地图
Rect.prototype.strokerect = function (sColor) {
this.context.strokeStyle = sColor;
this.context.strokeRect(this.x * this.size,this.y * this.size,this.size,this.size);
}
//填充颜色
Rect.prototype.fillrect = function (sColor) {
this.context.fillStyle = sColor;
this.context.fillRect(this.x * this.size + 1,this.y * this.size + 1,this.size - 2, this.size - 2);
this.color = sColor;
}
//清除颜色
Rect.prototype.clearrect = function () {
this.context.clearRect(this.x * this.size + 1,this.y * this.size + 1,this.size - 2,this.size - 2);
}
//地图类
function map(RectSize,color,canvas) {
this.width = canvas.width;
this.height = canvas.height;
this.RectSize = RectSize; //方块边长
this.backgroundcolor = color;
this.aMapArray = null;
this.ctx = canvas.getContext("2d");
this.born();
}
//地图由若干只有边框的方块组成
map.prototype.born = function () {
var i; var j;
var xCount;
var yCount;
xCount = this.width / this.RectSize;
yCount = this.height / this.RectSize;
this.aMapArray = new Array();
for (i = 0; i < xCount; i++) {
this.aMapArray[i] = new Array();
for (j = 0; j < yCount; j++) {
this.aMapArray[i][j] = new Rect(i,j,this.RectSize,this.ctx);
this.aMapArray[i][j].strokerect(this.backgroundcolor);
this.aMapArray[i][j].fillrect(this.backgroundcolor);
}
}
}
//地图刷新
map.prototype.refresh = function () {
var xCount;
var yCount;
xCount = this.width / this.RectSize;
yCount = this.height / this.RectSize;
for (var i = 0; i < xCount; i++) {
for (var j = 0; j < yCount; j++) {
this.aMapArray[i][j].fillrect("White");
this.aMapArray[i][j].fillrect(this.backgroundcolor);
this.aMapArray[i][j].issetcolor = false;
}
}
}
//获取地图上的方块
map.prototype.getrect = function (x,y) {
try {
return this.aMapArray[x][y];
}
catch (err) {
return null;
}
}
//俄罗斯方块父类
function tetris(x,y,size,scolor) {
//出生坐标
this.born_x = x;
this.born_y = y;
//方块边长
this.rectsize = size;
//存放方块的数组
this.rectarray = new Array();
//方块的颜色
this.color = scolor;
//方块名称
this.name = "";
//属于哪个地图
this.map = map;
}
tetris.prototype.setbornxy = function (x,y) {
this.born_x = x;
this.born_y = y;
}
//显示方块
tetris.prototype.show = function () {
var iCount = this.rectarray.length;
for (var i = 0; i < iCount; i++) {
this.rectarray[i].fillrect(this.color);
}
}
//清除方块
tetris.prototype.clear = function () {
var iCount = this.rectarray.length;
for (var i = 0; i < iCount; i++) {
//this.rectarray[i].clearrect();
this.rectarray[i].fillrect("Black");
}
}
//方块的旋转
tetris.prototype.trun = function () {
var iCount = this.rectarray.length;
var iTemp_x, iTemp_y, offset_x, offset_y;
/*
以rectarray的第一个方块为中心,
在定义方块时,需要将这个方块设置为中心
由于是按照中心方块来移动,所以中心方块坐标不用变。
*/
if (this.name != "D") {//我实在是找不出哪个字母比D更像“田”了
this.clear();
//取得方块所在矩阵偏移原点(0,0)的偏移量
offset_x = this.rectarray[0].x - 1;
offset_y = this.rectarray[0].y - 1;
for (var i = 1; i < iCount; i++) {
//方块坐标减去偏移量
iTemp_x = this.rectarray[i].x - offset_x;
iTemp_y = this.rectarray[i].y - offset_y;
/*
以原点坐标做矩阵旋转运算 参考公式 array[j][2 - i] = array[i][j]
逆时针旋转
计算完后,再加上偏移量
*/
this.rectarray[i].x = iTemp_y + offset_x;
this.rectarray[i].y = 2 - iTemp_x + offset_y;
}
this.show();
}
}
//方块左移
tetris.prototype.move_left = function () {
/*
左移就是x坐标减1
*/
var iCount = this.rectarray.length;
this.clear();
for (var i = 0; i < iCount; i++) {
this.rectarray[i].x = this.rectarray[i].x - 1;
}
this.show();
}
//方块右移
tetris.prototype.move_right = function (context) {
/*
右移就是x坐标加1
*/
var iCount = this.rectarray.length;
this.clear();
for (var i = 0; i < iCount; i++) {
this.rectarray[i].x = this.rectarray[i].x + 1;
}
this.show();
}
//方块下移
tetris.prototype.move_down = function (context) {
/*
下移就是y坐标加1
*/
var iCount = this.rectarray.length;
this.clear();
for (var i = 0; i < iCount; i++) {
this.rectarray[i].y = this.rectarray[i].y + 1;
}
this.show();
}
...全文
589 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
寒似火 2012-03-07
  • 打赏
  • 举报
回复
楼主不错,得多向LZ学习学习了
大宝贱 2012-03-06
  • 打赏
  • 举报
回复
100多行的才能被推荐,看来我得回去再好好学习一下了````
夜色镇歌 2012-03-05
  • 打赏
  • 举报
回复
aihua17 2012-03-04
  • 打赏
  • 举报
回复
这么牛,向LZ学习
大宝贱 2012-03-03
  • 打赏
  • 举报
回复
31楼怎么没了?
abirdtofly 2012-03-02
  • 打赏
  • 举报
回复
喜阳阳 2012-03-02
  • 打赏
  • 举报
回复
温柔哥 2012-03-02
  • 打赏
  • 举报
回复
可以在图片(每一个小格子)中搞点绣花或者 凹凸感 ,再搞些过关画面什么的。就很完美了。 。
大宝贱 2012-03-02
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 lihanbing 的回复:]

太多行了,现在不都流行100多行的吗
[/Quote]
算上html代码大概700多行,注释也蛮多的,记录了一些当时的思路,怕以后看不懂.
我做这个不是赶流行,初学js还没有那么强的能力用100多行就能写出来.
只是学了这么久的编程,一直想自己写个完整的小游戏.
2是把学习到的设计模式和js练习一下.
平时工作不是用js的,都是闲时看看资料,做做练习,不知道能不能坚持下去```
暗夜螃蟹 2012-03-02
  • 打赏
  • 举报
回复
有开始就是进步,接分
shexiaofan 2012-03-02
  • 打赏
  • 举报
回复
厉害a ~~~~我是菜鸟刚刚学习JS
lihanbing 2012-03-02
  • 打赏
  • 举报
回复
太多行了,现在不都流行100多行的吗
h123hu 2012-03-02
  • 打赏
  • 举报
回复
玩了一下很牛叉啊,偶才刚刚起步,还得加把劲啊
血痕123456 2012-03-02
  • 打赏
  • 举报
回复
这个我才开始学,现在还做不了这种效果··········
Acesidonu 2012-03-01
  • 打赏
  • 举报
回复
十分强大
大宝贱 2012-03-01
  • 打赏
  • 举报
回复
18楼怎么没了````
tzg157 2012-03-01
  • 打赏
  • 举报
回复
感谢楼主共享。
likeajin 2012-03-01
  • 打赏
  • 举报
回复
同上~~
大宝贱 2012-03-01
  • 打赏
  • 举报
回复
大宝贱 2012-02-13
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 ywtywt337 的回复:]

别忘了给分
[/Quote]
均分。感觉你做的要详细一些,还统计了那些方块出现了几次
加载更多回复(15)

87,910

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧