Javascript 俄罗斯方块 游戏代码解释!
俄罗斯方块代码说明
/**
名称: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:" ",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 俄罗斯方块 游戏代码解释!的更多相关文章
- 经典 HTML5 & Javascript 俄罗斯方块游戏
Blockrain.js 是一个使用 HTML5 & JavaScript 开发的经典俄罗斯方块游戏.只需要复制和粘贴一段代码就可以玩起来了.最重要的是,它是响应式的,无论你的显示屏多么宽都能 ...
- java俄罗斯方块游戏代码
java俄罗斯方块游戏代码: package com; import java.awt.Color; import java.awt.Graphics; import java.awt.event.K ...
- javascript俄罗斯方块游戏
在线试玩:http://keleyi.com/game/5/ 操作指南:键盘方向键←→控制左右移动,↑键变形,↓键快速下落. 别看这段js代码只有短短的100多行,效果却非常不错,用键盘的方向键操作, ...
- C++编写简单的俄罗斯方块游戏
代码地址如下:http://www.demodashi.com/demo/14593.html C++编写简单的俄罗斯方块游戏 使用C++编写一个简单的俄罗斯方块游戏. 1 环境要求 使用C++图形库 ...
- 教你看懂网上流传的60行JavaScript代码俄罗斯方块游戏
早就听说网上有人仅仅用60行JavaScript代码写出了一个俄罗斯方块游戏,最近看了看,今天在这篇文章里面我把我做的分析整理一下(主要是以注释的形式). 我用C写一个功能基本齐全的俄罗斯方块的话,大 ...
- 俄罗斯方块游戏JavaScript代码
JavaScript代码俄罗斯方块游戏 早就听说网上有人仅仅用60行JavaScript代码写出了一个俄罗斯方块游戏,最近看了看,今天在这篇文章里面我把我做的分析整理一下(主要是以注释的形式). 我用 ...
- 分享:使用 TypeScript 编写的 JavaScript 游戏代码
<上篇博客>我写出了我一直期望的 JavaScript 大型程序的开发模式,以及 TS(TypeScript) 的一些优势.博客完成之后,我又花了一天时间试用 TS,用它来重构之前编写的一 ...
- javascript代码解释执行过程
javascript是由浏览器解释执行的脚本语言,不同于java c,需要先编译后运行,javascript 由浏览器js解释器进行解释执行,总的过程分为两大块,预编译期和执行期 下面的几个demo解 ...
- 使用C#重写网上的60行 Javascript 俄罗斯方块源码 (带注释)
在很久很久以前,就已经看过 60行Js的俄罗斯方块源码.无奈当时能力不够看明白,当时觉得就是个神作. 现在总算有空再看了,顺便用c#实现一遍(超过60行),顺道熟悉下Js API. 网上其他博客也有分 ...
随机推荐
- UNIX文件的权限之“设置用户ID位”
用stat函数可以获取一个文件的状态信息,原型是这样的: int stat(const char *path, struct stat *buf); 其中结构体stat的结构: struct stat ...
- Neutron 理解 (8): Neutron 是如何实现虚机防火墙的 [How Neutron Implements Security Group]
学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...
- 图像处理工具V1.0
图像处理工具V1.0(仿彗星图片处理工具.VS2015安装界面)----个人无聊作品 以下是界面: 部分代码一.(摘自网络----加水印代码): public static void ImageWat ...
- Jsp 错题分析
ArrayList删除元素通过RemoveAt(int index)来删除指定索引值的元素 运行时异常都是RuntimeException类及其子类异常,如NullPointerException.I ...
- 第3章 Linux常用命令(2)_权限管理命令
2. 权限管理命令 2.1 改变文件或目录权限:chmod (1)chmod命令 命令名称 chmod(change the permission mode of a file) 命令所在路径 /bi ...
- UNIX系统基本结构
UNIX系统的基本结构如图所示.整个UNIX系统可分为五层:最底层是裸机,即硬件部分:第二层是UNIX的核心,它直接建立在裸机的上面,实现了操作系统重要的功能,如进程管理.存储管理.设备管理.文件管理 ...
- [备份]破解Xamarin
[转]试用了一阵子Mono For Android,今天到期了,,囊中羞涩,只好破解. 说是要在vs2013的英文界面下运行破解包,不知道是真是假,下载并安装了一个. 然后又下载了破解包.是个名为xa ...
- Linux下基于vsftpd搭建ftp服务器
1.先用检查是否已经安装rpm -qa| grep vsftpd2.然后再进行在线安装vsftpd这个服务yum install vsftpd -y3.修改vi /etc/vsftpd/vsftpd. ...
- 关于Oracle AUTONOMOUS TRANSACTION(自治事务)的介绍
AUTONOMOUS TRANSACTION(自治事务)的介绍 在基于低版本的ORACLE做一些项目的过程中,有时会遇到一些头疼的问题,比如想在执行当前一个由多个DML组成的transaction(事 ...
- Spring源码分析——BeanFactory体系之接口详细分析
Spring的BeanFactory的继承体系堪称经典.这是众所周知的!作为Java程序员,不能错过! 前面的博文分析了Spring的Resource资源类Resouce.今天开始分析Spring的I ...