第一次学html、css、javascript,也第一次用他们来写东西——俄罗斯方块。总结了一下
基本流程:
1、画表格
2、创建一个与表格里每个小格对应的标记数组
3、随机生成七种方块
4、键盘触发
5、使方块能按照键盘的按键改变方向、加速等
6、碰撞判断及消行
7、更新分数
8、预告功能
9、其他功能
二、详细设计
1、画表格。
用html定义了两个表格。一个用来显示运动方块,一个用来预告即将生成的方块
2、创建了一个二维数组,初始值为0,填满后复制1。
3、随机生成七种方块
利用Math.floor(Math.random() * 7)生成0~6的随机整数,每个整数对应一种方块。
每个方块由四个小方格组成,每个小方格均有XY坐标。
4、键盘触发
想要接收按键事件, 就要用到document的onkeydown,将写好的方法赋值给onkeydo\wn,
5、改变方向,加速下降等
左右移:比较简单。方格(每个均要判断)的X值不变,改变Y值。看能否左右移。如果能左右移,则改变Y值。同时更新标记数组,重绘表格
下移:分为匀速下移和加速下移,均采用setInterval()定时函数,加速下降则才调用该函数一次。
改变方向:比较复杂。在网上参考了一些转变的方法。算出中位数,然后根据中位数改变各方格的坐标。在转变前还必须判断转变后的坐标是否符合要求
6、碰撞分析及消行
按照碰撞后能否消行分为两种。
不能消行则停止下降,更新标记数组,然后重绘表格,生成新的方块
能消行则更新数组(将上面的数组下移),重绘画布,然后继续生成新的方块
7、更新分数
根据消除的行数来更新分数。同时将其显示出来,原理差不多和显示动态的方块画布一样。
8、其他细节
(1)预示方块,必须在每次生成当前方块前
(2)下落操作比较难。除了需判断碰撞外,考虑消行,更新分数,及继续定时生成新的方框
(3)旋转操作,需先算出中心坐标,然后在根据数学公式转变其坐标,改变前需对其判断是否合法、是否出界
(4)消行操作,纠结的最久的。
一开始,更新数组,清除画布,重绘画布很乱。
(5)浏览器兼容问题(原先IE,chrome都行,就firefox不行)后来用 var event = window.event || e搞定了
三、总结
1、没有在一开始好好安排下时间,需要哪些学哪些知识。致使后来有些乱,进度赶不上
2、语法不熟悉,犯了很多低级错误
3、函数多,有些乱。在开始前最好能把所有的函数列出来,比较清晰
4、写的过程没注意去调试各个函数。也没学好怎样调试。导致后来花很多时间在调试上
附:html文件
<html>
<head>
<title>俄罗斯方块</title>
<style>
#board tr td{
width: 18px;
height:18px;
}
#board1 tr td{
width: 10px;
height:10px;
}
.STYLE1 {
width: 40px;
height: 30px;
font-size: xx-large;
color: #FF0000;
}
.STYLE2 {
color: #000000;
font-size: x-large;
}
.STYLE7 {color: #FF0000}
</style>
</head>
<script type="text/javascript" language="javascript" src="eluosi.js"></script>
<body>
<p align="center" > <input name="button" type="button" onClick="begin(this);" value="begin"/> </p>
<table width="222" align="center" border="1">
<tr >
<td width="214" align="center" bgcolor="#00FF33" class="STYLE1"><span class="STYLE2"></span>score:<span id="score" >0</span> </td>
</tr>
</table>
<br>
<table id="board1" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td colspan="4" bgcolor="#00FF00"><span class="STYLE7">next:</span></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
<br>
<table id="board" align="center" cellpadding="0" cellspacing="0" border="1" style="border-collapse:collapse;">
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</body>
</html>
js文件:
var m=0;
var n=0;
var tbl;
var tbl1;
var status = 0;
var time;
var activeBlock; //活动的方块
var activeBlock1; //预览下个方块
//得分
var score = 0;
var board = new Array(18);
for(var i=0;i<18;i++){
board[i] = new Array(10);
}
for(var i=0;i<18;i++){
for(var j=0; j<10; j++){
board[i][j] = 0;
}
}
//预览方块
activeBlock1=new Array(4);
//预览方块标记数组
var board1 = new Array(4);
for(var i=0;i<4;i++){
board1[i] = new Array(4);
}
for(var i=0;i<4;i++){
for(var j=0; j<4; j++){
board1[i][j] = 0;
}
}
//生成预览方块
function next(){
m=Math.floor(Math.random() * 7);
clearBoard1();
switch(m){
case 0:{
activeBlock1[0]={x:1,y:1};
activeBlock1[1]={x:1,y:2};
activeBlock1[2]={x:2,y:1};
activeBlock1[3]={x:2,y:2};
break;
}
case 1:{
activeBlock1[0]={x:2,y:0};
activeBlock1[1]={x:2,y:1};
activeBlock1[2]={x:2,y:2};
activeBlock1[3]={x:2,y:3};
break;
}
case 2:{
activeBlock1[0]={x:1,y:2};
activeBlock1[1]={x:2,y:1};
activeBlock1[2]={x:2,y:2};
activeBlock1[3]={x:3,y:1};
break;
}
case 3:{
activeBlock1[0]={x:1,y:1};
activeBlock1[1]={x:2,y:1};
activeBlock1[2]={x:2,y:2};
activeBlock1[3]={x:3,y:2};
break;
}
case 4:{
activeBlock1[0]={x:1,y:1};
activeBlock1[1]={x:2,y:1};
activeBlock1[2]={x:2,y:2};
activeBlock1[3]={x:2,y:3};
break;
}
case 5:{
activeBlock1[0]={x:1,y:1};
activeBlock1[1]={x:2,y:1};
activeBlock1[2]={x:3,y:1};
activeBlock1[3]={x:3,y:2};
break;
}
case 6:{
activeBlock1[0]={x:1,y:1};
activeBlock1[1]={x:2,y:0};
activeBlock1[2]={x:2,y:1};
activeBlock1[3]={x:2,y:2};
break;
}
}
updateBoard1();
drawBoard1();
}
//更新预览的标记数组
function updateBoard1(){
for(var i=0; i<4; i++)
{ board1[activeBlock1[i].x][activeBlock1[i].y]=1;}
}
//擦除预览的面板
function clearBoard1(){
for(var i=1; i<4; i++){
for(var j=0; j<4; j++){
board1[i][j]=0;
tbl1.rows[i].cells[j].style.backgroundColor = "white";
}
}
}
//重绘面板
function drawBoard1(){
for(var i=1;i<4;i++){
for(var j=0; j<4; j++){
if(board1[i][j]==1){
tbl1.rows[i].cells[j].style.backgroundColor = "red";
}
}
}
}
//生产七种方块
function createBlock(){
activeBlock=null;
activeBlock=new Array(4);
switch(m){
case 0:{
activeBlock[0]={x:0,y:3};
activeBlock[1]={x:0,y:4};
activeBlock[2]={x:1,y:3};
activeBlock[3]={x:1,y:4};
break;
}
case 1:{
activeBlock[0]={x:0,y:3};
activeBlock[1]={x:0,y:4};
activeBlock[2]={x:0,y:5};
activeBlock[3]={x:0,y:6};
break;
}
case 2:{
activeBlock[0]={x:0,y:4};
activeBlock[1]={x:1,y:3};
activeBlock[2]={x:1,y:4};
activeBlock[3]={x:2,y:3};
break;
}
case 3:{
activeBlock[0]={x:0,y:3};
activeBlock[1]={x:1,y:3};
activeBlock[2]={x:1,y:4};
activeBlock[3]={x:2,y:4};
break;
}
case 4:{
activeBlock[0]={x:0,y:3};
activeBlock[1]={x:1,y:3};
activeBlock[2]={x:1,y:4};
activeBlock[3]={x:1,y:5};
break;
}
case 5:{
activeBlock[0]={x:0,y:3};
activeBlock[1]={x:1,y:3};
activeBlock[2]={x:2,y:3};
activeBlock[3]={x:2,y:4};
break;
}
case 6:{
activeBlock[0]={x:0,y:4};
activeBlock[1]={x:1,y:3};
activeBlock[2]={x:1,y:4};
activeBlock[3]={x:1,y:5};
break;
}
}
//提前生成预览方块
next();
//检查生成的方块是否可以放在初始的位置.
for(var i=0; i<4; i++){
if(!canFill(activeBlock[i].x, activeBlock[i].y)){
return false;
}
}
return true;
}
//向下移动
function moveDown(){
//检查能否下移
if(checkDown()){
//没有触底, 则擦除当前图形,
clear();
//更新当前图形坐标
for(var i=0; i<4; i++){
activeBlock[i].x = activeBlock[i].x + 1;
}
//重画当前图形
draw();
}
//触底,
else{
//停止下降
clearInterval(time);
//更新标记数组.
updateBoard();
//消行
var lines = deleteLine();
//有消行,
if(lines!=0){
//更新分数
score = score + lines*10;
//alert(score);
updateScore();
//擦除整个面板
clearBoard();
//重绘面板
drawBoard();
}
//产生一个新图形,判断是否可放在最初的位置.
if(!createBlock()){
alert("GAME OVER!");
status = 2;
return;
}
draw();
//定时器, 每隔一秒执行一次moveDown
time = setInterval(moveDown,1000)
}
}
//检查底边界
function checkDown(){
for(var i=0; i<activeBlock.length; i++){
if(activeBlock[i].x==17){
return false;
}
if(!canFill(activeBlock[i].x+1, activeBlock[i].y)){
return false;
}
}
return true;
}
//左移
function moveLeft(){
if(checkLeft()){
clear();
for(var i=0; i<4; i++){
activeBlock[i].y = activeBlock[i].y - 1;
}
draw();
}
}
//检查左边界
function checkLeft(){
for(var i=0; i<activeBlock.length; i++){
if(activeBlock[i].y==0){
return false;
}
if(!canFill(activeBlock[i].x, activeBlock[i].y-1)){
return false;
}
}
return true;
}
//右移
function moveRight(){
if(checkRight()){
clear();
for(var i=0; i<4; i++){
activeBlock[i].y = activeBlock[i].y + 1;
}
draw();
}
}
//检查右边界
function checkRight(){
for(var i=0; i<activeBlock.length; i++){
if(activeBlock[i].y==9){
return false;
}
if(!canFill(activeBlock[i].x, activeBlock[i].y+1)){
return false;
}
}
return true;
}
//旋转
function spin(){
var tBlock = new Array(4);
for(var i=0; i<4; i++){
tBlock[i] = {x:0, y:0};
}
//中心坐标
var cx = Math.round((activeBlock[0].x + activeBlock[1].x + activeBlock[2].x + activeBlock[3].x)/4);
var cy = Math.round((activeBlock[0].y + activeBlock[1].y + activeBlock[2].y + activeBlock[3].y)/4);
for(var i=0; i<4; i++){
tBlock[i].x = cx+cy-activeBlock[i].y;
tBlock[i].y = cy-cx+activeBlock[i].x;
}
//旋转后是否合法.
for(var i=0; i<4; i++){
if(!canFill(tBlock[i].x,tBlock[i].y)){
return;
}
}
//如果合法, 擦除
clear();
//对activeBlock重新赋值.
for(var i=0; i<4; i++){
activeBlock[i].x = tBlock[i].x;
activeBlock[i].y = tBlock[i].y;
}
//重画.
draw();
}
//检查方格是否合法
function canFill(x, y){
if(x>17||x<0||y>9||y<0){
return false;
}
if(board[x][y]==1){
return false;
}
return true;
}
//擦除
function clear(){
for(var i=0; i<4; i++){
tbl.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="white";
}
}
//绘活动方块
function draw(){
for(var i=0; i<4; i++){
tbl.rows[activeBlock[i].x].cells[activeBlock[i].y].style.backgroundColor="red";
}
}
//更新board数组
function updateBoard(){
for(var i=0; i<4; i++){
board[activeBlock[i].x][activeBlock[i].y]=1;
}
}
//消行
function deleteLine(){
var lines = 0;
for(var i=0; i<18; i++){
for(var j=0; j<10; j++){
if(board[i][j]==0){
break;
}
}
if(j==10){
lines++;
if(i!=0){
for(var k=i-1; k>=0; k--){
board[k+1] = board[k];
}
}
board[0] = createBlankLine(); //产生一个空白行
}
}
return lines;
}
//擦除整个面板
function clearBoard(){
for(var i=0; i<18; i++){
for(var j=0; j<10; j++){
tbl.rows[i].cells[j].style.backgroundColor = "white";
}
}
}
//重绘整个面板
function drawBoard(){
for(var i=0;i<18;i++){
for(var j=0; j<10; j++){
if(board[i][j]==1){
tbl.rows[i].cells[j].style.backgroundColor = "red";
}
}
}
}
//产生一个空白行.
function createBlankLine(){
var line = new Array(10);
for(var i=0; i<10; i++){
line[i] = 0;
}
return line;
}
//更新分数
function updateScore(){
if(document.all){
document.getElementById("score").innerText = " " + score;
}
else{
document.getElementById("score").textContent =" " + score;
}
}
//键盘控制
function keyDown(e){
if(status!=1){
return;
}
var event = window.event || e;
var k = event.keyCode;
switch(k){
case 37:{
moveLeft();
break;
}
case 38:{
spin();
break;
} //旋转
case 39:{
moveRight();
break;
}
case 40:{
moveDown();
break;
}
}
}
//开始
function begin(e){
e.disabled = true;
status = 1;
tbl = document.getElementById("board");
tbl1 = document.getElementById("board1");
if(!createBlock()){
alert("Game over!");
status = 2;
return;
}
draw();
time = setInterval(moveDown,1000);
}
document.οnkeydοwn=keyDown;
}