随笔-57  评论-202  文章-17  trackbacks-0

用JavaScript做涂格子游戏
原创:oq 2003年7月29日

这是我以前玩过的一个智力游戏,那个游戏的名子叫"开窗",实质都是一样的。学过JavaScript后我就试着做了一个,是用JavaScript和HTML及CSS做的一个.htm文档。

下面是这个文档的界面及其源文件的详细说明,点击这里可以下载源文件:点击下载源文件

首先在源文件的开头处我引用了一个名为game01.css的样式表:<link rel="stylesheet" href="game01.css">,用过CSS的朋友应该很熟悉了。当把样式表单独写成一个文件时就用<link>标记连接过来。下面我分别介绍游戏中的各个功能:

游戏一开始会画出一个10×10的网格,它的大小是可以更改的,只要在"棋盘大小"处输入你想要的网格大小后再点击"开始游戏"就可以了。一开始画出10×10的网格是用drawBoard()函数完成的,如下:

function drawBoard()
{
 var str="<table align='center' border='5' cellspacing=' 0' cellpadding='0' id='gameBoard' bordercolor='#0000ff' onMouseOver='mouseOver()' onMouseOut='mouseOut()' onClick='clicktable()'>";
 for(var i=0;i<size;i++)
 {
  str+="<tr>";
  for(var j=0;j<size;j++)
    str+="<td>&nbsp;</td>";
  str+="</tr>";
 }
 str+="</table>";
 return str;
}

其中size是在<script></script>标记的一开始定义的全局变量,如下:

var size=10;
var totalMoves=0;
var lightOn;
var lightOff;
var currentable;

它的初值为10,所以游戏一开始先画出一个10×10的表格。函数把一个完整的 <table> 赋给了变量str,最后返回str。两个for循环是根据size的大小赋给str表格的行数和列数。第一个for循环用 str+="<tr>;赋给str 行标记<tr>,每一行中用第二个for循环:

for(var j=0;j<size;j++)
         str+="<td>&nbsp;</td>"

赋给str单元格标记<td>,总共要赋size个,因此循环条件为:j<size; 。程序运行时在<BODY>的<script>中调用drawBoard()即:document.write(drawBoard());就画出了10×10的网格。而对网格的修改则是通过newGame()完成的:

function newGame()
{

 size=document.all.boardSize.value;
 if(size<2)
  size=2;

 if(size>14)
  size=14;

 document.all.boardSize.value=size;
 document.all.gameBoard.outerHTML=drawBoard();
 lightOn=0;
 document.all.LightOn.innerText=lightOn;
 lightOff=Math.pow(size,2);
 document.all.LightOff.innerText=lightOff;
 totalMoves=0;
 document.all.Move.innerText=totalMoves;
}

在单击"开始游戏"时就触发了 onClick="newGame()" 事件,在newGame()函数中我们对全局变量size的值进行了修改:size=document.all.boardSize.value; 即把玩家在棋盘大小处输入的值赋给size,再调用drawBoard()重新画一遍网格就实现了改变网格的大小。其中

if(size<2) size=2;
if(size>14) size=14;

是为了保证网格的改变在页面允许的范围内,即把size限制在  2<=size<=14 。过大或过小的值都会被 document.all.boardSize.value=size;语句把2或14写到"棋盘大小"处。newGame()中语句: document.all.gameBoard.outerHTML=drawBoard() 是用THML语言设置对象内容。newGame()中下面的内容:

lightOn=0;
document.all.LightOn.innerText=lightOn;
 lightOff=Math.pow(size,2);
document.all.LightOff.innerText=lightOff;
totalMoves=0;
 document.all.Move.innerText=totalMoves;

是对记寻游戏状态的变量赋初值,就是游戏板左边的那三个记录灯亮个数,灯灭个数,以及移动总数的变量。

下面我们再来看在鼠标经过时如何使网格变色,这就是用了两个事件:onMouseOver和onMouseOut,都定义在了drawBoard()的那个 <table> 中。当鼠标经过时调用mouseOver():

function mouseOver()
{
 currentable=event.srcElement;
 if(currentable.tagName=="TD")
  {
   currentable._background=currentable.style.backgroundColor;
   currentable.style.backgroundColor=
"#999999";
  }
}

其中currentable表示当前发生事件的对象,用event.srcElement获得。currentable.tagName表示当前发生事件对象的标识符名。于是鼠标经过时 <table> 时,currentable得到当前发生事件的 <td> 使得它的_background变为当前的backgroundColor即: currentable._background=currentable.style.backgroundColor;  把当前的backgroundColor变为"#999999"即: currentable.style.backgroundColor="#999999"; 。看懂了mouseOver()再看mouseOut()就不难了。以下是mouseOut():

