一.简介
俄罗斯方块(Tetris, 俄文:Тетрис)是一款风靡全球的电视游戏机和掌上游戏机游戏,它由俄罗斯人阿列克谢·帕基特诺夫发明,故得此名。俄罗斯方块的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。由于上手简单、老少皆宜,从而家喻户晓,风靡世界。
二.需求分析
(完全按照QQ游戏的制作,如下图:)
三.技术分析与实现
1.方块位置定位
解决方案:建立盒子模型
由于长条的存在,所以建立一个4*4的盒子模型,任何一个方块都会存在该盒子当中,方块的定位就===盒子的定位。
2.颜色状态的生成与保存
随机生成颜色:
functionrandomColor(){
//16进制方式表示颜色0-F
vararrHex=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];
varstrHex="#";
varindex;
for(vari=0;i<6;i++){
//取得0-15之间的随机整数
index=Math.round(Math.random()*15);
strHex+=arrHex[index];
}
returnstrHex;
}
颜色保存:(那一个方块的一种状态做示例)
vardiamonds=newArray();
diamonds[0]={x:appearPosition.position.x+1,y:appearPosition.position.y,diamondColor:color};
diamonds[1]={x:appearPosition.position.x+0,y:appearPosition.position.y+1,diamondColor:color};
diamonds[2]={x:appearPosition.position.x+1,y:appearPosition.position.y+1,diamondColor:color};
diamonds[3]={x:appearPosition.position.x+2,y:appearPosition.position.y+1,diamondColor:color};
所有生成的方块有个diamondColor属性,用于存颜色。appearPosition.position是盒子模型的位置。
3.碰撞检测
碰撞分两种,一种是元素与左右墙壁和底部的碰撞,另外一种是方块与底部方块的接触碰撞
a.元素与左右墙壁和底部的碰撞
a.1元素与底部的碰撞检测
if(diamonds[i].y*height+height>=canvasHeight){
appearPosition.position.x=Math.round(appearPosition.position.x);
appearPosition.position.y=Math.round(appearPosition.position.y);
createElement();
breakTag=1;
}
a.2元素与左右墙壁的碰撞检测
functionreturnRightOrLeft(){
varmax_X=11;
for(i=0;i<diamonds.length;i++){
if(diamonds[i].x>max_X){
max_X=diamonds[i].x;
}
}
if(max_X!=11)appearPosition.position.x=appearPosition.position.x-(max_X-11);
varmin_X=0;
for(i=0;i<diamonds.length;i++){
if(diamonds[i].x<min_X){
min_X=diamonds[i].x;
}
}
if(min_X!=0)appearPosition.position.x=appearPosition.position.x-min_X;
}
b.元素与元素碰撞检测
//判断下面是否有元素
for(j=0;j<bottomElement.length;j++){
if(bottomElement[j].x==diamonds[i].x){
if(Math.round(bottomElement[j].y)==Math.round(diamonds[i].y+1)){
appearPosition.position.x=Math.round(appearPosition.position.x);
appearPosition.position.y=Math.round(appearPosition.position.y);
createElement();
breakTag=1;
}
}
}
//判断arrayOne是否在arrayTwo的右边
functionIsAtRight(arrayOne,arrayTwo){
for(i=0;i<arrayOne.length;i++){
for(j=0;j<arrayTwo.length;j++){
if(Math.round(arrayOne[i].y)==Math.round(arrayTwo[j].y)){
if(arrayTwo[j].x==arrayOne[i].x+1)returntrue;
}
}
}
returnfalse;
}
//判D断arrayOne是否在arrayTwo的左边
functionIsAtLeft(arrayOne,arrayTwo){
for(i=0;i<arrayOne.length;i++){
for(j=0;j<arrayTwo.length;j++){
if(Math.round(arrayOne[i].y)==Math.round(arrayTwo[j].y)){
if(arrayTwo[j].x==arrayOne[i].x-1)returntrue;
}
}
}
returnfalse;
}
4.方块变形
vardirection=0;
if(e.keyCode==87){
direction++;
direction%=4;
}
W键是变形,0123分别代表四种。
如果是长条或者只有两种状态的直接 if (direction % 2 == 0) {},如果是正方块直接忽略direction,因为它就一种形状。
5.键盘捕获(目前WSAD+空格,W是变形,S和空格都是加速,IE9和FF异常,建议在谷歌浏览器下运行)
document.onkeydown=function(e){
if(e.keyCode==65){
for(i=0;i<diamonds.length;i++){
if(diamonds[i].x==0){
return;
}
}
if(IsAtLeft(diamonds,bottomElement)){
return;
}
appearPosition.position.x-=1;
}
if(e.keyCode==87){
direction++;
direction%=4;
}
if(e.keyCode==68){
for(i=0;i<diamonds.length;i++){
if(diamonds[i].x==11){
return;
}
}
if(IsAtRight(diamonds,bottomElement)){
return;
}
appearPosition.position.x+=1;
}
if(e.keyCode==32){
delay=1;
}
if(e.keyCode==83){
delay=1;
}
}
document.onkeyup=function(e){
if(e.keyCode==32){
delay=20;
}
if(e.keyCode==83){
delay=20;
}
}
6.消除加分
//一行满了的话,消除并加分
functionclearUp(){
for(varline=0;line<21;line++){
varcount=0;
for(vari=0;i<bottomElement.length;i++){
if(bottomElement[i].y==line){
count++;
}
}
if(count==12)clearByLineNum(line);
}
//if(count==12)
}
functionclearByLineNum(num){
//以上的元素下降一行
score++;
varcount=0;
for(i=0;i<bottomElement.length;i++){
if(bottomElement[i].y==num){
count++;
}
}
for(varj=0;j<count;j++){
for(vari=0;i<bottomElement.length;i++){
if(bottomElement[i].y==num){
bottomElement.splice(i,1);
break;
}
}
}
for(i=0;i<bottomElement.length;i++){
if(bottomElement[i].y<num){
bottomElement[i].y+=1;
}
}
} 消除加分有一个潜在的逻辑就是,在该行以上的元素的位置下降一个格子。
7.控制核心Jscex Show Time
varJropAsync=eval(pile("async",function(){
varbreakTag=0;
while(true){
color=randomColor();
rectBlockIndex=MR()*7|0;
direction=MR()*3|0;
$await(Jscex.Async.sleep(1));
while(true){
for(i=0;i<diamonds.length;i++){
if(diamonds[i].y*height+height>=525){
appearPosition.position.x=Math.round(appearPosition.position.x);
appearPosition.position.y=Math.round(appearPosition.position.y);
createElement();
breakTag=1;
}
//判D断?下?面?是?否?有D元a素?
for(j=0;j<bottomElement.length;j++){
if(bottomElement[j].x==diamonds[i].x){
if(Math.round(bottomElement[j].y)==Math.round(diamonds[i].y+1)){
appearPosition.position.x=Math.round(appearPosition.position.x);
appearPosition.position.y=Math.round(appearPosition.position.y);
createElement();
breakTag=1;
}
}
}
}
if(breakTag==1){
for(i=0;i<diamonds.length;i++){
//alert(diamonds[i].x+"____"+diamonds[i].y)
bottomElement.push(diamonds[i]);
}
clearUp();
//清?空?下?降μ的?元a素?
diamonds.splice(0,diamonds.length);
appearPosition={position:{x:4,y:-2},direction:0};
breakTag=0;
break;
}
appearPosition.position.y+=step;
draw();
$await(Jscex.Async.sleep(delay));
}
}
}));
这是也整个俄罗斯方块的控制核心,由两个while循环构成,简单大方。
四.在线演示
操作指南:W变形 A左移 D右移 (谷歌浏览器:S加速 空格加速,其他浏览器慎重按此键,该死的浏览器兼容)
火拼俄罗斯
Your browser does not support the canvas element. 得分:0
最新的Jscex 库,请上/JeffreyZhao/jscex或者/projects/jscex/wiki下载吧····
五.同步
本文已同步更新至: