俄罗斯方块代码说明

/**
名称:Javascript 俄罗斯方块!
作者:Gloot
邮箱:glootz@gmail.com
QQ:345268267
网站:http://www.cnblogs.com/editor/
*/ OLSFK = {};

本俄罗斯方块代码采用 JavaScript 脚本代码写成,简单易懂;

全代码采用静态类及静态变量成员组成;

全脚本通过实现代码全局配置 OLSFK.Options = {...}

定义方块起始坐标及定义各自的旋转点;

从初始化俄罗斯方块界面开始,再监听键盘事件;以及左右,向下及旋转动作判断,重新渲染方块位置;

判断是否消行,以及相应的加级判断,执行速度,加分操作来执行;

最后以判断是否当前级别大于所定义的最大级别来判断是否结束;

代码说明讲解

OLSFK.Options = { //相关参数
width:12,//界面横向方块数
height:20,//界面纵向方块数
boxWidth : '16px',
curLevel:1,
speed : 1000, //setInterval,setTimeout
direct : { //可以设定是A S D W, 还是← ↓ →
Down: 40 , /*run speed*/
Left: 37,
Right: 39,
Rotate: 38
},
Move:true,//是否正在移动
Eventing:false,
Levels: {
1:1000,
2:900,
3:800,
4:700,
5:600,
6:500,
7:400,
8:300,
9:200,
10:100
},
curBlock:4, //当前移动的图形名称
nextBlock:0,
GampMap:new Object(),
Timer:null,
deline:0,
Score:0,
Deling:false,
Start:false,
lineNum:10, //删除几行了,加级
ScoreNum:40 //消一行加分
}

direct 表示 使用键盘方位键来操作方块的移动方向;

使用哪种方向键按自由喜欢配置,比如字母键的A, S, D, W; 或右边小数字键盘的数字键各自的键盘编码;

比如 上(旋转)、下、左、右 方向键的编码分别为:38、40、37、39;

Levels:表示级别配置,本配置共分为10级,每个级别所对应的下落速度,即定时执行间隔;

curBlock:表示当前活动的方块;

nextBlock:表示接下来执行的方块索引,并显示界面右上角的预览框中;

GampMap:用于保存在根据定义行列数形成的游戏表格中保存每个格的数据信息;

OLSFK.Options.GampMap[x+'_'+y] = 0;

对象表格为: id: "box_"+x+"_"+y;

初始化数据为 ‘0’;  表示该表格还未占用;当有占用时,设置值为 ‘1’;

Timer:为定时执行器;setTimeout 定时执行方块下落的的频率;定时时间越小,速度越快;

Deling:当正在执行消行操作时,下次暂不显示并下落;

lineNum:表示消超过 10 行,加一级;

ScoreNum:表示每消一行所加的分数;

OLSFK.ReItems = function (cur){ //key旋转点

    switch (cur)
{
case 1:
OLSFK.Items[1] = {//长块 LongBlock
1:{x:4,y:0},
2:{x:5,y:0},
3:{x:6,y:0},
4:{x:7,y:0},
5:{x:5,y:0} //旋转点
};
break;
//....
}
}

该方法用于恢复方块的初始设置;

OLSFK.Next = { //key旋转点
//长块 LongBlock
1: {
1:{x:0,y:1},
2:{x:1,y:1},
3:{x:2,y:1},
4:{x:3,y:1}
},
//...
}

为不了不与游戏方块的设置冲突,独立出来下次随机方块的对象配置;