function mouseOut()
{ 

 if(currentable.tagName=="TD")
  currentable.style.backgroundColor=currentable._background;
}

很好理解吧,我在这里就不多废话了。有了mouseOver()和mouseOut()就可以实现当鼠标经过每个单元格时使其改变颜色,而当鼠标移出后又变回原来的颜色。

源文件中最重要的函数要属clicktable()了,它的作用是当鼠标点下时使得当前对象和上下左右的方格都变色,而且要更改灯亮个数,灯灭个数,以及移动总数的值,还要判断游戏是否结束等等很多事情。同onMouseOver和onMouseOut事件一样,在drawBoard()的 <table> 中同样定义了onClick事件。下面是clicktable():

function clicktable()
{
 totalMoves++;

 document.all.Move.innerText=totalMoves;
 if(currentable.tagName=="TD")
 {
  setColor(currentable);

  var cell=currentable.cellIndex;
  var row=currentable.parentElement.rowIndex;
  if(row>0)
   setColor(gameBoard.rows[row-1].cells[cell]);

  if(row<size-1)
   setColor(gameBoard.rows[row+1].cells[cell]);

  if(cell>0)
   setColor(gameBoard.rows[row].cells[cell-1]);

  if(cell<size-1)
   setColor(gameBoard.rows[row].cells[cell+1]);
 }
 var over=light();

 if(!over)
  document.all.LightOff.innerText="You Win!";
}

totalMoves就是记录总移动次数的那个变量,totalMoves++就很明白了吧,每当鼠标在某个格子上单击时就把totalMoves加1,并把totalMoves改变后的值写在移动总数的位置:document.all.Move.innerText=totalMoves; 其中innerText用来设置或得到该对象起始标记到结束标记之间的内容。往下的if语句与另一个函数setColor(current)有关,setColor(current)通过参数current得到当前对象,然后将当前对象的颜色改为黄色(灯亮)。这样通过

cell=currentable.cellIndex;
row=currentable.parentElement.rowIndex;

取得当前对象所在表格的行、列,从而gameBoard.rows[row-1].cells[cell]就可以访问到与该对象在同列但比它靠前一行的那个对象,也用 setColor(gameBoard.rows[row-1].cells[cell] 把它的颜色改变,同理在该对象右、下、左的对象也都可以访问到,使它们的颜色都得以改变。下面是setColor():

function setColor(current)
{

 if(current._background==""||current._background==null||current._background=="#ccccff")
 {
  current.style.backgroundColo
r="yellow";
  current._background="yellow";
 }
 else if(current._background=="yellow")
 {
  current.style.backgroundColo
r="#ccccff";
  current._background="#ccccff";
 }
}

代码不难,我就不细说了。clicktable()中最后的那个light()是判断游戏是否结束的函数,因为函数中要数一下灯亮和灯灭的个数,所以我就叫它light()了,如下:

function light()
{
 lightOn=0;
 lightOff=0;

 for(var i=0;i<size;i++)
 for(var j=0;j<size;j++)
 if(gameBoard.rows[i].cells[j]._background=="yellow")
  lightOn++;
 else lightOff++;
 document.all.LightOn.innerText=lightOn;
 document.all.LightOff.innerText=lightOff;
 return lightOff;
}

lightOn和lightOff还是在一开始定义的全局变量,因为鼠标每次单击后都要检查一遍,所以要先给它们赋0。接下来就是用一个双重循环访问每一个 <td> 对象的 _background 如果是yellow则lightOn++,如果不是则lightOff++,最后不要忘记把lightOn和lightOff的值赋到LightOn和LightOff的innerText里。然后将lightOff反回并在clicktable()中判断是否结束,如果lightOff==0就结束并在"灯灭"的位置出现"You Win"。

最后还有一个规则说明,是一个超链接,点击后调用newWin():

function newWin()
{

 var newin=open("","","height=170,width=250,resizable=0");
 newin.document.write("&nbsp;&nbsp;在'棋盘大小'处输入数字 后按'开始游戏'键即可得到你想要的棋盘大小。棋盘中黄色表示灯亮, 白色表示灯灭。单击鼠标后当前方格和上下左右的方格都会变色,把所有的方格都' 点亮'后你就胜利了!");
}

newWin()新打开一个窗口,并在新窗口中写入游戏规则。

以上就是对本游戏的全部讲解,所有的功能我都调试通过,文章中若有疏漏之处还请高手指点。

posted on 2005-07-15 16:46 小米 阅读(1216) 评论(0)  编辑  收藏 所属分类: 其它

只有注册用户登录后才能发表评论。


网站导航: