《HTML5 canvas开发详解(第2版)》——1.10 第二个示例:猜字母

1.10 第二个示例:猜字母

现在来快速看一下另一个广泛提及的“Hello World!”类型的应用程序示例——“猜字母”游戏。本章通过这个示例来说明用JavaScript编写Canvas程序比用Canvas API多了哪些工作量。

图 1-4所示的游戏中,玩家要做的是猜出计算机从字母表中随即抽取的字母。游戏会记录玩家已经猜了多少次,并列出已经猜过的字母,同时告诉玩家需要往哪个方向猜(往Z方向猜还是往A方向猜)。

1.10.1 游戏如何工作
这个游戏的基本结构与“Hello World!”的设置相同——canvasApp()是主函数,所有其他函数都定义为局部函数。这里使用drawScreen()函数在画布上显示文本。不过,本示例中也包括了其他一些函数,后面的章节会继续描述。

1.10.2 “猜字母”游戏的变量
这里是游戏中将要用到的所有变量的列表,它们都在canvasApp()中定义并初始化。因此,它们的作用域都被限定在本地定义的封装函数内。

  • guesses:这个变量保存玩家按键的次数,次数越少说明他玩得越好。
  • message:这个变量用来向玩家提示游戏的玩法。
  • letters:这个数组保存字母表中的每一个字母,一方面用来随机挑选一个游戏的秘密字母,另一方面也用来计算字母在字母表中的相对位置。
  • today:这个变量保存当前日期,仅用于在屏幕上显示,并无其他目的。
  • letterToGuess:这个变量保存当前被猜的游戏秘密字母。
  • higherOrLower:这个变量存储文本 “Higher”或“Lower”,具体取决于最后一次猜的字母与秘密字母的位置关系。如果秘密字母离“a”更近,则程序给出“Lower”提示;如果离“z”更近,则程序给出“Higher”提示。
  • lettersGuessed:这个数组保存玩家已经猜过的字母集合。程序将把这些字母显示在屏幕上,提示玩家他已经猜过什么字母。
  • gameOver:这个变量在玩家获胜前都设为false,程序能通过它知道何时在屏幕上显示“You Win”信息,玩家赢了之后就不用再猜了。
    代码如下所示。
var guesses = 0;
var message = "Guess The Letter From a (lower)to z (higher)";
var letters = [
      "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
      "p","q","r","s","t","u","v","w","x","y","z"
      ];
var today = new Date();
var letterToGuess = "";
var higherOrLower = "";
var lettersGuessed;
var gameOver = false;

1.10.3 initGame()函数
initGame()函数为玩家初始化游戏。以下是两段重要的代码。第一段代码从字母数组中找出一个随机字母,然后将其储存在letterToGuess变量中。

var letterIndex = Math.floor(Math.random()* letters.length);
letterToGuess = letters[letterIndex];
第二段代码为DOM的window对象添加了一个事件监听器,以“监听”键盘的keydown事件。当某个键被按下时,将调用eventKeyPressed事件处理函数检测按下的字母。

window.addEventListener("keydown",eventKeyPressed,true);

以下是函数的全部代码。

function initGame(){
  var letterIndex = Math.floor(Math.random()* letters.length);
  letterToGuess = letters[letterIndex];
  guesses = 0;
  lettersGuessed = [];
  gameOver = false;
  window.addEventListener("keydown",eventKeyPressed,true);
  drawScreen();
}

1.10.4 eventKeyPressed()函数
当玩家按下一个键时将调用此函数,这个函数包含了游戏中的大部分操作。JavaScript中的每个事件处理函数都会传递event对象。该对象中包含发生事件的相关信息,这里使用e参数表示该对象。

首先检测gameOver变量是否为false,如果是false,则继续检测玩家按下的是哪个键。以下代码实现了该功能:第一行代码从事件中获得按键值,并将其转换为一个字母表中的字母,用于与letterToGuess中存储的字母进行比较。

var letterPressed = String.fromCharCode(e.keyCode);

下一行代码将这个字母转换为小写字母。如果玩家不小心打开大写锁定键也可以检测大写字母。

letterPressed = letterPressed.toLowerCase();

接下来,增加guesses变量的计数,用于显示猜测次数。然后,使用Array.push()方法将字母添加到lettersGuessed数组。

guesses++;
lettersGuessed.push(letterPressed);

检测游戏的当前状态,给予玩家反馈。首先,测试letterPressed与letterToGuess是否相同,如果相同玩家就赢了。

if (letterPressed == letterToGuess){
  gameOver = true;

如果玩家没赢,程序需要分别获得letterToGuess以及letterPressed在数组letters中的索引。下面将用这些数值计算是应该显示“Higher”还是“Lower”,或者显示“That is not a letter.”(这不是一个字母)。为此,这里使用数组的indexOf()方法获得每个字母的对应索引。由于数组是按字母顺序排列的,因此判断显示哪条信息会非常容易。

} else {
  letterIndex = letters.indexOf(letterToGuess);
  guessIndex = letters.indexOf(letterPressed);

现在来进行检测。首先,如果guessIndex小于0,意味着indexOf()返回了−1,也就是说,按键不是一个字母,那么就显示一条错误信息。

if (guessIndex < 0){
  higherOrLower = "That is not a letter";

剩下的测试就简单了。如果guessIndex大于letterIndex,就把higherOrLower文本设为“Lower”。反之,若guessIndex小于letterIndex,就把higherOrLower文本设为“Higher”。

} else if (guessIndex > letterIndex){
   higherOrLower = "Lower";
  } else {
   higherOrLower = "Higher";
  }
}

最后,调用drawScreen()在屏幕上进行绘制。

drawScreen();

以下是函数的全部代码。

function eventKeyPressed(e){
   if (!gameOver){
     var letterPressed = String.fromCharCode(e.keyCode);
     letterPressed = letterPressed.toLowerCase();
     guesses++;
     lettersGuessed.push(letterPressed);

     if (letterPressed == letterToGuess){
      gameOver = true;
     } else {

      letterIndex = letters.indexOf(letterToGuess);
      guessIndex = letters.indexOf(letterPressed);
      Debugger.log(guessIndex);
      if (guessIndex < 0){
        higherOrLower = "That is not a letter";
      } else if (guessIndex > letterIndex){
        higherOrLower = "Lower";
      } else {
        higherOrLower = "Higher";
      }
     }
     drawScreen();
     }
   }

1.10.5 drawScreen()函数
下面开始编写drawScreen()函数。之前已经学习过其中的大部分代码了——代码几乎与“Hello World!”中的代码相同。例如,这里使用Canvas文本API在屏幕上绘制多个变量。仅需要设置一次context.textBaseline = 'top',就可以对所有显示的文本生效。另外,还可以使用context.fillStyle改变颜色,使用ontext.font改变字体。

这里最有趣的事就是显示lettersGuessed数组的内容。在画布上,数组将显示为一组用逗号分隔的字符串,例如:

Letters Guessed: p,h,a,d

为了输出这个字符串,只需使用lettersGuessed数组的toString()方法,即可以使用逗号间隔的方式打印出玩家猜到的数组。

context.fillText ("Letters Guessed: " + lettersGuessed.toString(), 10, 260);

接下来,还需检测gameOver变量。如果结果为真,程序在屏幕上使用大字号(40px)显示文本“You Got It!”(你胜利了)。这样,用户就知道自己获胜了。

以下是函数的完整代码。

function drawScreen(){
    //背景
    context.fillStyle = "#ffffaa";
    context.fillRect(0, 0, 500, 300);
    //边框
    context.strokeStyle = "#000000";
    context.strokeRect(5, 5, 490, 290);

    context.textBaseline = "top";
    //日期
    context.fillStyle = "#000000";
    context.font = "10px Sans-Serif";
    context.fillText (today, 150 ,10);
    //消息
    context.fillStyle = "#FF0000";
    context.font = "14px Sans-Serif";
    context.fillText (message,125,30);
    //猜测的次数
    context.fillStyle = "#109910";
    context.font = "16px Sans-Serif";
    context.fillText ('Guesses: ' + guesses, 215, 50);
    //显示Higher或Lower
    context.fillStyle = "#000000";
    context.font = "16px Sans-Serif";
    context.fillText ("Higher Or Lower: " + higherOrLower, 150,125);
    //猜过的字母
    context.fillStyle = "#FF0000";
    context.font = "16px Sans-Serif";
    context.fillText ("Letters Guessed: " + lettersGuessed.toString(), 

               10, 260);
    if (gameOver){
      context.fillStyle = "#FF0000";
      context.font = "40px _ sans-serif";
      context.fillText ("You Got It!", 150, 180);
    }
  }

1.10.6 导出Canvas到图像
之前,本章简要讨论了Canvas对象的toDataUrL()属性。这里将使用这个属性让用户能够随时创建一个游戏画面的图像,类似基于Canvas制作的游戏中的屏幕捕捉功能。

此处需要在HTML页面上创建一个按钮,用户单击该按钮就可以获得屏幕捕捉的图像。下面将这个按钮添加到< form >中,然后赋予其编号createImageData。

<form>
<input type="button" id="createImageData" value="Export Canvas Image">
</form>

在init()函数中,通过document对象的getElementById()方法获得了这个表单元素的参考。然后,使用createImageDataPressed()方法为按钮的“单击”事件设置一个事件处理器。

var formElement = document.getElementById("createImageData");
formElement.addEventListener('click', createImageDataPressed, false);

在canvasApp()函数中,定义createImageDataPressed()函数作为事件处理器。这个函数调用window.open(),并将Canvas.toDataUrl()方法的返回数值传送给窗口。由于这个数据表单是一个有效的.png,因此图像会在一个新窗口中显示。

function createImageDataPressed(e){

  window.open(theCanvas.toDataURL(),"canvasImage","left=0,top=0,width=" +
  theCanvas.width + ",height=" + theCanvas.height +",toolbar=0,resizable=0");
  }

1.10.7 最终的游戏代码
读者可以在本书分发的代码包中的CH1EX4.html文件中找到“猜字母”的最终游戏代码。

时间: 2024-09-20 04:20:27

《HTML5 canvas开发详解(第2版)》——1.10 第二个示例:猜字母的相关文章

《HTML5 Canvas开发详解》——1.9 第二个示例:猜字母

1.9 第二个示例:猜字母 现在来快速看一下另一个广泛提及的 "Hello World!"类型的应用程序示例--"猜字母"游戏.本章通过这个示例来说明用JavaScript编写Canvas程序比用Canvas API多了哪些工作量. 如图1-4所示的游戏当中,玩家要做的是猜出计算机从字母表中随即抽取的字母.游戏会记录玩家已经猜了多少次,列出已经猜过的字母,并且告诉玩家是需要往哪个方向猜(往Z方向猜还是往A方向猜). 1.9.1 游戏如何工作这个游戏的基本结构与&qu

《HTML5 canvas开发详解(第2版)》——导读

前言第2版介绍自从本书第1版发行之后,在过去的两年里,HTML5 Canvas的使用有了突飞猛进的增长.本书的第1版可以称得上是第一批介绍Canvas的专著之一.在我们为自己的快速而感到自豪同时也意味着我们曾经独自进行了大量的研究和探索.早在2011年,只有极少数HTML5 Canvas应用的例子和教程.但在2013年情形发生了改变.现在有许多关于HTML5 Canvas的资源可供选择,从框架到API,有许多网站和书籍进行专门的阐述.为了编写第2版,我们进行了大量艰辛的工作来检查在第1版中哪些部

《HTML5 canvas开发详解(第2版)》——1.6 HTML5 Canvas版“Hello World!”

1.6 HTML5 Canvas版"Hello World!" 如前所述,将Canvas放入HTML5页面时第一件要做的事就是,看看整个页面是否已经加载,并且开始操作前是否所有HTML元素都已展现.在用Canvas处理图像和声音的时候,这点会非常重要. 为此,这里要使用JavaScript的事件.当定义的事件发生时,事件从对象发出.其他对象监听事件,这样就可以基于事件进行处理.用JavaScript可以监听对象的一些常见事件,包括键盘输入.鼠标移动以及加载结束. 第一个需要监听的事件是

《HTML5 canvas开发详解(第2版)》——第1章 HTML5 Canvas简介1.1 什么是HTML5

第1章 HTML5 Canvas简介 HTML5是新一代的HTML,即超文本标记语言.HTML从1993年第一次标准化后,便奠定了万维网的基础.HTML通过使用将标签用尖括号(< >)括起来的方式定义Web页面内容. HTML5 Canvas是屏幕上的一个由JavaScript控制的即时模式位图区域.即时模式是指在画布上呈现像素的方式,HTML Canvas通过JavaScript调用Canvas API,在每一帧中完全重绘屏幕上的位图.作为一名程序员,所要做的就是在每一帧渲染之前设置屏幕的显

《HTML5 Canvas开发详解》——1.5 HTML5 Canvas版“Hello World!”

1.5 HTML5 Canvas版"Hello World!" 如前所述,将Canvas放入HTML5页面时第一件要做的事,就是看看整个页面是否已经加载,并且开始操作前是否所有HTML元素都已展现.用Canvas处理图像和声音的时候这点会非常重要. 为此,这里要使用JavaScript的事件.当定义的事件发生时,事件从对象发出.其他对象监听事件,这样就可以基于事件进行处理.用JavaScript可以监听对象的一些常见事件,包括键盘输入.鼠标移动以及加载结束. 第一个需要监听的事件是wi

《HTML5 canvas开发详解(第2版)》——1.11 动画版本的Hello World

1.11 动画版本的Hello World "Hello World"和"猜字母"本身都是不错的示例,但是它们都没能回答出"为什么"--究竟为什么要使用HTML5 Canvas?自创立以来,静态的图像和文字就是HTML的领域,那么画布的不同之处在哪里呢?要回答这个问题,需要创建第二个"Hello World"示例.这个示例将介绍画布与HTML上的其他显示方式的最大不同之处:动画.在这个示例中,将为"Hello Wor

《HTML5 canvas开发详解(第2版)》——1.9 HTML5 Canvas对象

1.9 HTML5 Canvas对象 Canvas对象是通过在HTML页面的< body >部分中放置< canvas >标签创建的,也可以通过以下代码创建画布实例. var theCanvas = document.createElement("canvas"); Canvas对象有两个相关的属性和方法可以通过JavaScript访问:width和height.这些属性显示当前HTML页面创建的画布的宽度和高度.这里需要强调的是,这两个属性并不是只读的.例如,

《HTML5 canvas开发详解(第2版)》——1.8 2D环境及其当前状态

1.8 2D环境及其当前状态 通过调用Canvas对象的getContext()方法可以获得HTML5的2D环境对象(Canvas RenderingContext2D对象).所有操作都要通过该对象进行.CanvasRenderingContext2D对象包含了在画布上绘图所需的所有方法和属性.CanvasRenderingContext2D(简称环境,后同)采用画布左上角为原点(0,0)的笛卡尔坐标系,坐标轴向右.向下为正方向. 然而,所有这些属性和方法都与当前状态关联使用.当前状态是一个必须

《HTML5 canvas开发详解(第2版)》——2.14 内容预告

2.14 内容预告 本章讨论了很多基础内容,介绍了创建简单和复杂形状的方式,以及如何在画布上绘制和变换这些形状.本章还讨论了如何组合.旋转.缩放.平移.填充这些形状以及为它们创建阴影.不过,HTML5 Canvas探索之旅才刚刚开始.