OLSFK.Items = { //key旋转点
//长块 LongBlock
1: {
1:{x:4,y:0},
2:{x:5,y:0},
3:{x:6,y:0},
4:{x:7,y:0},
5:{x:5,y:0}
},
//方块Box
2: {
1:{x:4,y:0},
2:{x:5,y:0},
3:{x:4,y:1},
4:{x:5,y:1},
5:{x:0,y:0}
},
//凸块 TuBlock
3: {
1:{x:4,y:1},
2:{x:5,y:0},
3:{x:5,y:1},
4:{x:6,y:1},
5:{x:5,y:1}
},
//L块 LBlock
4: {
1:{x:5,y:0},
2:{x:5,y:1},
3:{x:5,y:2},
4:{x:6,y:2},
5:{x:5,y:2}
},
5: { //反向L块 FLBlock
1:{x:5,y:2},
2:{x:6,y:2},
3:{x:6,y:1},
4:{x:6,y:0},
5:{x:6,y:2}
},
//Z块 ZBlock
6: {
1:{x:4,y:0},
2:{x:5,y:0},
3:{x:5,y:1},
4:{x:6,y:1},
5:{x:5,y:0}
},
7: {//反向Z块 FZBlock
1:{x:4,y:1},
2:{x:5,y:1},
3:{x:5,y:0},
4:{x:6,y:0},
5:{x:5,y:1}
}
}

方块共分为:长条块,方块,凸块(T块),L块,反L块,Z块,反Z块几种;

共7种方块,以1,2,3,4,5,6,7 索引键表示,方块是四个小块组成,每块都有各自的坐标,1-4表示组成该块的初始坐标位置,5表示旋转点;

OLSFK.Init = function() { //初始化界面
//...
}

俄罗斯方块的界面初始化方法;将在 window.onload 中调用执行;

var w = OLSFK.Options.width;
var h = OLSFK.Options.height;
var total = w * h; var x=0,y=0;
for (var i=0; i<total; i++)
{ OLSFK.Options.GampMap[x+'_'+y] = 0; Lib.Tag('SPAN',{id:"box_"+x+"_"+y,name:"cbox",style:{
width:OLSFK.Options.boxWidth,
height:OLSFK.Options.boxWidth,
border:"2px outset #669",
background:"#ddd",
float:"left",
overflow:"hidden"
},innerHTML:"&nbsp;",className:"cssbox"},back); var end = i + 1;
x++;
if (end >= w && end % w == 0)
{
x=0;
y++;
Lib.Tag('DIV',{style:{
clear:"both"
}},back);
} }

通过设置的 Options.width, Options.height 列数与行数,以及设置的小方格宽度,初始化了一个宽:Options.width列,高为 Options.height 的表格界面出来;

Lib.Tag 用于创建标签对象;

Lib.Tag = function(TAG,json,pnode) {
//...
}

TAG为标签名,比如: div, span 等;

json为设置标签样式 style;

pnode 是该创建所在的父容器;

OLSFK.Init = function() {} 还创建主游戏区域旁边的下次随机方块预览区,当前级别,及分数,以及操作“开始”,“暂停”按钮等;

游戏初始入口点

window.onload = function() {
if (window.isIE)
{
document.attachEvent("onkeydown",function(e) {
if (OLSFK.Options.Start)
{
var E = OLSFK.KeyCode();
OLSFK.EventFunc(E);
} }); document.attachEvent("onkeyup",function(e) {
if (!OLSFK.Options.Move && OLSFK.Options.Start)
{
OLSFK.Options.Move = true;
OLSFK.Options.Eventing = false; OLSFK.Options.Timer = setTimeout(function() {
OLSFK.play();
}, OLSFK.Options.Levels[OLSFK.Options.curLevel]);
}
});
} else {
document.addEventListener("keydown",function(e) { if (OLSFK.Options.Start)
{
var E = OLSFK.KeyCode();
OLSFK.EventFunc(E);
} },false); document.addEventListener("keyup",function(e) {
if (!OLSFK.Options.Move && OLSFK.Options.Start)
{
OLSFK.Options.Move = true;
OLSFK.Options.Eventing = false; OLSFK.Options.Timer = setTimeout(function() {
OLSFK.play();
}, OLSFK.Options.Levels[OLSFK.Options.curLevel]);
}
},false);
}
OLSFK.Init();
}

主要是监听键盘事件,根据 键盘事件 返回的按钮编码与 OLSFK.Options.direct 设置方向键匹配来操作方块的移动,旋转等;

keydown 用于操作下落方块的移动方向,旋转等;并重新绘制方块位置;

keyup 后继续按本级速度向下落;

OLSFK.Options.Levels[OLSFK.Options.curLevel]

表示当前级别对应的速度,即定时器间隔执行时间(毫秒);

OLSFK.EventFunc = function(code) {
switch (code)
{
case OLSFK.Options.direct.Left: //LEFT
if (!OLSFK.Options.Deling)
{
clearTimeout(OLSFK.Options.Timer);
OLSFK.Options.Eventing = true;
OLSFK.Options.Move = false;
OLSFK.Left();
} break;
//...
}
}

该方法是 监听 keydown 事件执行的动作;code 为按键 编码;

当判断未在消行动作时,清除定时器,OLSFK.Options.Eventing 设置为事件中 true,OLSFK.Options.Move 为 false 表示停止移动;

进入 向左移动方法 OLSFK.Left();

OLSFK.Left = function() {
var block = OLSFK.Items[OLSFK.Options.curBlock]; if (block)
{
var flag = true;
for (var i=1; i<=4; i++)
{
var x = block[i].x;
var y = block[i].y; if (x-1 < 0)
{
flag = false;
break;
} if (OLSFK.Options.GampMap[(x-1)+'_'+y] == 1 && !OLSFK.isMe(x-1,y))
{
flag = false;
break;
}
} if (flag)
{
for (var i=1; i<=4; i++) //清除图形
{
var itm = block[i];
var box = Lib.Getid('box_'+itm.x+'_'+itm.y); box.style.background = '#ddd';
OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;
} for (var i=1; i<=5; i++)
{
var x = block[i].x;
var y = block[i].y; OLSFK.Items[OLSFK.Options.curBlock][i] = {x:(x-1),y:y};
} OLSFK.draw();
}
}
}

var block = OLSFK.Items[OLSFK.Options.curBlock]; 表示获取当前移动方块;

if (OLSFK.Options.GampMap[(x-1)+'_'+y] == 1 && !OLSFK.isMe(x-1,y))
{
flag = false;
break;
}

判断该方块四个小方块左边是否有被占用的方块,也即: OLSFK.Options.GampMap[(x-1)+'_'+y] 为 1; 并且该位置块不属于方块自己的;

当左边方向无占用格时,清除当前方块四个小方块位置,重新绘制方块新坐标位置;并重置 相应的 OLSFK.Options.GameMap [x+y] 相应格的值;

当按钮 keyup 时,继承正常向下落;

OLSFK.isMe 代码:

OLSFK.isMe = function(x,y) {
var block = OLSFK.Items[OLSFK.Options.curBlock]; if (block)
{
for (var i=1; i<=4; i++)
{
if (block[i].x == x && block[i].y == y)
{
return true;
}
}
} return false;
}

即指定的 x,y (参数值) 是否还在当前方块四个坐标内;

OLSFK.Right () 与 Left() 一样;

旋转方块代码;

OLSFK.Rotate = function() {
var block = OLSFK.Items[OLSFK.Options.curBlock]; if (block)
{
var flag = true; var R = block[5];
for (var i=1; i<=4; i++)
{
var x = block[i].x;
var y = block[i].y; if (R.x == x && R.y == y)
{ } else {
var nson = new Object(); nson.x = R.x + R.y - y;
nson.y = R.y - R.x + x; if ( nson.x < 0 || nson.y < 0 || nson.x >= OLSFK.Options.width || nson.y >= OLSFK.Options.height )
{
flag = false;
break;
} if (OLSFK.Options.GampMap[nson.x+'_'+nson.y] == 1 && !OLSFK.isMe(nson.x,nson.y))
{
flag = false;
break;
}
}
} if (flag)
{
for (var i=1; i<=4; i++) //清除图形
{
var itm = block[i];
var box = Lib.Getid('box_'+itm.x+'_'+itm.y); box.style.background = '#ddd';
OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;
} var Pnt = 1; for (var i=1; i<=4; i++)
{
var x = block[i].x;
var y = block[i].y; if (R.x == x && R.y == y)
{
Pnt = i;
} else {
var nson = new Object(); nson.x = R.x + R.y - y;
nson.y = R.y - R.x + x;
OLSFK.Items[OLSFK.Options.curBlock][i] = {x:nson.x,y:nson.y};
}
} OLSFK.Items[OLSFK.Options.curBlock][5] = OLSFK.Items[OLSFK.Options.curBlock][Pnt]; OLSFK.draw();
}
}
}

