用纯JS做俄罗斯方块 - 简要思路介绍(1)
大家都知道俄罗斯方块是一款大众化的游戏了,我很小的时候就玩过,今年已经25岁了,可以说俄罗斯方块确实是历史悠久,做俄罗斯方块是我上个星期开始的想法。也许是由于自己从来没有写过这种东西吧,所以有生疏。代码的话,只完成了一小部分,大概1/5左右吧。今天还是决定先写一部分思路。
至于俄罗斯方块的话,有很多的难点,如果有JS去写的话,要考虑到碰撞啊,边界啊,下落等问题,本文这些问题大部分不会考虑到,只是提供一部分思路而已,开始已经说了,因为自己还没写完这个游戏,但是又出于想写博客记录,所以才有了这一系列的博客。
回到正题,我们首先想一想,俄罗斯方块需要什么?我做一个简单的归纳。如果我简单点说的话,就是一个俄罗斯方块对象,那么这个对象里又有些什么东西呢?我们可以想象一下,有一个平面直角坐标系,这个平面直角坐标系有X轴,有Y轴,也有“每一等分”的距离(unit),而俄罗斯方块就是一个一个的“格子”,这些格子从某一个地方开始下落,某一个地方停止下落,于是我们就规定了俄罗斯方块的“下落区域”(Area)。但是下落是一个“动作”,所以我们还要有一个类(这里定义为operate),来控制动作的下落。
好了,先就介绍到这里,我们再来做一段代码性质的归纳,表示对上面的代码做一段归纳。
/*俄罗斯方块实体类*/
function Tetris()
{
var self =this; //自身 this.area=null;//区域
this.operate=null; //操作 /*初始化X,Y,单元为5或者20*/
this.x=5;
this.y=5;
this.unit=20; this.running=null; //是否在运行中 //俄罗斯方块实体ID
this.id="tempid"; //开始游戏
this.start=function()
{
this.area=new getArea(this.x,this.y,this.unit,"tempid"); //获得Area对象 ,其中TEMPID是俄罗斯方块实体类ID
this.operate=new OperateTetris(this.area,self); //是否替换俄罗斯方块
if(this.operate.mayPlace())
{
//alert(1);
this.operate.place();
}
} //开始游戏
document.getElementById("startGame").onclick=function(){self.start()};
}
那么,当我们点击StartGame的时候,开始游戏,即运行start()方法。好,我们现在开始考虑Area对象里面到底需要什么东西 function getArea(x,y,unit,id)参数需要带入4个,前面3个刚才已经说了,第四个参数就是Area的ID。我们需要area这个对象,所以通过HTML代码来设置ID。大家玩过俄罗斯方块的都知道,每一次触底,都会新加一个元素,而新的元素是“随机”的,每当一行是满的(这里不考虑颜色不同的情况),就会消掉一行,当然我们一次形成了多行可消掉的方块的时候,那么我们就可以消掉多行。下面的是代码,算是对上面的文字的一个小小的总结,还没有完成的代码。
//获得区域的横坐标和纵坐标
function getArea(x,y,unit,id)
{
this.x=x;
this.y=y;
this.unit=unit; //每个单元的大小,单位为像素
this.el=document.getElementById(id); //得到ID对象 this.board=[]; //面板,即在区域范围内的元素(俄罗斯方块)
//添加元素
this.addElement=function()
{
//得到起始元素的X开始坐标和Y开始坐标的位置(错误)
//得到X坐标的下落次数,和Y轴的左右移动的次数
var xBegin=parseInt(el.offsetLeft/unit);
var yBegin=parseInt(el.offsetTop/unit); if(xBegin>=0&&xBegin<=this.x&&yBegin>=0&&yBegin<=this.y)
{
board[yBegin][xBegin]=el; //确定元素的位置
} } //消掉所有的行
this.removeFullLines=function()
{
var lines=0;
for(var i=this.y-1;y>0;y--)
{
if(this.linesRelated(y))
{
lines++;
this.y++;
}
}
} //和线性有关的东西(判断是否满了)
this.linesRelated=function(y)
{
for(var x=this.x;x>0;x--)
{
this.removeLines(y);
if(this.board[y][x]){return false;} //不明觉厉
} return true;
}; //去掉行
this.removeLines=function(y)
{
for(var x=0;x<this.x;x++)
{
this.el.removeChild(this.board[y][x]);
this.board[y][x]=0;
}
y--;
for(;y>0;y--)
{
/*今天暂时写到这里*/
}
};
}
需要注意的一点是,俄罗斯方块是“二维性质”的,所以我这里定义了一个board类型的二维数组,即board[行][列](board[y][x]).好了,这里我们当然还需要一个类,这个类就是控制元素下落的“动作”的类,那么这个下落“动作“的类里应该有一些什么东西呢?我们需要考虑边界,于是有了(区域),我们要考虑俄罗斯方块于是有了俄罗斯方块对象(tetris),因为方块的种类不同,有各种不同的形状于是我们必须考虑方块的类别(types),还有下一个类别(NEXTTYPE),因为方块有下一个提示;我们需要考虑方块在AREA中的位置于是有了(position),我们需要判断游戏是否暂停于是有了running,当然了,方块下落的速度SPEED肯定也是要考虑到的,如果GAME OVER了那么就要判断游戏是否停止stopped,当然了,方块是一个一个的元素于是我们要考虑elements,当然了,最重要的还是下落(falldown).下面是定义的代码:
var self=this; //当前对象
this.area=area;
this.tetris=tetris; this.types=null; //方块的类型;
this.nextType=null; //下一个类型 //初始化X和Y
this.x=null;
this.y=null;
this.position=0; //初始位置 this.board=[]; //用来填充HTML元素的
this.elements=[]; this.running=null; //是否在运行中
this.stopped=null; //是否停止 this.fallDownId=null; //往下掉落的
this.speed=null; //速度
这么一说有点头晕,我们选一个切入点吧,我们的切入点就是如何构造方块。大家应该知道俄罗斯方块的几种形状吧,比如T形,L形,口形等等,那么我们可以想象一下,把俄罗斯方块定义成一个二维数组,然后有元素的地方为1,没元素的地方为0来构造形状,如下面的代码:
/*方块的组合方式,用数组进行组合(二维数组)
用0,1表示是否有方块存在,如果是0:不存在,1:存在,
以下的逻辑就可以非常的清楚了。*/
this.blockComplex=[
[
[0,0,1],[1,1,1],[0,0,0] //_|
], [
[1,0,0],[1,1,1],[0,0,0] //L
], [
[0,1,0],[1,1,1],[0,0,0] //T
], [
[0,0,0],[1,1,1],[0,0,0] //--
], [
[0,0,0],[0,1,1],[0,1,1] //口
], [
[0,1,1],[0,1,0],[1,1,0] //Z
]
];
好了,形状构造好之后,我们当然需要考虑程序的性能方面的问题,于是我创建了如下的GETTER方法,来判断是游戏是否在运行中等。
/*一连串的GETTER方法
分别是速度,X,Y轴,运行和停止的GETTER方法*/
this.getSpeed=function()
{
return this.speed;
} this.getX=function()
{
return this.x;
} this.getY=function()
{
return this.y;
} this.isRunning=function()
{
return this.running;
} this.isStopped=function()
{
return this.stopped;
}
当然了,我们如果要”重新开始游戏“,肯定是要建立一个方法reset(),说白一点,就是恢复游戏开始的状态。
//重置(初始化)
this.reset=function()
{
this.nextType=random(this.blockComplex.length);
this.types=this.nextType; this.position=0;
this.board=[];
this.elements=[];
this.x=null;
this.y=null; }
如果这个俄罗斯方法触底的话,那么肯定是会触发下一个俄罗斯方块的开始于是我们这里肯定要有一个方法, 内容我还没想好,就给一个架子吧。我直接返回TRUE了。
this.mayPlace=function()
{ return true;
}
下面的是最重要的方法,就是我们的替换方块的方法。先来简单做一个介绍,我也不知道自己能不能讲好,大家想想在一个坐标系中,方块如果下落了,肯定是Y--,毕竟方块是向下方下落的,当然,我们还需要有线条,假设我们一直在堆方块的话,这个线肯定是会增加的,还有我们的方块本身就是DIV,肯定是一个掉落DIV的过程,而这些DIV,肯定是在AREA范围内的。我们不妨想一想,第一步,我们来创建一个空的BOARD,就是面板,然后往这个面板里面填充东西呢?
//创建空对象,即所有的都为0的对象,并返回对象
this.createEmpty=function(x,y)
{
var elements=[];
for(var y2=0;y2<y;y2++)
{ elements.push(new Array()); for(var x2=0;x2<x;x2++)
{
elements[y2].push(0);
} }
return elements;
}
我们如果想下落元素的话,肯定是要知道开始下落的坐标,当然Y轴肯定是0,X轴可以依据自己的喜好来设定。当然了,下落的DIV肯定是属于这个AREA下面的子元素的,所以我们等下肯定要把这个APPENDCHILD到这里面去。下面是代码:
/*替换*/
this.place=function()
{
//初始化
var operate=this.blockComplex[this.types]; //区域开始X轴的位置
var AreaXStartPos=parseInt(this.area.x-operate[0].length); //区域开始Y轴的位置
//var AreaYStartPos=parseInt(this.area.y-operate[0]);
var AreaYStartPos=1; //因为X轴的位置可能变化,而Y轴总是从最上面下来的,所以是1 this.x=AreaXStartPos; //把新的位置赋给X;
this.y=AreaYStartPos; //把新的位置赋给y; //构建空对象,并存入BOARD
/*y:行,x:列*/ //alert(operate[0].length+" "+operate.length);
this.board=this.createEmpty(operate[0].length,operate.length); /*线条,往下掉落,初始化*/
var lines=0;
var foundLines=false; //循环遍历,先遍历行,每一行再来遍历列
for(var yAxis=this.board.length-1;yAxis>=0;yAxis--)
{
for(var xAxis=0;xAxis<=this.blockComplex[yAxis].length;xAxis++)
{
if(this.blockComplex[yAxis][xAxis])
{
var el=document.createElement("div");
el.className="block"+this.types; //确定这个元素的CLASSNAME //确定左边距和上边距
el.style.left=(this.x+xAxis)*this.area.unit+"px";
el.style.top=(this.y+yAxis)*this.area.unit+"px";
this.area.el.appendChild(el); //这个EL去APPEND主要的EL。 this.board[yAxis][xAxis]=el;
this.elements.push(el); //推入elements中 }
} /*个人感觉这个功能应该是加速往下掉落的方法?不明觉厉*/
if(lines)
{
yAxis--;
} if(foundLines)
{
lines++;
} }
需要注意的是,当下一个俄罗斯方块(随机)的形成是随机的,所以我们需要定义一个RANDOM方法。其实每次下落都是一个RESET的循环,只是游戏还没有结束而已。
//随机数,产生1~6的
function random(i)
{
return Math.floor(Math.random()*i);
}
好了,今天只介绍一个思路,当然了,我也没写出来这个游戏,等下一篇出来的时候应该游戏会有一个大的架子了,还有一些代码我都不好意思放出来了,写得太差了。其实这个俄罗斯方块不完全是我自己写的,我也参考了下别人的东西,但不是抄袭,我想通过自己的努力,做一个游戏出来,这是我多年的梦想,努力!
至于全部的代码我就不贴了,因为还没写完,只是对这几天写代码的一个总结而已,高手可以无视我写的代码。
用纯JS做俄罗斯方块 - 简要思路介绍(1)的更多相关文章
- 纯JS实现俄罗斯方块,打造属于你的游戏帝国
纯JS俄罗斯方块,打造属于你的游戏帝国. 本文原始作者博客 http://www.cnblogs.com/toutou 俄罗斯方块(Tetris, 俄文:Тетрис)是一款电视游戏机和掌上游戏机游戏 ...
- [前端 3]纯Js制作俄罗斯方块游戏
导读:在别人文章里看到了,然后写了一遍.结果出错了,然后调出来了,然后理解了一下,加了点注释,有一些想法.忘了在 哪一篇上面看的了,就贴不出来链接地址.原谅.呃,真没自己的东西,权当练打字了吧.其实, ...
- 纯js做的select二级联动
分步阅读 select 联动用到的范围很广,下面介绍一下简单的二级联动 方法/步骤 做一个简单的html页面,用于显示select联动,如图所示: 设置js,点击一级选择项时,创建其下对应的二 ...
- 如何用纯js做一个大富翁游戏
下面这张是效果图: 先立个flag,一个星期内把这个坑填了
- F2工作流引擎之-纯JS Web在线可拖拽的流程设计器(八)
Web纯JS流程设计器无需编程,完全是通过鼠标拖.拉.拽的方式来完成,支持串行.并行.分支.异或分支.M取N路分支.会签.聚合.多重聚合.退回.传阅.转交,都可以非常方便快捷地实现,管理员 ...
- 纯js实现瀑布流布局及ajax动态新增数据
本文用纯js代码手写一个瀑布流网页效果,初步实现一个基本的瀑布流布局,以及滚动到底部后模拟ajax数据加载新图片功能. 缺点: 1. 程序不是响应式,不能实时调整页面宽度: 2. 程序中当新增ajax ...
- 纯JS Web在线可拖拽的流程设计器
F2工作流引擎之-纯JS Web在线可拖拽的流程设计器 Web纯JS流程设计器无需编程,完全是通过鼠标拖.拉.拽的方式来完成,支持串行.并行.分支.异或分支.M取N路分支.会签.聚合.多重聚合.退回. ...
- 纯js实现html转pdf
项目开发中遇到了一个变态需求,需要把一整个页面导出为pdf格式,而且要保留页面上的所有的表格.svg图片和样式.简而言之,就是希望像截图一样,把整个页面截下来,然后保存成pdf.咋不上天呢--查了一下 ...
- Vue.js是什么,vue介绍
Vue.js是什么,vue介绍 Vue.js 是什么Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用. ...
随机推荐
- C#中的委托与事件并存的理由
更多资源:http://denghejun.github.io 问题 有了委托为什么还要有事件? 理论上,事件能完成的事情委托完全可以胜任,但是我们思考的这一方面是功能性,我们必须从他们各自的特点分析 ...
- js原生代码实现轮播图案例
一.轮播图是现在网站网页上最常见的效果之一,对于轮播图的功能,要求不同,效果也不同! 我们见过很多通过不同的方式,实现这一效果,但是有很多比较麻烦,而且不容易理解,兼容性也不好. 在这里分享一下,用j ...
- 启动App的Intent
类似桌面图标打开App的Intent 程序中需要一种通知,点击后的效果需要像点击桌面图标那样: 程序在前台就什么也不干. 程序在后台,就切换到前台. 程序未启动,就启动程序. 点击通知后,通知本身跳转 ...
- 《深入理解Java虚拟机》垃圾收集器
说起垃圾收集(Garbage Collection,GC),大部分人都把这项技术当做Java语言的伴生产物.事实上,GC的历史远比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态 ...
- 剑指Offer面试题:32.数字在排序数组中出现的次数
一.题目:数字在排序数组中出现的次数 题目:统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4. 二.解题思路 2 ...
- Hadoop学习笔记—16.Pig框架学习
一.关于Pig:别以为猪不能干活 1.1 Pig的简介 Pig是一个基于Hadoop的大规模数据分析平台,它提供的SQL-LIKE语言叫Pig Latin,该语言的编译器会把类SQL的数据分析请求转换 ...
- 简单一招实现json数据可视化
开发一个内部功能时碰到的需求,要把json数据在页面上展示出来,平时浏览器会安装jsonView这样的扩展来看json数据,但是程序要用到的话该怎么办呢?今天在网上搜索的时候,发现了这个小技巧,分享一 ...
- WebDriver--简单的元素操作
以登录163邮箱为例,演示以下几个方法的使用 ①switch_to.frame() ②.clear() ③.send_keys() ④.click() ⑤switch_to_default_conte ...
- iOS-网络基础
概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力 ...
- HTTP学习二:Web应用中的HTTP
1 HTTP连接 1.1 TCP连接对性能的影响 TCP三次握手如下图: 如上图,建立一次TCP连接要经过三个步骤.HTTP是建立在TCP之上的,因此TCP连接的性能直接影响HTTP的性能. TCP影 ...