var R = block[5]; 就是获取旋转点;

就开始对方块四个小块以旋转点为中心,逆时针旋转(并不全是 90 度);当当前块不为旋转点时,旋转公式;

var nson = new Object();

nson.x = R.x + R.y - y;
nson.y = R.y - R.x + x;

这个公式要这样看;

ResultX = RotateX + (RotateY - CurrentY);
ResultY = RotateY - (RotateX - CurrentX); //Y的偏移量,就是X的增加值;
//反之同

当旋转四周都无占用物时;清除当前图形,重绘旋转后的图形位置;

重置 OLSFK.Options.GampMap[itm.x+'_'+itm.y] 各个方块的占用值;

OLSFK.Random = function() {

    if (OLSFK.Options.nextBlock != 0)
{
OLSFK.Options.curBlock = OLSFK.Options.nextBlock; var block = OLSFK.Next[OLSFK.Options.nextBlock];
if (block)
{
for (var i=1; i<=4; i++)
{
var itm = block[i];
var box = Lib.Getid('cur_'+itm.x+'_'+itm.y); box.style.background = '#ddd';
//OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;
}
}
} else {
OLSFK.Options.curBlock = Math.floor(Math.random() * 7 + 1);
}
OLSFK.Options.nextBlock = Math.floor(Math.random() * 7 + 1); OLSFK.drawNext();
}

随机生成下次预下落的方块;并显示到右上角的预览表格里;

OLSFK.play = function(speed) {
var block = OLSFK.Items[OLSFK.Options.curBlock]; if (block && OLSFK.Options.Move)
{ var flag = true;
for (var i=1; i<=4; i++)
{
var x = block[i].x;
var y = block[i].y; if (y+1 >= OLSFK.Options.height)
{
flag = false;
break;
} if (OLSFK.Options.GampMap[x+'_'+(y+1)] == 1 && !OLSFK.isMe(x,y+1))
{
flag = false;
break;
}
} if (flag)
{
for (var i=1; i<=4; i++) //清除图形
{
var itm = block[i];
var box = Lib.Getid('box_'+itm.x+'_'+itm.y); box.style.background = '#ddd';
OLSFK.Options.GampMap[itm.x+'_'+itm.y] = 0;
} for (var i=1; i<=5; i++)
{
var x = block[i].x;
var y = block[i].y; OLSFK.Items[OLSFK.Options.curBlock][i] = {x:x,y:(y+1)};
}
OLSFK.draw(); var S = OLSFK.Options.Levels[OLSFK.Options.curLevel];
if (speed)
{
S = 50;
}
OLSFK.Options.Timer = setTimeout(function() {
OLSFK.play();
}, S);
} else {
OLSFK.ReItems(OLSFK.Options.curBlock);
OLSFK.newRun();
}
}
}

OLSFK.play 正常下落的方法,也得判断下落一格是否有被占用的格,如果没有,清除当前方块,绘制方块新位置;

当方块不能再下落时(flag = false),重置当前方块坐标配置; OLSFK.ReItems(OLSFK.Options.curBlock);

进入 OLSFK.newRun(); 新下落方块下落过程准备;

OLSFK.newRun = function() {

    clearTimeout(OLSFK.Options.Timer);
OLSFK.DelFunc();
if (OLSFK.Options.deline >= 10)
{
OLSFK.Options.deline = 0;
OLSFK.Options.curLevel ++;
OLSFK.Element.CurLevel.setHTML("级:"+OLSFK.Options.curLevel);
}
OLSFK.Element.Score.setHTML("分:"+OLSFK.Options.Score); if (OLSFK.Options.curLevel <= OLSFK.Options.lineNum)
{
OLSFK.Random();
//判断是否结束
OLSFK.ChkEnd();
} else {
OLSFK.Options.Move = false;
OLSFK.Options.Start = false;
OLSFK.Options.Eventing = false;
OLSFK.Options.Deling = false;
Lib.Getid('spn').innerHTML = 'Game Is Over! You Win the Game!'; Lib.Getid('dobtn').innerHTML = ' 开始 ';
} }

当下落结束时,清除定时器,暂停新方块下落,检测是否有可消除的行;减了多少行;

每减去一行 加分 OLSFK.Options.Score += OLSFK.Options.ScoreNum;

这个方法在 :

OLSFK.DelFunc = function() {
OLSFK.Options.Deling = true;
OLSFK.Options.Move = false;
OLSFK.Options.Eventing = false;
var Fn = 0;
for (var i=OLSFK.Options.height-1; i>=0; i--)
{
Fn = 0;
for (var j=0; j<OLSFK.Options.width; j++)
{
if (OLSFK.Options.GampMap[j+'_'+i] == 1)
{
Fn++;
}
} if (Fn == OLSFK.Options.width)
{
OLSFK.Options.deline ++;
OLSFK.Options.Score += OLSFK.Options.ScoreNum;
OLSFK.DelLine(i);
i++;
}
}
OLSFK.Options.Deling = false;
OLSFK.Options.Move = true;
OLSFK.Options.Eventing = true;
}

中执行;

减完一行,就重置该行以上所有行往下降一行;并重置 :

OLSFK.Options.GampMap[x+'_'+y] = OLSFK.Options.GampMap[x+'_'+(y-1)];

该减行为上行的数据;

if (Fn == OLSFK.Options.width)
{
OLSFK.Options.deline ++;
OLSFK.Options.Score += OLSFK.Options.ScoreNum;
OLSFK.DelLine(i);
i++;
}

该判断表示该行上所有格都被占用到;

回到 newRun 上,当判断消行超过几行时,即加级;

if (OLSFK.Options.curLevel <= OLSFK.Options.lineNum)
{
OLSFK.Random();
//判断是否结束
OLSFK.ChkEnd();
}

如果级数小于配置的总级数,则进入 OLSFK.random();

设置当前下落方块,并随机生成下次下落方块并预览右上角表格上;

OLSFK.ChkEnd = function() {
var block = OLSFK.Items[OLSFK.Options.curBlock]; if (block && OLSFK.Options.Move)
{ var flag = true;
for (var i=1; i<=4; i++)
{
var x = block[i].x;
var y = block[i].y; if (OLSFK.Options.GampMap[x+'_'+y] == 1)
{
flag = false;
break;
}
}
} if (flag )
{
OLSFK.draw(); //定时往下掉
OLSFK.Options.Timer = setTimeout(function() {
OLSFK.play();
}, OLSFK.Options.Levels[OLSFK.Options.curLevel]);
} else {
OLSFK.Options.Move = false;
OLSFK.Options.Start = false;
OLSFK.Options.Eventing = false;
OLSFK.Options.Deling = false;
Lib.Getid('spn').innerHTML = 'Game Is Over'; Lib.Getid('dobtn').innerHTML = ' 开始 ';
}
}

当当前下落的方块进入表格上有被占用的格子,即被卡住,游戏结束;

反之 则 setTimeout 开始新方块的下落动作;

其他方法说明

OLSFK.Event = function() {
if (window.isIE)
return window.event;
func = OLSFK.Event.caller; while(func!=null)
{
var arg0=func.arguments[0];
if(arg0)
{
return arg0;
}
func=func.caller;
}
return null;
} OLSFK.KeyCode = function() {
return OLSFK.Event().keyCode || OLSFK.Event().which;
}

OLSFK.Event = function();

这是一种获取当前事件的方法,可以比较兼容获取当前的事件;

俄罗斯方块 JavaScript 代码

http://files.cnblogs.com/editor/OLSFK.rar

Javascript 俄罗斯方块 游戏代码解释!的更多相关文章

  1. 经典 HTML5 & Javascript 俄罗斯方块游戏

    Blockrain.js 是一个使用 HTML5 & JavaScript 开发的经典俄罗斯方块游戏.只需要复制和粘贴一段代码就可以玩起来了.最重要的是,它是响应式的,无论你的显示屏多么宽都能 ...

  2. java俄罗斯方块游戏代码

    java俄罗斯方块游戏代码: package com; import java.awt.Color; import java.awt.Graphics; import java.awt.event.K ...

  3. javascript俄罗斯方块游戏

    在线试玩:http://keleyi.com/game/5/ 操作指南:键盘方向键←→控制左右移动,↑键变形,↓键快速下落. 别看这段js代码只有短短的100多行,效果却非常不错,用键盘的方向键操作, ...

  4. C++编写简单的俄罗斯方块游戏

    代码地址如下:http://www.demodashi.com/demo/14593.html C++编写简单的俄罗斯方块游戏 使用C++编写一个简单的俄罗斯方块游戏. 1 环境要求 使用C++图形库 ...

  5. 教你看懂网上流传的60行JavaScript代码俄罗斯方块游戏

    早就听说网上有人仅仅用60行JavaScript代码写出了一个俄罗斯方块游戏,最近看了看,今天在这篇文章里面我把我做的分析整理一下(主要是以注释的形式). 我用C写一个功能基本齐全的俄罗斯方块的话,大 ...

  6. 俄罗斯方块游戏JavaScript代码

    JavaScript代码俄罗斯方块游戏 早就听说网上有人仅仅用60行JavaScript代码写出了一个俄罗斯方块游戏,最近看了看,今天在这篇文章里面我把我做的分析整理一下(主要是以注释的形式). 我用 ...

  7. 分享:使用 TypeScript 编写的 JavaScript 游戏代码

    <上篇博客>我写出了我一直期望的 JavaScript 大型程序的开发模式,以及 TS(TypeScript) 的一些优势.博客完成之后,我又花了一天时间试用 TS,用它来重构之前编写的一 ...

  8. javascript代码解释执行过程

    javascript是由浏览器解释执行的脚本语言,不同于java c,需要先编译后运行,javascript 由浏览器js解释器进行解释执行,总的过程分为两大块,预编译期和执行期 下面的几个demo解 ...

  9. 使用C#重写网上的60行 Javascript 俄罗斯方块源码 (带注释)

    在很久很久以前,就已经看过 60行Js的俄罗斯方块源码.无奈当时能力不够看明白,当时觉得就是个神作. 现在总算有空再看了,顺便用c#实现一遍(超过60行),顺道熟悉下Js API. 网上其他博客也有分 ...

随机推荐

  1. stm32定时器实现60秒定时秒表

    #include "led.h" #include "delay.h" #include "key.h" #include "sy ...

  2. Xcode 6、7 打包

    从 Xcode 6 开始,打包需要开发者帐号添加到授权帐号列表里. 现实情况是作为公司开发工作者,很少能获此殊荣. 解决之道: 用 Xcode 6/7 照常打包,生成 *.xcarchive 文件,然 ...

  3. [HTML]输入框被限制输入某些类型数据

    ENTER键可以让光标移到下一个输入框 <input onkeydown="if(event.keyCode==13)event.keyCode=9" > 只能是中文& ...

  4. Dan Zhang - Visual Studio ALM MVP

    I am a Microsoft Certified Partner specialising in .NET solutions, also worked as an ALM consultant. ...

  5. Excellent Articles

    Lisp The roots of lisp Recursive Functions of Symbolic Expressions and Their Computation by Machine, ...

  6. STL 堆

    洛谷P3378 [模板]堆 #include <iostream> #include <cstdio> #include <algorithm> #include ...

  7. python yield from用法

    Reading data from a generator using yield from def reader(): """A generator that fake ...

  8. java中的大数BigInteger

    compareTo比较大小 equals比较是否相等 ,不能用== while(cin.hasNext())//等价于!=EOF n=cin.nextBigInteger();//读入一个大整数 Sy ...

  9. codevs 2894 保留小数

    时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题目描述 Description 给你一个实数,小数点后不超过50位,请你保留到小数点后n位(四舍五入!!!) 输 ...

  10. Highcharts——让你的网页上图表画的飞起

    Highcharts是一款纯javascript编写的图表库,能够很简单便捷的在Web网站或Web应用中添加交互性的图表,Highcharts目前支持直线图.曲线图.面积图.柱状图.饼图.散点图等多达 ...