EnchantJS HTML5 游戏编程教程(一)

原文:HTML5 Game Programming with enchant.js

协议:CC BY-NC-SA 4.0

零、简介

如果你正在读这篇文章,毫无疑问你对制作网络游戏有一定程度的兴趣。作为一个在这个领域有些经验的人,我觉得有资格告诉你,你来对地方了。

在过去的十年中,网络游戏发生了巨大的变化,虽然网络游戏的核心概念往往会随着时间的推移而缓慢变化,但我们用来创建它们的工具却变化得更快。在今天的 web 上,必须编写大量的代码才能在浏览器中完成简单的、与游戏相关的任务。

开源游戏引擎 enchant.js 通过大幅减少编写游戏所需的代码量来解决这一问题,并包括几个后台工作的后备和兼容性功能,以保持事情在多个浏览器之间顺利运行,而无需您做任何特殊的事情。在它的祖国日本,它已经成为一个非常受欢迎的工具,现在被越来越多的西方程序员使用。

如果你是 web 编码的初学者,不要担心!我们一步一步地向您介绍 enchant.js 的基本工作原理、JavaScript(enchant.js 使用的 web 通用脚本语言)以及 enchant . js 游戏的基本元素。然后我们转向更高级的话题。我们涵盖了一个游戏的所有必需品,包括场景、精灵、交互性等等。此外,我们为每个概念提供教程。在本书的第二部分,我们将向您展示如何创建几个游戏,包括一个打地鼠游戏(二维和三维)和一个经典的街机空间射击游戏。

虽然书中的一些代码示例链接到了免费编程环境code.9leap.net的工作版本,但通过搜索该标题并转到本书页面的源代码部分,可以在 Apress 网站(www.apress.com)上找到本书中的所有代码示例。

学习游戏编程是一个有趣和令人兴奋的冒险,有娱乐性的回报。如果您有关于该库的问题,请不要犹豫,通过官方 enchant.js subreddit ( reddit.com/r/enchantjs)、enchantjs.com或我们的脸书页面(搜索“enchant.js”)联系我们。我们的用户群体每天都在增长,既有全新的,也有经验丰富的游戏程序员。

祝你的游戏编程之旅好运!

布兰登·麦金尼斯

enchant.js 技术布道者

一、开始 enchant.js 开发

enchant.js 框架由位于东京的泛在娱乐公司(UEI)秋叶原研究中心开发,最初于 2011 年 4 月发布。从那以后,它在日本相当受欢迎,并拥有越来越多来自其他国家的粉丝。enchant.js 框架是一个基于 HTML5 和 JavaScript 的游戏引擎和独立代码库,使您能够开发可以在 PC 或 Mac 或 iPhone、iPad 和 Android 设备上运行的应用。虽然使用该引擎创建的游戏应用可以在许多不同类型的设备上运行,但大多数都是为智能手机的使用而创建和优化的。

近年来,Adobe Flash 作为交互平台的衰落导致现代网页游戏开发者转向其他基于浏览器的无处不在的平台,如 HTML5 和 JavaScript,为他们的用户创建基于浏览器的体验。然而,虽然 JavaScript 最初被开发为非专业开发人员可访问的语言,但是今天在浏览器中用于游戏创作的 JavaScript 的复杂性通常需要投入大量时间来学习和有效使用。作为一个开源的游戏库,enchant.js 通过为开发人员提供游戏创作功能来降低这种复杂性,这大大减少了您编写基于浏览器的游戏的学习曲线,并提高了您的游戏开发速度。

有了这本书,你可以开始快速轻松地创建和发布游戏。如果你完全是编程初学者,也不用担心。我们将带您了解所有基础知识,以便您可以快速上手并运行。如果您处于中级水平,我们也为您提供高级内容。我们描述了 enchant.js 框架的不同部分,并创建了几个游戏,包括经典游戏,如打地鼠和街机射击游戏,同时让您熟悉 enchant.js 库提供的所有功能。

访问 enchant.js 网站

要快速开始使用 enchant.js,请看一下三个主要的 enchant.js 网站。每个网站都有特定的功能,可以帮助你更快更容易地创建和分享游戏。

  • http://enchantjs.com:下载 enchant.js 代码库,查找资源,阅读编程技巧
  • 在基于云的在线环境中开发、编辑和测试游戏
  • http://9leap.net:上传、玩和分享游戏

在 enchant.js 主网站上,您可以了解该库并下载源代码来开发自己的游戏。您还可以在code.9leap.net上的在线环境中开发游戏,以获得流畅的体验。开发完你的游戏,就可以发布到9leap.net了。图 1-1 显示了站点的基本关系。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-1 。网站之间的关系

enchantjs.com

位于http://enchantjs.com的 enchant.js 官方网站提供了关于库、教程、技巧和资源的参考信息。该网站定期更新来自 enchant.js 开发人员的关于新版本和新特性的帖子,并且完全是日语和英语双语。该网站的默认语言是英语。如果碰巧出现了日语版本,并且您希望显示英语版本,请使用屏幕右侧的旗帜图标将语言改回英语。图 1-2 显示 enchant.js 的主页

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-2 。enchantjs.com首页

code.9leap.net

http://code.9leap.net网站上,您可以直接在 web 浏览器中执行 HTML/JavaScript 编辑、测试和共享。code.9leap.net网站支持 enchant.js 的导入,也可以轻松上传到9leap.net,允许整个游戏开发周期,从编程到发布,都在浏览器中进行。它可以在 PC 或 Mac 上使用,也可以在 iPad 等设备上使用。

图 1-3 显示了code.9leap.net登录页面。在本书出版时,该网站正处于测试开发阶段。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-3 。【code.9leap.net】登录页面

9leap.net

位于http://global.9leap.net的 9leap 网站由 UEI 和 D2 通信公司(www.d2c.co.jp/en)主办,旨在发现和提升年轻开发者。该网站允许你上传、玩和分享游戏。9leap 网站包括许多像您一样的开发人员用 enchant.js 创建的游戏。在您开始创建自己的游戏之前,尝试一下该网站上的一些游戏,感受一下 enchant.js。图 1-4 显示的是 9leap 主页。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-4 。【9leap.net 首页

你也可以在网站上参加游戏开发竞赛。竞赛决赛入围者赢得奖品,如最新的 PC 和 Mac 电脑、书店礼品卡等。此外,作为 9leap 项目的一部分,UEI 定期在日本举办 9leap 游戏编程训练营,并开始在美国举办训练营。通常,这些夏令营以游戏编程研讨会开始,并提供指导以帮助参与者创建他们自己的简单游戏。有关更多信息,请访问enchantjs.com网站。

兼容性和版本

以下浏览器和设备支持 enchant.js:

  • Internet Explorer (IE) 9.0 和更高版本
  • 适用于 Mac OS X、Windows 和 Linux 的 Chrome 10 及更高版本
  • 适用于 Mac OS X 和 Windows 的 Safari 5 及更高版本
  • 适用于 Mac OS X 和 Windows 的 Firefox 3.6 及更高版本
  • 适用于 iPhone 和 iPad 的 iOS 4 及更高版本
  • Android 2.1 及更高版本

表 1-1 显示了 enchant.js 的主要版本,在本书出版时,enchant.js 的最新版本是 0.6.2 版。

表 1-1 。enchant.js 的最新版本和新增功能

版本添加的功能
0.6.2(当前)
  • Do better on Android
  • Improved key binding.

|
| 0.6.1 |

  • 改良网络音频
  • Improved timeline

|
| 0.6.0 |

  • web 音频 API
  • 唐/坎瓦斯科
  • Animation engine
  • Core class

|
| 0.5.2 | |
| 0.5.1 |

  • [bug fix]

|
| 0.5.0 |

  • Sound support on iPhone
  • Support rotation & scaling attribute
  • Support canvas
  • 经过时间支持

|

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 从 0.6.1 版本开始,enchant.js 在 MIT 许可下授权。联系 Ubiquitous Entertainment ( http://global.uei.co.jp/)咨询有关公司使用 enchant.js 代码的问题。

enchant.js 的特性

enchant.js 旨在使游戏编程更简单,它提供了几个功能,使开发人员(无论是专家还是新手)更容易创建游戏。该库的主要特点是它的面向对象的方法,它处理游戏代码的特定方式,它通过插件的可扩展性,以及它的内容库。

面向对象编程

面向对象编程(OOP) 是一种强调被操作对象而不是操作过程的方法论。为了说明这个概念,enchant.js 中可以在屏幕上显示的每个图形都是一个对象。屏幕上实际可见的是另一个对象的一部分,称为显示对象树。通过发出将图形对象加入显示对象树的命令,图形对象在屏幕上变得可见。

列表 1-1 显示了一个玩家对象和一个敌方角色对象通过在显示对象树中注册而被创建并显示在屏幕上。现在,不要担心这段代码如何工作的细节。我们在这里提供一个代码示例,只是为了让您快速了解 OOP 的实际应用。稍后,我们将带您详细了解代码示例。

清单 1-1。 使用面向对象编程创建两个对象并在屏幕上添加它们

//Player object creation
var player = new Sprite(32, 32);
player.image = game.assets['player.png'];

//Enemy character object creation
var enemy = new Sprite(32, 32);
enemy.image = game.assets['enemy.png'];

//Registration in the display object tree
var scene = game.currentScene;
scene.addChild(player);
scene.addChild(enemy);

异步处理

异步处理是独立于主代码集运行的处理。把这当成多任务处理。如果计算机正在接收要一个接一个运行的命令行,然后在第一组命令仍在运行时开始接收运行其他命令的命令,这就是异步处理的一个例子。

enchant.js 异步处理用户或其他程序发起的操作或事件。当用户不发出任何命令时,程序只是等待而不做任何事情,而不是在后台连续运行代码。此外,当用户被迫等待一个程序完成处理时,这种异步特性使得同时发出其他命令成为可能。

清单 1-2 显示了指定在特定事件发生时运行的代码段。这被称为事件处理。在这个代码示例中,我们处理每一帧中的玩家对象,同时也处理触摸事件。具体来说,每次绘制一个帧,我们都希望运行一些代码(或者像开发人员有时说的那样“被执行”)。当玩游戏的用户点击或“触摸”角色时,我们希望执行不同的代码。我们将在第三章中详细介绍这一过程。

清单 1-2。 异步处理用于创建、设置和处理一个角色

//player (character) object creation
var player = new Sprite(32, 32);

//handling of the character in each frame
player.addEventListener(Event.ENTER_FRAME, function() {
    ...
});

//handling touch events
player.addEventListener(Event.TOUCH_START, function(e) {
    var x = e.localX;
    var y = e.localY;
    ...
});

插件扩展性

您可以通过各种插件来扩展 enchant.js 的功能,以添加更多功能。例如,一些插件允许你开发支持 D-pad 和模拟棒等设备的游戏,或者创建看起来像漫画书的互动游戏。在本书后面的章节中,我们将向您展示如何使用几个插件。

我们在这里没有提供所有 enchant.js 插件的详尽列表,因为您可以在enchantjs.com网站上找到该列表以及每个插件的详细信息。您可以从网站下载插件(参见 enchant.js 下载包)。

图像和声音

如果你是一个独立的游戏程序员,寻找用于角色、怪物、风景等的图像可能是一个挑战。由于 enchant.js 附带了一个免版税(用于非商业游戏)的原始游戏图像分类,以及来自以前 UEI 游戏版本的材料,您可以通过使用图像库为自己的游戏创建图像。图像包含在主 enchant.js 包中。图 1-5 展示了几个广泛可用的角色形象的例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-5 。enchant.js 包中的角色图像示例

你也可以从enchantjs.com的下载页面下载独立于主库的 zip 文件中的声音。例如,您可以包括背景音乐、爆炸声、激光射击、枪声、当角色捡起物品时可以使用的信号等等。

JavaScript、HTML5 和 CSS

现代网站通常由三种类型的代码组合而成:JavaScript、HTML5 和层叠样式表(CSS)。通常,HTML 提供核心内容,CSS 用于样式和格式,JavaScript 用于与页面元素交互并提供动画。我们在这一章中提供了 HTML5 和 CSS 的简要总结,但这本书总体上主要关注 JavaScript,因为这是编写 enchant.js 游戏的语言。

JavaScript

JavaScript 是一种面向对象的解释型编程语言,最初的开发目的是增加网页的交互性和动态性。JavaScript 的一个例子在清单 1-3 中显示。你可能听说过一种叫做 Java 的编程语言,但它与 JavaScript 完全不同。JavaScript 保证可以在所有主流浏览器上运行,无需安装任何额外的软件。如果您以前从未见过 JavaScript,请不要担心!我们会在第二章中详细介绍。

清单 1-3。 显示“Hello,World!”在屏幕上

document.write('<p>Hello, World!</p>');

HTML 和 HTML5

HTML 是超文本标记语言的缩写,是一种用于描述 Web 上文本的标记语言。在 enchant.js 中,HTML 用于加载 JavaScript 并控制智能手机上的某些浏览器操作(如缩放)。清单 1-4 中显示了一个例子。如果你打开一个普通的文本文件,在其中键入来自清单 1-4 的代码,并将其保存为“index.html”,该文件可以通过你的浏览器打开。浏览器会显示“Hello World!这是 HTML 页面的内容部分。

清单 1-4。 HTML 示例在浏览器中显示内容

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no">
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
        <title>HelloWorld</title>
        <style type="text/css">
            body {
                margin: 0;
            }
        </style>
    </head>
    <body>
<p>Hello World! This is the content part of an HTML page.</p>
    </body>
</html>

HTML5 是 HTML 几个新特性的统称。表 1-2 显示了主要特征的例子。

表 1-2。【HTML5 的新特性

新的 HTML 功能描述
<canvas>元素支持二维图形的绘制
<audio>元素允许声音回放
<video>元素支持视频播放
应用缓存允许脱机执行应用
跨域消息传递允许在域之间传输信息
XMLHttpRequest二级
网络存储使用客户端保存数据
SQL 数据库
索引数据库
Web 工作器支持后台处理以改善用户体验
服务器发送事件允许与服务器进行双向通信
Web 套接字
文件 API允许访问本地文件

在 enchant.js 中,不直接使用 HTML5 函数,而是通过 enchant.js 库访问。在本书中,我们不提供 HTML 和 HTML5 的详细讨论。

半铸钢ˌ钢性铸铁(Cast Semi-Steel)

CSS 代表级联样式表,和 HTML 一起用来定义网页的外观,比如颜色、文本和大小。HTML 也可以用来指定页面的外观,但是它的正确用法是使用 CSS 来指定内容和定义内容的外观。使用 CSS 编辑动态网页尤其容易。清单 1-5 展示了如何将网页主体元素的背景改为灰色并指定字体。

清单 1-5。 改变网页背景并指定字体

body { background-color: #DDDDDD; font: 30px sans-serif; }

在 enchant.js 中,CSS 函数不是直接使用的,而是通过 enchant.js 库访问的。在本书中,我们不提供 CSS 的详细讨论。

制作“Hello World!”出现在屏幕上

对于我们的第一个 enchant.js 应用,我们将向您展示如何创建一个非常简单的程序来创建一个标签“Hello World!”这个练习的目的是用简单的方式向你展示 enchant.com 游戏的元素是如何组合在一起的。我们稍后会创建更复杂的游戏。

  1. 去 enchantjs.com 点击下载按钮下载最新的 enchant.js 包(不是开发版)。

  2. After unzipping the file, open a text editor, copy and paste the code shown in Listing 1-6, and save the file as “index.html” inside the folder the enchant.js package unzipped to.

    清单 1-6。 Index.html:加载 enchant.js 和主游戏代码

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>HelloWorld</title>
            <script type="text/javascript" src="enchant.js"></script>
            <script type="text/javascript" src="main.js"></script>
        </head>
        <body>
        </body>
    </html>
    

    代码将文件指定为 HTML 文件,告诉浏览器我们使用的是 UTF-8 字符编码(enchant.js 就是用这种编码编写的),给它一个标题“HelloWorld”,然后告诉它从一个名为“main.js”的文件加载我们的游戏代码,我们接下来将创建这个文件。

  3. Create a new file in your text editor, copy and paste the code shown in Listing 1-7, and save the file as “main.js” inside the same folder.

    清单 1-7。 简单的 enchant.js 应用显示“Hello World!”屏幕上的

    enchant();
    var game;
    
    window.onload = function(){
           game = new Core(320, 320);
           game.onload = function(){
                   sign = new Label();
                   sign.text = "Hello World!";
                   game.rootScene.addChild(sign);
           };
           game.start();
    };
    

清单 1-7 中的代码告诉 enchant.js 用enchant();命令启动,创建游戏,并指定游戏屏幕的尺寸。页面完全加载后,我们指定创建名为“sign”的新标签的指令,指定文本为“Hello World!”,然后将其添加到游戏屏幕。最后,用game.start(),我们运行那些指令。

现在,如果你在浏览器中打开 index.html,你应该会看到“你好,世界!”显示在屏幕上。在这个例子中,唯一使用的文件是 enchant.js、index.html 和 main.js

这是一个非常基本的例子,但从中你可以看到 index.html 加载了 enchant.js,index.html 也加载了我们用 main.js 编写的游戏代码。我们的下一个例子本质上将更加图形化,并向你介绍在线编程环境,code.9leap.net

创造一只滑冰熊

对于我们的第二个 enchant.js 应用,我们让一只熊在屏幕上从左向右滑动,并优化应用以在智能手机上显示。您可以找到我们在http://code.9leap.net/codes/show/19822创建的代码示例。

正如我们之前提到的,code.9leap.net为 enchant.js 中的游戏编码准备了所有必要的元素。我们在这个应用中使用了code.9leap.net,我们将带您完成所有必要的步骤。请注意code.9leap.net仍处于测试阶段,可能会与本节中的截图略有不同。

以下步骤展示了在code.9leap.net上创建 enchant.js 应用的整个开发过程。我们将在接下来的小节中详细介绍每个步骤。

  1. 开始使用您的应用
  2. 导入 enchant.js 库
  3. 编辑源代码
  4. 预览您的结果
  5. 完成编辑您的源代码

开始使用您的应用

code.9leap.net上开发游戏的第一步是创建一个账户。以下步骤向您展示了如何创建帐户。如果您已经创建了一个帐户,那么您可以跳过这一步,登录并继续创建项目。

当使用 enchant.js 编程时,我们强烈建议使用 Google Chrome 作为您的首选浏览器。虽然使用 Safari 和 Firefox 也有不错的结果,但我们不能保证 Internet Explorer 在与 enchant.js 库或与 enchant.js 相关的网站交互时的稳定性。

  • 1.  Open http://code.9leap.net in your favorite browser and click the Sign up link, which is located below the username and password input areas. See Figure 1-6. (If the Japanese site appears, scroll down and click Switch To English).

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-6 。code.9leap.net 登录屏幕

  • 2.选择用户名和密码,并将其输入到相应的字段中。阅读服务条款后,选择“我同意服务条款”。完成后,点击位于输入表单下方的注册按钮。

  • 3.  You will be redirected to the dashboard of your new account. An explanation of this screen follows in the next step. The next time you visit the site, you can just enter in your login information to log in.

    创建帐户或登录后,您将被重定向到仪表板,如图 1-7 所示。仪表板提供了关于您的帐户的所有必要信息。在右边你会发现你已经创建的所有项目的列表。(当然,创建新帐户后,该列表最初将为空。)在左侧,您会发现一个包含各种类别的示例项目列表。

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-7 。code.9leap.net 仪表板

    要创建 enchant.js 应用,首先需要创建一个项目。项目是包含管理应用所需的所有文件的包。要开发一个应用,您需要一个项目。

  • 4.  Click the English Tutorials category in the Sample Projects list, shown in Figure 1-8.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-8 。英语教程

  • 5.  After you click a category, it will expand, displaying all projects in the category. You will see a list of Beginner projects that you can fork or view. Forking the project creates a copy in your project list. Viewing a project allows you to see the code together with a screen showing the result of the code when executed. Click Fork next to the Beginner 01 project. In the pop-up, confirm your action by clicking Fork again, as shown in Figure 1-9.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-9 。叉子弹出

  • 6.  After you click Fork for the second time, a source code editing screen is displayed with code already populated inside it. Shown in Listing 1-8, this code displays the string “Hello,Bear” using enchant.js, similar to the way we created the “Hello World!” program in a preceding section.

    清单 1-8。 屏幕上显示“你好,小熊”

    enchant(); //the magic words that start enchant.js
    
    window.onload = function() {
        game = new Game();
        game.onload = function() {          //Prepares the game
            hello = new Label("Hello,Bear");   //Create a new label with the words "Hello,Bear"
            hello.x = 10;                   //Place the label 10 pixels to the right (0 will always be the left border)
            hello.y = 150;                  //Place the label 150 pixels from the top (0 will always be the top border)
            game.rootScene.addChild(hello); //Show the label on the active screen
        }
        game.start(); //Begin the game
    }
    

就像我们前面的例子一样,这段代码在屏幕上创建了一个标签。这里,我们将标签放在离屏幕中心更近的地方,并将文本指定为“Hello,Bear!”而不是“你好,世界!”这一次我们不会使用源代码,而是重写它来制作我们自己的 enchant.js 程序。图 1-10 和表 1-3 显示了代码编辑屏幕的不同区域。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-10 。源代码编辑屏幕

表 1-3 。源代码编辑屏幕的元素

| 标题编辑区 | 你的申请的标题。 |
| 账户区域 | 注销和仪表板访问。 |
| 代码预览区 | 显示应用预览的代码区域。 |
| 提示区 | 这里将显示教程的提示或说明。 |
| 资源选择 | 一个下拉菜单,使您能够在 JavaScript (main.js)、HTML (index.html)、级联样式表(style.css)和提示(tips.json)之间切换。默认情况下,该菜单设置为 main.js。下拉菜单位于代码预览区域的正上方。 |
| 运行按钮 | 在预览区域执行源代码。 |
| 格式按钮 | 格式化源代码编辑区域中的源代码。 |
| 添加资源按钮 | 用于添加项目中使用的资源(图像、声音等)。 |
| 完成按钮 | 完成源代码编辑并返回仪表板。 |
| 源代码编辑区 | JavaScript 源代码、HTML 文件和编辑技巧。导入库时也使用。 |
| 图像区域 | 显示项目的所有本地图像。 |

接下来,您需要编辑标题(应用名称)。

  • 7.在源代码编辑屏幕上的标题编辑区(直接位于右上角 code.9leap 徽标的右侧)更改标题。现在输入“HelloEnchant”。

  • 8.  Change the title of the HTML file. Select index.html, which is the HTML file of the application, in the resource selection. The file will be displayed in the source code editing area, and should be prepopulated with some code. There you will find the title of the HTML file. In this case it is currently set to <title>untitled</title>. As shown in Figure 1-11, change it to <title>HelloEnchant</title> for our current application.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-11 。编辑标题

导入 enchant.js 库

库是一个文件或一组文件,它允许其他程序使用特定的功能。为了构建我们的应用,我们使用 enchant.js 库。通过 HTML 文件中的脚本标签将库加载到项目中。有时库需要将图像添加到项目中,但是我们现在不需要这样做。

请记住,enchant.js 中的插件也是库,因此它们需要加载自己的脚本标签。这就是为什么您会在下面的清单中看到引用诸如 tl.enchant.js 等文件的行。

要添加 enchant.js 库,请执行以下操作:

  1. Remove the lines of code containing nineleap.enchant.js and tl.enchant.js. You should already be at index.html from the preceding steps. These lines of code will be inside the script tags (sections of code marked by <script>). These tags tell the browser that everything between <script> and </script> should be treated as a line of code. When src= is included in the script tag, it tells the browser to load lines of code from a file outside index.html. After removing the two lines of code, your <script> tags should match Listing 1-9.

    清单 1-9。 脚本标签加载 enchant.js,插件,游戏代码

    <script src='/static/enchant.js-latest/enchant.js'></script>
    <script src='/code.9leap.js'></script>
    <script src='main.js'></script>
    

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意main . js 脚本标签导入应用代码,所以这个标签始终是必需的。切勿更改或删除它。

您可以使用code.9leap.js库添加在code.9leap.net中开发 enchant.js 应用时所需的任何特性;但是,对于我们当前的应用,不要对库进行更改。/static/enchant.js-latest/enchant.js标签导入 enchant.js 库。当你在code.9leap.net中开发应用时,你可以使用/static/enchant.js-latest/路径引用最新发布的 enchant.js。enchant.js 插件nineleap.enchant.jstl.enchant.js也是如此。

编辑源代码

要编辑源代码,请从资源下拉列表中选择 main.js。该屏幕应如图 1-12 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-12 。编辑源代码

删除源代码编辑区域中显示的所有内容,因为您需要在此复制并粘贴一些代码。JavaScript 区分大小写,所以复制代码时要小心。接下来,执行以下步骤。

  1. Initialize the enchant.js library. This allows you to use all the classes and methods included in the library. Listing 1-10 shows how to initialize the enchant.js library. The parentheses after the word “enchant” indicate that the previous word is a method, which runs a predefined set of code, and the semicolon at the end (😉 indicates the end of a single statement of code.

    清单 1-10。 初始化 enchant.js 库

    enchant();
    
  2. On a new line under the enchant() method, designate code to be run after the page has loaded completely, as shown in Listing 1-11. Assigning code to the onload function of an object called the window, which, as you may suspect, represents the window in the browser, specifies that code to be run after loading.

    清单 1-11。 指定加载完成后运行的代码

    window.onload = function() {
        //code to be executed
    };
    
  3. Create the core object by replacing “//code to be executed” with the code shown in Listing 1-12. The line that begins with two forward slashes indicates that the line is a comment, and will not be processed as code. To create a game, enchant.js needs a core object to add game elements to. Typing in “Core(320,320)” creates a game screen with a width of 320 pixels and a height of 320 pixels, respectively. The format of “new Core(320,320)” is called a constructor, and we use constructors to create new objects.

    清单 1-12。 创建核心对象

    var game = new Core(320, 320);
    
  4. Preload the required image of a bear skating, as shown in Listing 1-13. To use images in enchant.js, you must preload them first. The image we load for this application is shown in Figure 1-13. Normally, this image must be uploaded into the code.9leap project or included in the same folder as your index.html file, but because we forked the project, this image is already in the project.

    清单 1-13。 预载一只滑冰熊的形象

    game.preload('chara1.gif');
    

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-13 。熊图片:chara1.gif

  5. Designate a function to be run once the game has loaded completely, as shown in Listing 1-14. We create this in much the same way as we did with window.onload, and we do this because any game object we create can be created successfully only if the core object has completely loaded.

    清单 1-14。 创建game.onload功能

    game.onload = function() {
    };
    
  6. Create the bear sprite, as shown in Listing 1-15. We must first create a new variable as a new Sprite object, with dimensions of 32 pixels wide by 32 pixels high, specify the image we preloaded to be used as the image of the bear, and then specify which part of the image we want to use. We want to use the image of the skating bear, which is the fifth image counting from the top left. Frame numbering begins with 0, so the skating bear is frame number 4 within the image. Note that this code must be typed inside the curly braces of the game.onload function.

    清单 1-15。 创造熊精灵

    var bear = new Sprite(32, 32);
    bear.image = game.assets['chara1.gif'];
    bear.frame=4;
    
  7. Create an event listener to move the bear by three pixels to the right every frame, as shown in Listing 1-16. We cover event listeners in more detail later, but for now simply be aware that this code tells the program to move the bear every frame. Add it after the code you entered in Listing 1-16, still inside the game.onload curly braces.

    清单 1-16。 创建事件监听器来移动熊

    bear.addEventListener(Event.ENTER_FRAME, function() {
        this.x += 3; //move by 3 pixels
    });
    
  8. Add the bear to the game’s root scene, as shown in Listing 1-17. We’ve created the bear, but it still won’t be shown on the screen unless we add it to the game’s root, or main, scene. Enter this code after the code you entered in Listing 1-16, still inside the game.onload curly braces.

    清单 1-17。 将熊添加到游戏的根场景

    game.rootScene.addChild(bear);
    
  9. Under the game.onload curly braces, but still inside the window.onload curly braces, start the game. See Listing 1-18.

    清单 1-18。 开始游戏

    game.start();
    
  10. Check your code. Your code should match what is shown in Listing 1-19. You can ignore the comments (lines starting with two forward slashes). If it all matches, hit the Run button in the upper-right corner, and you should see your bear skate across the screen!

***清单 1-19。*** 让熊滑过屏幕

```js
//initialization of enchant.js
enchant();

//code written here will be executed once the HTML file is completely loaded
window.onload = function() {
    //game object creation
    var game = new Core(320, 320);

    //image loading
    game.preload('chara1.gif');

    //execution once the image has loaded completely
    game.onload = function() {
        //Sprite creation
        var bear = new Sprite(32, 32);
        bear.image = game.assets['chara1.gif'];
        bear.frame=4;

        //frame loop to move the bear every frame
        bear.addEventListener(Event.ENTER_FRAME, function() {
            this.x += 3; //move by 3 pixels
        });

        //add the bear to the display object tree
        game.rootScene.addChild(bear);
    };
    game.start();
};
```

现在让我们添加一些信息来优化智能手机上的玩家体验。
  1. Select the index.html file from the resource drop-down menu. Adjust the content of your file to match the content shown in Listing 1-20.
***清单 1-20。*** 为智能手机调整 HTML】

```js
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <style type="text/css">
        body {
            margin: 0;
        }
    </style>
    <link rel='stylesheet' href='style.css' type='text/css'>
    <script src='/static/enchant.js-latest/enchant.js'></script>
    <script src='/code.9leap.js'></script>
    <script src='main.js'></script>
    <title>HelloEnchant</title>
</head>
<body>
</body>
</html>
```

让我们来看看我们添加的新 HTML 标签。以下代码将字符编码设置为 UTF-8 (unicode),这种字符编码与大多数现代语言中使用的几乎所有字符都兼容。

  • <meta charset="utf-8">

下面的代码禁止用户缩放(zoom)以确保游戏看起来总是正确的。

  • <meta name="viewport" content="width=device-width, user-scalable=no">

下面的代码将显示设置为全屏。

  • <meta name="apple-mobile-web-app-capable" content="yes">

下面的代码更改了状态栏的显示方式。

  • <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

下面的代码将 HTML 正文边距设置为 0,以保持不同浏览器之间的外观一致。

  • <style type="text/css"> body { margin: 0; } </style>

我们将在本书的所有应用中使用这个 HTML 文件。除了改变我们导入的库,我们唯一改变的是标题。

预览您的结果

如图 1-14 所示,当您编辑完源代码后,点击屏幕右上角的运行按钮保存您的进度。如果你输入的源代码正确,熊应该从左向右滑。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-14 。展示预览

如果预览看起来很奇怪,请检查您的源代码以确保它匹配。特别要注意丢失的分号(;)、放错位置的句号、拼错的名字。

我们可以将字符串打印到控制台,这是一个专门为开发人员提供的特殊输出屏幕,方法是使用一种叫做 log output 的东西。它可以用来检查变量值和程序执行的方式。要在日志屏幕上打印名为sum的变量的值,使用列表 1-21 中的符号。

清单 1-21。 显示控制台中变量的名称

console.log("Total = " + sum); console.log("sum = " + sum);

如果您使用 Google Chrome 作为浏览器,您可以使用以下步骤来查看日志的输出。

  1. Open the console by right-clicking the part of the window running the game and select Inspect Element, shown in Figure 1-15.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-15 。从下拉菜单中选择检查元素

  2. 将会打开“开发工具”窗口。单击控制台按钮显示控制台。如果您的应用由于 JavaScript 语法错误而无法运行,错误类型和行号将显示在控制台中。

完成源代码编辑

要完成源代码编辑,请单击源代码编辑屏幕上的 finish 按钮。您将被重定向回您的仪表板。

在设备上执行并上传到9leap.net

正如我们在本章开始时所说的,到目前为止,许多用 enchant.js 创作的游戏都是为在移动浏览器上玩而设计的。一旦你完成了游戏编码,我们建议你检查你的源代码,在移动设备上测试你的游戏,如果你愿意的话,在9leap.net上分享你的游戏。

源代码查看屏幕

点击仪表板上的项目名称,打开您自己的项目或示例项目的源代码视图,如图 1-16 所示。在那里,你可以查看和执行源代码,获得在其他设备上运行代码的 URL,创建一个标签嵌入博客,并在9leap.net上发布游戏。在您的仪表板上,单击 HelloEnchant 打开您刚刚创建的项目的源代码视图。在屏幕的上部,您会发现各种按钮,其功能在表 1-4 中有说明。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-16 。源代码查看屏幕

表 1-4 。源代码查看屏幕上的按钮

| 编辑按钮 | 返回源代码编辑屏幕进行编辑。 |
| 叉形按钮 | 用这个源代码开始一个新项目。 |
| 下载按钮 | 将项目使用的源代码和资源下载到本地硬盘上。 |
| 发布到9leap.net | 在9leap.net (beta)上分享您的应用。 |
| 嵌入按钮 | 创建一个标签,用于将应用嵌入到博客、网站等中。 |
| 删除按钮 | 删除此项目。 |

在这些按钮下面,您可以在左侧看到应用的预览,当您打开屏幕时,会自动执行该预览。源代码出现在右边。

在设备上执行

要在 iPhone、Android 或其他设备上通过code.9leap.net执行 enchant.js 应用,请执行以下步骤。

  1. Check the project ID by looking at the URL of the project, as shown in Figure 1-17. In this case, the ID is 21345.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-17 。检查项目 ID

  2. Use this ID to create a URL that can be opened on mobile devices. If the URL shown in the window is http://code.9leap.net/codes/show/21345, then the mobile URL will be http://coderun.9leap.net/codes/21345. This example is shown in Figure 1-18.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-18 。在设备上运行代码

嵌入博客

要创建标签以将 enchant.js 应用嵌入到博客或网站中,请在源代码视图中单击“嵌入”按钮。将出现一个嵌入标签,如图图 1-19 所示。将此标签复制并粘贴到您的网站或博客的 HTML 代码中。如果你有一个简单的网站,你可以将标签直接粘贴到网站的<div><body>标签中,但是如果你使用一个内容管理系统,比如 WordPress,你可能需要在编写或编辑一个新的页面或文章时启用 HTML 编辑来成功粘贴这个标签。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-19 。嵌入弹出

提交到9leap.net

当你的 enchant.js 应用完成后,试试在9leap.net上分享吧!你可以先把它设置为私有模式,这样你就有机会在公开之前测试它。按照以下步骤共享您的应用。(在撰写本书时,发布到 9leap 按钮仍在测试中。)

  1. 单击源代码查看屏幕中的下载按钮。你的浏览器会下载游戏的压缩文件。

  2. Go to 9leap.net, shown in Figure 1-20, and log in using your Twitter account. (If you don’t have one, you’ll need to register one before you can use 9leap.net.) The button might appear in English or Japanese because the site is still in the beta stage.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-20 。9leap.net 上的登录按钮

  3. Click Game Upload/Edit Screen, as shown at the top of the screen in Figure 1-21.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-21 。游戏上传/编辑链接

  4. Click on Add New, as shown in Figure 1-22.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-22 。添加新按钮

  5. Accept the terms of service, fill in your information, and click Send, as shown in Figure 1-23. This information is used to consider the game for contests on the site.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 1-23 。发送按钮

  6. 在空白处填入你的游戏信息。这些字段在表 1-5 中解释。对于游戏文件,找到从code.9leap.net保存的游戏的 zip 文件。你需要包括一个截图,可以是游戏的图片文件或者截图。(请参见http://bit.ly/11m6e4了解 Mac 的屏幕截图信息,参见http://bit.ly/ZFSdT了解 PC 的屏幕截图信息。)请确保指明您希望使用哪种许可证来许可您的游戏。完成后,点击游戏后按钮,如图图 1-24 所示。

表 1-5 。游戏信息字段

| 游戏标题 | 输入不超过 40 个字符的游戏名称。 |
| 型 | 为你的游戏选择一个流派。 |
| 游戏解说 | 用不超过 1000 个字符的篇幅解释你的游戏目标以及如何玩。 |
| 游戏文件 | 包含游戏的小于 10MB 的 zip 文件。 |
| 截图 | 你的游戏截图(小于 1MB - jpg/png/gif)。 |
| 运行时环境 | 指出游戏浏览器的兼容性。 |
| 推特设置 | 指明您是否希望 9leap 在 Twitter 上发布您的游戏。 |
| 设为私有 | 如果您希望您的游戏只有您一个人可以查看,请选择此选项。 |
| 提交参赛作品 | 如果你的游戏有资格参加目前正在 9leap 上举行的比赛,它们将会出现在这里。 |
| 源代码许可 | 如果你想指定一个许可证来保护你的游戏,请在这里指定。 |

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-24 。上传按钮

私人设置可以在任何时候从游戏编辑设置页面更改。

成功上传游戏后,将显示共享完成屏幕,您可以在游戏上传/编辑屏幕上查看您的游戏。参见图 1-25 。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1-25 。上传的游戏出现在游戏上传/编辑界面

结论

在本章中,我们介绍了 enchant.js 的基本特性,并展示了 enchant.js 游戏如何融入网页结构。我们在code.9leap.net上谈到了 JavaScript、HTML5 和 CSS,以及如何开始编写游戏代码。最后,我们看了看如何在global.9leap.net上与 enchant.js 社区分享你的游戏,以及玩其他用户创建的游戏如何给你自己的游戏带来灵感。

在下一章中,我们将介绍 JavaScript 的构建模块,这是编写 enchant.js 的语言。学习 JavaScript 将为你开始用 enchant.js 创建自己的游戏打下基础。

二、JavaScript 基础知识

正如我们在第一章中所说,enchant.js 是用 JavaScript 编程语言编写的。当您在 enchant.js 中编写游戏时,您将使用 JavaScript 语言编写命令和其他代码,因此在深入研究 enchant.js 游戏之前,我们需要研究简单的 JavaScript。如果你已经熟悉 JavaScript,可以跳过这一章。

JavaScript 是用于网页脚本的主要编程语言。与大多数用于创建必须安装在计算机上才能运行的软件应用的编程语言不同,JavaScript 代码在客户端 web 浏览器上运行。鉴于 enchant.js 和用 enchant.js 编写的游戏都是用 JavaScript 创建的,所以理解 JavaScript 的基本概念是必不可少的。如果您是编程新手,学习这些基础知识将使您受益匪浅,因为它们恰好也是面向对象语言的构建块,并且是学习其他流行编程语言(如 Java 和 C++)的有用起点。

一种编程语言的语法,或者更确切地说,这种语言的元素编写的特定方式,被称为语法。在本章中,你将通过在 code.9leap.net 网站上编写代码来学习 JavaScript 的构建模块、语法和功能。我们将带您一步一步地完成这一过程,并通过一系列简单的代码项目来解释每一个构建模块。

汇总列表

在本章中,我们将向您展示如何执行以下操作:

  1. 声明一个变量
  2. 给变量赋值
  3. 添加变量
  4. 检查变量的值
  5. 使用变量本身操作变量
  6. 使用增量操作变量
  7. 比较变量
  8. 看看两个变量有多相似
  9. 操纵比较
  10. 用 If 语句实现逻辑
  11. 创建一个对象
  12. 更智能地使用 While 和 For 循环语句
  13. 用 Break 中断循环
  14. 用 Continue 跳过循环迭代
  15. 生成随机数
  16. 用开关定义场景
  17. 将编号数据存储在一个数组中
  18. 在关联数组中存储无编号的数据
  19. 使用功能节省时间
  20. 查看变量的位置
  21. 用原型制作物体蓝图

声明一个变量

变量是值的容器,在大多数情况下可以随时用新值更新,因此得名。它们的值“不同”,所以它们是“可变的”使用变量优于显式值是因为变量的动态特性。如果在计算中包含一个变量,然后又更改了该变量的值,则下次执行相同的计算时,将使用新值。

要使用一个变量,首先必须用var语句声明它,它告诉应用在内存中为该变量保留一个位置。在 JavaScript 的任何一条语句的末尾,都必须包含一个分号(;).

要声明三个名为num0num1sum的变量,请执行以下操作:

  1. 如果您还没有帐户,请转到http://code.9leap.net并登录或注册。

  2. 转到http://code.9leap.net/codes/show/26854,点击 fork 按钮,将空白的 JavaScript 模板分叉。

  3. 通过直接修改屏幕左上角 code.9leap 徽标右侧的字段来更改项目的标题。选择适当的东西,比如“声明一个变量”(对于所有将来派生此代码的示例,请以这种方式更改标题,以跟踪您的单个项目。)

  4. Type in the code shown in Listing 2-1.

    清单 2-1。 声明一个变量

    var num0;
    var num1;
    var sum;
    

命名变量

您可以在变量名中使用以下字符:

  • 字母(A-Z,A-Z)
  • 数字(但不是变量名的第一个字符)
  • 下划线(_)

表 2-1 显示了 JavaScript 中不能用作变量名的保留字。

表 2-1。JavaScript 中的保留字

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

表 2-2 显示了当前未被使用,但将来被使用的概率很高的单词。我们建议在命名变量时避免使用它们。

表 2-2。保留文字供将来使用

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

您不能使用 JavaScript 中预定义的任何其他单词,如Stringtrue等。完整名单请见www.javascripter.net/faq/reserved.htm

给变量赋值

一旦变量被声明,就可以给它赋值。要给num0num1赋值,请执行以下操作:

  1. Below the Listing 2-1 code you entered, type in the code shown in Listing 2-2.

    清单 2-2。 给变量赋值

    num0 = 100;
    num1 = 200;
    

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意变量可以通过使用

var num3 = 400;

添加变量

变量可以用来代替数字进行运算。如果使用变量执行算术运算,变量的当前值将用于计算。要将num0num1相加并将结果分配给sum,请执行以下操作:

  1. Below the Listing 2-2 code you entered, type in the code shown in Listing 2-3.

    清单 2-3。 添加变量

    sum = num0 + num1;
    

基本算术运算符

你不仅仅局限于添加变量或数字。所有基本的算术运算都可以执行。表 2-3 显示了基本操作符。

表 2-3 。基本算术运算符

操作员描述例子
+添加a + b(将 a 和 b 相加)
减法a–b(从 a 中减去 b)
*增加a * b(a 和 b 相乘)
/分开a/b(a 除以 b)
%剩余物a % b(a 除以 b 的余数。换句话说,7 % 4 = 3,因为 4 一次进入 7,余数为 3。)

运算符具有优先级:乘法和除法首先发生,然后才是加法和减法。要改变优先顺序,如果你想在计算其他部分之前计算特定部分,这可能是有用的,使用括号,如清单 2-4 所示。您不需要复制这段代码。仅供参考。

清单 2-4。 用括号改变操作顺序

var result0 = 1 + 2 * 3;        //result0 will be 7
var result1 = (1 + 2) * 3;      //result1 will be 9

检查变量的值

要查看sum的值,请执行以下操作:

  1. Below your current code, type in the code shown in Listing 2-5. The document.write() command tells the program to display whatever is within the parentheses on-screen, and uses the plus sign to combine, or concatenate, values together to display a final result. Commands like this are called methods, and can be identified by the parentheses at the end of the method name. The period before write indicates that it is a method of the document object, a predefined set of code allowing JavaScript to have access to the browser window. We’ll cover objects in more detail later.

    清单 2-5。 在屏幕上显示总和的值

    document.write("Total amount = " + sum);
    
  2. 单击运行按钮。(我们在下文中将其简称为 Run。)预览区应该显示“总金额= 300”。

如果你想对照一个完成的例子检查你的代码,你可以在http://code.9leap.net/codes/show/19823找到一个。

数据类型

为什么我们必须在清单 2-5 中的document.write()内放置的内容加上引号?这是因为document.write()只接受字符串值。字符串用于存储文本字符串,是 JavaScript 中五种基本数据类型之一。其中三种数据类型——数字、字符串和布尔——用于存储数据,而另外两种用于表示变量的当前状态。表 2-4 显示了五种数据类型。

表 2-4。基本数据类型

类型分配值用法示例
Number基数为 10var num = 10
基数为 8 (0 附加到值的开头)var num = 011:
基数为 16 (0x 附加到值的开头)var num = 0x 9a;
浮点,基数为 10(使用句点[。])凡 fnum = 3.1415
浮点,指数(使用句点[。]和 E)var fnum =-3.1 和 12;
Booleantruefalse其中标志= true
String用双引号或单引号括起来的字符串var str = “字符串”;
var str = ‘字符串’;
null已知该对象存在,但没有值var obj = null;
undefined对象不存在、不返回值或尚未初始化

除了基本的数据类型,JavaScript 中还有复杂的数据类型:

  • 对象:对象是多种基本数据类型和/或其他对象的集合,通常由开发人员预定义或定义。如果你要创建一个保龄球游戏,你很可能有多个对象代表保龄球瓶,另一个对象代表保龄球。
  • 数组:数组是一组索引有序的数据。在保龄球游戏示例中,您的保龄球瓶对象可以全部存储在一个数组中。添加到数组中的每一项都分配有一个数字,从 0 开始,每添加一项就增加 1。
  • 关联数组:关联数组是一组没有特定顺序的命名数据。与常规数组不同,关联数组可以将一个项与任何其他值或项配对在一起。想象一下,我们的保龄球游戏是 3d 游戏,保龄球瓶上方悬挂着几盏灯。关联阵列可用于将每个保龄球瓶与特定的灯连接在一起。
  • 函数:函数执行一个定义的计算或一组代码。在保龄球游戏的例子中,如果保龄球与瓶接触,可以使用一个函数来使保龄球瓶翻倒。

我们将在后面更详细地介绍复杂的数据类型。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意在 C/C++和 Java 这样的编程语言中,变量有静态数据类型(比如integer或者string),你不能把一种数据类型的值赋给另一种数据类型的变量。换句话说,如果你有一个integer变量,你不能给这个变量赋值一个字符串。

在 JavaScript 中,情况并非如此。任何数据类型的值都可以赋给一个变量,完全不同数据类型的变量可以在以后重新分配给同一个变量。名为foo的变量可以用foo = 10;赋一个数值,然后下一行可以声明foo = "bar";为同一个变量赋一个字符串值。这种灵活性是 JavaScript 的一个主要优点,但缺点是有时在执行计算时必须格外小心。稍后我们会看到这样的例子。

使用变量本身操作变量

许多游戏都包含一个分数,当玩家获得分数时,该分数会不断更新。要更新这个分数,包含它的变量必须增加。请执行以下操作来了解如何操作:

  1. 清除您编写的代码,直到清单 2-5 。

  2. Type in the code shown in Listing 2-6.

    清单 2-6。 通过引用自身操纵变量

    var score = 10;
    score = score + 20;
    document.write(score);
    
  3. 单击运行。预览屏幕应该显示“30”

  4. score = score + 20;替换为score += 20;

  5. 再次单击运行。结果是一样的。步骤 4 使用自引用操作的缩写形式,称为复合赋值操作符。

复合赋值运算符

复合赋值运算符是同时对一个变量赋值和另一个运算的运算符。表 2-5 显示了这些有用的操作符。

表 2-5。复合赋值运算符

操作员描述例子
+=添加a += 10(相当于 a = a + 10)
–=减法a –= 10(相当于 a = a–10)
*=增加a *= 10(相当于 a = a * 10)
/=分开a /= 10(相当于 a = a / 10)
%=剩余物a %= 10(相当于 a = a % 10)

使用增量操作变量

当变量需要增加值 1 时,可以使用更简短的操作符。执行以下操作来查看它的运行情况:

  1. 清除您当前的代码。

  2. Type in the code in Listing 2-7.

    清单 2-7。 声明并递增变量

    var num = 1;
    num++;
    document.write(num);
    
  3. 单击运行。预览屏幕应该显示“2”,表明++将 num 的值增加 1。

  4. 清除您当前的代码。

  5. Type in Listing 2-8.

    清单 2-8。 在一个语句内递增一个变量

    var num = 1;
    document.write(num++);
    num = 1;
    document.write(++num);
    
  6. 单击运行。屏幕首先显示“1”,然后显示“2”在类似于document.write()的语句中,如果增量运算符(++)在变量之后,那么document.write()语句将首先执行,如果运算符出现在变量之前,那么运算符将在document.write()之前执行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意增量运算符的反义词是减量运算符(--)。减量运算符的工作方式与增量运算符完全相同,只是它从附加的变量中减去 1。

比较变量

JavaScript 包含名为关系运算符的命令,比较两个值并根据结果返回布尔值truefalse。执行以下操作来查看它们的运行情况:

  1. 清除您当前的代码。

  2. Type in the code in Listing 2-9.

    清单 2-9。 比较数值

    var num0 = 4;
    var num1 = 7;
    document.write(num0 >= num1);
    document.write(num0 < num1);
    document.write(num0 === num1);
    
  3. 单击运行。屏幕先显示false,因为 4 不大于等于 7;显示true,因为 4 小于 7;又显示了false,因为 4 不等于 7。

表 2-6 显示了可用的关系运算符。

表 2-6 。关系运算符

操作员描述例子
==相等的a == b
===严格等价a === b
!=不等价答!= b
!==严格不等价答!== b
>大于a > b
>=大于或等于a >= b
<不到a < b
<=小于或等于a <= b

看看两个值有多相似

通过执行以下操作,查看等价(==)和严格等价(===)关系运算符有何不同:

  • 1.清除您当前的代码。

  • 2.  Type in the code in Listing 2-10.

    清单 2-10。 不同等价运算符

    var num0 = 4;
    var num1 = "4";
    document.write(num0 == num1);
    document.write(num0 === num1);
    
  • 3.单击运行。屏幕首先显示 true,因为如果被比较的值之一是字符串,则符号==会暂时将所有值转换为字符串。这叫做型转换。然后屏幕显示 false,因为===符号不执行类型转换。要评估为相同,比较值必须是相同的数据类型。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意等价运算符的反义词是不等价运算符(!=!==),它们执行几乎完全相同的运算。然而,!=操作符执行类型转换,而!==操作符不执行。

操纵比较

有时您会想要操纵比较如何解析(true / false)。要查看如何操作这些比较,请执行以下操作:

  • 4.清除您的代码。

  • 5.  Type in the code in Listing 2-11.

    清单 2-11。 操纵比较

    document.write(!(4 > 3));
    document.write((4 < 7) && (5 < 13));
    document.write((4 > 5) || (4 < 5));
    
  • 6.单击运行。

屏幕会先说false是因为语句(4 > 3)解析为true!逻辑运算符反转其后的布尔语句(true / false),使之成为false。然后屏幕列出true,因为(4 < 7)和(5 < 13)都评估为true。只有当它周围的两个语句都是true时,&& ( and)逻辑运算符才返回 true。最后屏幕再次显示true,因为在(4 > 5)和(4 < 5)中,有一个是true。如果至少有一个语句是true,则|| ( or)运算符解析为true。表 2-7 显示了逻辑运算符。

表 2-7。逻辑运算符

操作员描述例子
!false如果 a 是truetrue如果 a 是false! a
&&true如果 a 和 b 都是true,否则为falsea && b
&#124;&#124;true如果 a 或 b 为true,否则为falsea &#124;&#124; b

用 If 语句实现逻辑

有时,当且仅当满足特定条件时,我们希望在代码中执行特定的操作。请执行以下操作来了解如何操作:

  1. 清除您当前的代码。

  2. Type in the code in Listing 2-12.

    清单 2-12。 用 If 语句实现逻辑

    var num0 = 4;
    var num1 = 8;
    if (num0 >= num1) {
        document.write(num0 + " is greater than or equal to " + num1 + ".");
    }
    else if (num0 < num1) {
        document.write(num0 + " is less than " + num1 + ".");
    }
    
  3. 单击运行。屏幕将显示“4 小于 8”改变num0num1的值,看看如何改变结果。只有当第一条if语句评估为false ( num0 >= num1返回false)时,才会评估else if()语句。

创建一个对象

对象是一个结构,它可以包含自己的变量(称为属性)和方法。当它们属于一个对象时,它们被称为实例属性实例方法。要创建一个使您能够获取当前日期的对象,请执行下列操作:

  • 1.清除您的代码。

  • 2.  Type in the code in Listing 2-13. This code creates a variable as an instance of an object called the Date object, which contains methods that can give us information about the current date. The new Date() part of the code is called the constructor of the Date object, and by assigning it to a variable, you create the object.

    ***清单 2-13。***创建日期对象

    var date = new Date();
    
  • 3.  Type in the code in Listing 2-14. The methods of the date object return information about the year, month, or day of the current date. When getMonth() is called, 1 is added to the result because getMonth() counts January as 0, February as 1, and so on. Table 2-8 shows the methods that can be used with the Date object.

    清单 2-14。 给变量分配日期信息

    var y = date.getFullYear();
    var m = date.getMonth() + 1;
    var d = date.getDate();
    

表 2-8 。日期对象的方法

方法影响返回值
getFullYear()返回四位数的公历年{Number} 4 位数的公历年
getMonth()返回月份- 1(因为它是一个数组引用){Number}月 1 日
getDate()返回日期{Number}天
getDay()返回一周中的第几天一周中的第{Number}天
getHours()返回小时{Number}小时
getMinutes()返回分钟{Number}分钟
getSeconds()返回第二个{Number}秒
getMilliseconds()返回毫秒{Number}毫秒
  • 4.  Type in the code in Listing 2-15. You are concatenating multiple strings and values of the month, day, and year variables together into a single variable, text.

    清单 2-15。 创建一个字符串并显示它

    var text = "The date is " + m + "/" + d + "/" + y;
    document.write(text);
    
  • 5.单击运行。屏幕上会显示一个字符串,显示当前日期。如果遇到问题,可以在http://code.9leap.net/codes/show/19827查看完整的代码示例。

Date对象只是 JavaScript 预定义的众多对象之一。表 2-9 包含了一些与 JavaScript 捆绑在一起的主要对象。

表 2-9 。JavaScript 包含的主要对象

对象名称目标描述
窗户浏览器窗口
文件浏览器中的网页
设计网页中的框架
历史浏览器历史记录
位置当前页面位置
HTML 超链接
小应用网页中的嵌入式程序
区域图像上的可点击区域
形式Web 表单
图像网页上的图像
透明元素的图层
链接到外部样式资源
按钮可点击按钮
检验盒可标记的复选框
fileupload(文件上载)文件上传对话框
隐藏的隐藏密码
密码接受密码
收音机可标记单选按钮
重置清除表单中的选项
文本单行文本
链接区文本区域
挑选下拉菜单上的选择
排列值数组
布尔代数学体系的布尔值(true / false)
日期存储日期
事件随着事件(如单击)发生
功能功能(方法)
数学数值计算
航海家浏览器信息
数字存储一个号码
目标存储代码元素
正则表达式正则表达式
线字符串

这个庞大的对象列表乍一看可能令人望而生畏,但它只是作为一个快速参考。如果您想了解更多信息,请参阅 Mozilla Developer Network 的 JavaScript guide 中的“预定义核心对象”一节,这是一个关于 JavaScript 基本核心对象及其用途的极好资源。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意如果你熟悉 C/C++或 Java 等面向对象语言,你可能会熟悉的概念。在这些语言中,类充当对象的预定义模板。可以为给定的类定义属性和方法,然后从该类创建的所有对象都将继承这些属性和方法。

在 JavaScript 中,类的概念在技术上是不存在的,取而代之的是原型的概念。一个原型是一个特别指定的对象,可以为其定义属性和方法。当创建新对象时,它们可以从原型创建,并且将具有与原型相同的属性和方法。

起初,类和原型的概念可能看起来很相似,但是它们的限制是不同的。我们不会详细讨论基于类的编程和基于原型的编程,但主要的区别是从原型创建的对象可以用它们自己的函数定义覆盖预定义的原型函数,而作为类的一部分创建的对象通常不能这样做。

更智能地使用 While 和 For 循环语句

重复让你的编码生活变得更容易,因为在很多情况下,程序可以很容易地被设计来为你执行重复的任务。假设我们需要设计一种方法,将 1 到 1000 之间的所有数字相加,并将该值赋给一个变量(int)。如果我们手动添加 1 到 100 之间的每一个数字,我们最终会得到类似于清单 2-16 中的代码。

清单 2-16。 一种不切实际的将顺序数字相加的方法

int num = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100;

哎哟。这看起来不像是一种很实用的消磨时间的方式,不是吗?为了加快速度,我们可以使用loop语句来为我们执行这个重复的计算。要查看实际效果,请执行以下步骤:

  1. 清除您的代码。

  2. Type in the code in Listing 2-17 to first create a variable, i, which will be used to control the loop (in other words, the control variable), and then create two other variables to store the results from the upcoming loops.

    清单 2-17。 创建变量

    var i;
    var sumFor;
    var sumWhile;
    
  3. Create a while loop to add together all numbers from 1 to 100 by typing in the code in Listing 2-18 after your current code. First, you must give sumWhile a value of 0 because you will be using a self-referencing operator (+=) in your code, so it must have a value before you begin. Next, you give i a value of 1. This number represents both the first time through the while loop, and the first number to be added to sumWhile. Finally, you enter the while loop. At the beginning of the while loop, the program will check to see if i has a current value equal to or less than 100. If it does, it will move into the loop, add the current value of i to sumWhile, and then add one to i. The loop will then check again to see if i is less than or equal to 100 and start again. This will continue repeatedly until the last value, 100, is added to sumWhile.

    ***清单 2-18。***While 循环

    sumWhile = 0;
    i = 1;
    while (i <= 100) {
            sumWhile += i;
            i++;
    }
    document.write("The result using a while loop: " + sumWhile + "<BR />");
    

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意document.write()方法中的“< BR / >”是一个 HTML 标签(用括号括起来的 HTML 元素的名称,指定要插入的网页元素),它告诉系统在显示更多文本之前向下移动一行。

  4. 单击运行。屏幕将显示 5050 的结果。

  5. Now do the same thing with a different kind of loop, the for loop, by typing in the code in Listing 2-19 below your current code. The for loop has three statements at the beginning of it. The first (i = 1;) declares and creates a variable to control the loop. The second one (i <= 100;) is checked before the for loop is run or rerun, exactly the same as the statement at the beginning of the while loop. Finally, the last statement (i++) is run when a for loop completes, before the second statement is checked against for a rerun.

    ***清单 2-19。***For 循环

    sumFor = 0;
    for (i = 1; i <= 100; i++) {
            sumFor += i;
    }
    document.write("The result using a for loop: " + sumFor + "<BR />");
    
  6. 单击运行。屏幕将显示 5050 两次,因为两个循环计算的是相同的东西。如果遇到问题,您可以在http://code.9leap.net/codes/show/19828 .对照完整的代码样本检查您的代码

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 提示如果一个for语句只有一个命令,就像清单 2-19 中的一样,花括号就没有必要了。例如,清单中的for循环可以重写为

for (i = 1; i <= 1000; i++) sumFor = sumFor + i;

用 Break 中断循环

偶尔,在一个循环的执行过程中,我们希望停止处理该循环中的代码,并在循环结束后继续处理代码。这很容易用break语句来完成,该语句将当前处理从循环中断开,即使循环的条件仍然满足。要查看它的运行情况,请执行以下操作:

  1. 清除您的代码。

  2. Type in the code in Listing 2-20.

    清单 2-20。 打破循环

    var sumWhile = 0;
    var i = 1;
    while (true) {
        sumWhile += i;
        i++;
        if (i > 100) break;
    }
    document.write(sumWhile);
    
  3. 单击运行。结果和之前一样。当i等于 100 时,它被加到sumWhile,变成 101,然后因为它大于 100,while循环停止。

用 Continue 跳过循环迭代

在其他情况下,您可能希望跳过循环中剩余的代码,重新开始。只要满足了forwhile循环的条件表达式,就可以用continue语句来完成。发出该语句后,循环代码的下一次迭代将立即开始。像往常一样,在for循环中,当返回到循环代码的开始时,for循环的递增/递减表达式被执行。通过编写一个只计算从 0 到 100 的偶数的程序,执行以下步骤来验证这一点:

  1. 清除您的代码。

  2. Type in the code from Listing 2-21. The line if (i % 2 != 0) continue; says if the remainder after dividing i by 2 is not 0 (if i is odd), skip the remaining code in the current for loop iteration and begin the next for loop iteration immediately.

    清单 2-21。 利用继续跳过奇数

    var sumFor = 0;
    for (i = 1; i <= 100; i++) {
        if (i % 2 != 0) continue;
        sumFor = sumFor + i;
    }
    document.write("The sum of all even numbers up to 100 is " + sumFor);
    
  3. 单击运行。显示结果 2550。

生成随机数

如果你想让敌人角色随机出现在你的游戏中,或者如果你想创建一个游戏来告诉你当天的运气,并随机给你分配一个“运气”值,你需要能够创建随机数。执行以下操作,了解它在算命游戏中的工作原理:

  1. 清除您的代码。

  2. Type in the code in Listing 2-22 to create variables and assign a random number to num.

    清单 2-22。 为算命游戏创造变量

    var num;
    var text = "";
    num = Math.floor(Math.random() * 4);
    

    Math.random()返回一个从 0(包括 0)到 1(不包括 1)的值。将它乘以 4,得到一个从 0 到 4 的值,但不包括 4。Math对象的floor()方法将圆括号中的内容向下舍入。因此,您刚刚编写的代码将随机返回 0、1、2 或 3。

  3. Create the fortune-telling game using your random variable by typing in the code in Listing 2-23 below your current code.

    清单 2-23。 用 If 语句算命

    if (num===0) {
        text = "Super Lucky";
    } else if (num===1) {
        text = "So-so Luck";
    } else if (num===2) {
        text = "Minor Luck";
    } else {
        text = "Bad Luck";
    }
    document.write("Your fortune: " + text);
    

    这里,您根据num的值给text赋值,然后输出结果。

  4. 单击运行。你会随机得到一个关于你当前“幸运度”的回答

用开关定义场景

在最后一个代码示例中,使用了几个if语句来确定应该给text分配什么值。然而,有一种更简单的方法来实现这一点,不需要所有的if语句。请执行以下操作来了解如何操作:

  1. Delete the document.write() statement and all if statements. Your code should look as it does in Listing 2-24.

    清单 2-24。 为开关设置示例

    var num;
    var text = "";
    num = Math.floor(Math.random() * 4);
    
  2. Add the switch statement by typing in the code in Listing 2-25 below your current code.

    清单 2-25。 算命开关声明

    switch (num) {
            case 0:
                    textSwitch = "Excellent Luck";
                    break;
            case 1:
                    textSwitch = "Moderate Luck";
                    break;
            case 2:
                    textSwitch = "Small Luck";
                    break;
            default:
                    textSwitch = "Bad Luck";
                    break;
    }
    

    switch语句接受括号中的任何值,找到与该数字匹配的大小写,然后执行其下的代码。如果当前案例中没有break语句,switch 语句将继续执行下一个案例的代码,依此类推,直到遇到break语句或到达switch语句的结尾。如果没有找到匹配,则执行default案例。

  3. 单击运行。你会得到一笔随机产生的财富。

将编号数据存储在数组中

数组用于跟踪数据集,这在处理地图、字符串(文本字符数组)等时是必要的。执行以下操作,查看如何在数组中创建一组数字索引(编号)数据:

  1. 清除您的代码。

  2. Create an array to represent a collection of three devices by typing in the code in Listing 2-26.

    清单 2-26。 创建设备阵列

    var array = new Array(3);
    array[0] = "iPhone";
    array[1] = "Android";
    array[2] = "Computer";
    

    就像当我们创建一个Date对象的实例时,您使用一个构造函数来创建一个数组(new Array(3))。Array(3)告诉程序创建一个有 3 个空格的数组。

  3. Create a string to save parts of the array into it, and then iterate through the array, adding all of the array elements to the string before displaying it. Listing 2-27 shows how to do this.

    清单 2-27。 遍历一个数组

    var text = "";
    for (var i = 0; i < array.length; i++) {
        text += array[i] + "<BR />";
    }
    document.write(text);
    

    注意复合赋值操作符+=是如何被用来在字符串末尾添加字符的。使用一个for循环允许你自动遍历一个数组中的所有元素。

  4. 单击运行。屏幕将显示数组中的三个元素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意你不需要指定更大的数组来添加更多的条目到数组中。例如,在上面的例子中键入array[3]="iPad";不会导致错误。

数组对象的方法

在上一个示例中,您创建了一个数组对象。该对象带有几个可以在其上执行的方法。例如,如果您在代码末尾键入array.push("Galaxy");,它会将“Galaxy”添加到数组中最后一项之后的任何位置。表 2-10 提供了数组对象方法的总结。

表 2-10 。数组对象的方法

种类密码影响
添加元素push(元素)将元素添加到数组的末尾。
unshift(元素)将元素添加到数组的开头。
移除元素pop()移除数组末尾的元素。
shift()移除数组开头的元素。
排序元素sort()按升序对数组元素进行排序。
reverse()对数组中的元素进行逆序排序。
提取元素slice(开始,结束)提取指定开始和结束位置内的元素,并用它们创建一个新数组。
slice(开始)从指定的起始位置到数组的末尾提取元素,并用它们创建一个新数组。

在关联数组中存储无编号的数据

如果您想为刚刚创建的数组中的每个设备存储一种颜色,该怎么办?为此,您需要使用关联数组而不是常规数组。执行以下操作以创建关联阵列:

  1. 清除您的代码。

  2. Create your associative array by typing in the code in Listing 2-28.

    清单 2-28。 创建关联数组

    var obj = new Object();
    obj["iPhone"]     = "White";
    obj["Android"]    = "Black";
    obj["Computer"]   = "Silver";
    

    在 JavaScript 中,关联数组不是作为数组对象存储的,因为所有数组对象都是索引的,数组中的每个实体都包含一个键值(从 0 开始)和一个成对值。这里,我们使用 JavaScript 中对象作为值数组的能力,将设备名称和颜色的字符串链接在一起。

  3. Create a string, add the associative array objects, and then display the string by typing in the code in Listing 2-29.

    清单 2-29。 手动遍历关联数组

    var textObj = "";
    textObj += "The iPhone is " + obj["iPhone"] + ".<BR />";
    textObj += "The Android is " + obj["Android"] + ".<BR />";
    textObj += "The Computer is " + obj["Computer"] + ".<BR />";
    document.write(textObj);
    
  4. 单击运行。设备的颜色列表显示在屏幕上。

因为对象数组的索引方式不同于标准数组,所以不能用简单的for循环遍历它们。

使用功能节省时间

你已经见过自带函数的对象,比如数组,但是如果你打算做几乎任何需要你多次输入相同代码的事情,你可以定义你自己的函数来节省你的时间。请执行以下操作来了解如何操作:

  1. 清除您的代码。

  2. Define a function that accepts an argument (whatever is passed in parentheses), and then writes it on the screen after “I will buy the,” by typing in the code in Listing 2-30.

    清单 2-30。 定义购买()功能

    function buy(device) {
        document.write("I will buy the " + device + ".<BR />");
    }
    
  3. Call the function using “iPhone” and “Android” as arguments by typing in the code in Listing 2-31.

    清单 2-31。 调用功能

    buy("iPhone");
    buy("Android");
    
  4. 单击运行。屏幕将显示“我将购买”行两次,因为您调用了该函数两次。

查看变量的位置

我想让你想象一下,你要写的程序发生在一个中世纪的王国,有几个村庄和一座城堡。为了便于解释,假设这个王国的国王名叫鲍勃。在整个王国,如果有人谈论鲍勃,每个人都知道他们在谈论国王。然而,如果在一个给定的村庄里,还有一个叫鲍勃的人呢?在那个村子里,人们可能称当地居民鲍勃为“我们的鲍勃”,但在城堡里,如果有人称“鲍勃”,很可能每个人都会认为这个人就是国王。

这在本质上是范围的概念。它指的是程序中变量的可见性。换句话说,范围是变量的上下文。要了解其工作原理,请执行以下操作:

  1. 清除您的代码。

  2. Create a variable representing King Bob and assign him a value of 39 to represent his age by typing in the code in Listing 2-32. Because he is the ruler of the kingdom, we will create him as a variable at the beginning of the program, giving him a global scope. This means that if you type “bob” anywhere in the program, the program will know you mean King Bob.

    清单 2-32。 神树王鲍勃

    var bob = 39;
    
  3. Create a function that creates a variable representing a random Bob in one of the kingdom’s villages, assign him a random age between 10 and 50, and then increase that age by one to simulate the villager Bob celebrating his birthday, before displaying that Bob’s age on the screen, by typing in the code in Listing 2-33.

    清单 2-33。 创建函数创建随机 Bob

    function villager() {
            var bob = Math.floor(Math.random() * 50 + 10);
            this.bob += 1;
            document.write("King Bob's age is " + bob + ".<BR />");
            document.write("Villager Bob, this Bob, is " + this.bob + ".");
    }
    

    请注意,当您引用函数内部的 Bob 时,您使用this.bob来指定您指的是函数内部的那个。为了解释村民 Bob 的可见性,我们说他有函数作用域,而不是像 King Bob 那样有全局作用域。

  4. Call the villager function by typing in the code in Listing 2-34 below your current code.

    清单 2-34。 调用村民函数

    Villager();
    
  5. 单击运行查看结果。您将看到国王鲍勃的年龄为 39 岁,然后是村民鲍勃的随机年龄。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意你不能引用在一个函数之外的函数中创建的变量。这是函数范围的限制。例如,我们不能在函数外部键入this.bob来引用村民 Bob。在villager()之外,我们唯一能看到或与之互动的鲍勃就是鲍勃大王。

用原型制作物体蓝图

原型本质上是一套可以用来创造物体的蓝图。通过创建具有属性和方法的原型,我们可以轻松地创建具有原型中指定的相同属性和方法的新对象。要创建和使用包含名称和编程语言的软件原型,请执行以下操作:

  1. 清除您的代码。

  2. Create the prototype first as a function, and then add properties by typing in the code in Listing 2-35.

    清单 2-35。 创建原型和属性

    function Software() {
    }
    
    Software.prototype.name     = "";
    Software.prototype.language = "";
    
  3. Create a function for the prototype that displays information about it by typing in the code in Listing 2-36.

    清单 2-36。 创建原型功能

    Software.prototype.output = function() {
        document.write(this.name + " is written in " + this.language + "<BR />");
    };
    
  4. Type in the code in Listing 2-37 to create a new object, accounting, as an instance of the Software prototype; specify values for its properties; and then call its function to display information on the screen.

    ***清单 2-37。***创建会计对象

    var accounting = new Software();
    
    accounting.name     = "Spreadsheet Master";
    accounting.language = "Java";
    
    accounting.output();
    
  5. 单击运行。您将看到一条消息,说明 Spreadsheet Master 是用 Java 编写的。

  6. 尝试在accounting对象下创建另一个对象,并调用output()函数。如果你遇到麻烦,查看http://code.9leap.net/codes/show/19835中的工作示例。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意以前面的代码为例,用accounting作为对象名,在这里输入类似于accounting.secondLanguage = "C++";.secondLanguage之前没有用var或者任何东西声明过,就可以随时给这个对象添加属性。这是一份即时声明。使用accounting.showLanguage = function() {document.write(this.language)};功能也可以以类似的方式添加到对象中。

结论

恭喜你!如果您已经通读了本节并使用了 code.9leap.net 的示例代码,那么您现在应该对变量、运算符、字符串、数组、函数和原型有所了解。这些是 JavaScript 的构建块,也是当今使用的许多面向对象语言的构建块。理解这些基础知识为你学习如何在 enchant.js 中编写自己的 HTML5 游戏打下了基础。

在第三章中,我们深入研究了 enchant.js 库,了解了精灵、场景、标签、表面等等。这些是 enchant.js 提供的基本特性。随着我们在《??》第三章和《??》第四章中的进展,你会开始看到这些特性是如何结合在一起创造一个游戏的。

三、enchant.js 的基本特性

既然您已经熟悉了 JavaScript 的基础知识,那么您应该对 enchant.js 的元素如何交互以及为什么要以特定的方式编写元素有了更好的理解。在这一章中,我们从你开始创作游戏需要知道的 enchant.js 的基本概念开始,然后我们探索集成这些概念的项目。我们涵盖了继承和显示对象树,这是每个 enchant.js 游戏都存在的两个元素,然后我们涵盖了标签、精灵、表面、触摸事件和基于屏幕的界面元素。我们在练习中大量使用了 code.9leap.net。一旦你读完这一章,你将对游戏的主要组件以及如何创建它们有一个基本的了解。

汇总列表

  1. 遗产
  2. 查看游戏的元素
  3. 创建标签
  4. 创建精灵
  5. 用曲面绘制地图
  6. 使用触摸进行互动
  7. 使用 D-pad 进行互动

继承

在面向对象编程中,继承是将一个对象归类为一个更大类别的成员的关系。为了更好地理解这一点,想象一个苹果。苹果是一种水果,借用面向对象编程的术语,我们可以说它继承了水果的品质。例如,苹果像所有其他水果一样含有种子。这类似于面向对象编程中的继承。

可以继承和被继承的对象的一个例子是 节点。游戏中的每一个物品都被称为一个节点。图 3-1 显示了不同类型的节点及其分类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-1 。节点的分类

图中的每个项目都有自己的功能和属性。此外,每个项目还具有与层次结构中它上面的类别相同的功能和属性。例如,Node类包含一个名为moveBy(x, y)的函数,它移动节点的量等于作为 x 轴和 y 轴的参数传递的量。因为这个函数是Node类的一部分,所以一个EntityLabelSpriteMapGroup或者Scene都可以调用moveBy()。这叫继承。

查看游戏元素

创建游戏时,并不是游戏的所有部分都能立即看到。如果我们创建一个射击游戏,敌人出现在屏幕的顶部,并不是所有的敌人在游戏开始时都是可见的。如果是的话,这个游戏很可能要么太难被击败,要么很快结束。

相反,我们随着时间的推移在场景中创建和注册敌人,使他们可见。游戏中所有可见的元素都是称为显示对象树的对象层次结构的一部分。 显示对象树的根对象称为场景。创建游戏时,默认创建一个场景。这个默认场景被称为rootScene。可以创建多个场景,可以将多个对象注册到显示对象树中的场景,如图图 3-2 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-2 。显示对象树

如果rootScene是活动场景,只有注册到它的对象在屏幕上可见。注册到场景 1 或场景 2 的对象将不可见。通过向场景中添加对象,移除对象,以及改变哪个场景是活动的,我们可以改变游戏过程中屏幕上显示的内容。我们将通过本章后面提供的代码示例,用更多的实际操作细节来检验这一点。

创建标签

在游戏中有很多情况下需要在屏幕上显示文本,例如当用户的分数在游戏过程中发生变化,关卡有时间限制,或者主要角色有特定的生命值。任何出现在游戏中的文本,除了风格化的艺术,都应该存在于标签中。enchant.js 中的标签是以一种允许它们在字体、颜色和位置方面容易操作的方式创建的。

作为本节的初始练习,我们将完成创建一个 enchant.js 游戏所需的所有步骤,该游戏可以创建随机位置和颜色的标签。

设置游戏

当您编写创建和执行游戏的 JavaScript 时,您必须遵循特定的格式来初始化或激活 enchant.js 库,并指定页面加载后要运行的游戏代码。请按照以下步骤查看如何操作:

  1. Go to http://code.9leap.net/codes/show/27204 and fork the code to have a workable blank template. You might need to log in or create an account to do this.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意如果你没有使用 code.9leap.net,你需要将 enchant.js 库导入到你的项目中,这将在第一章中介绍。

  2. Type in the code shown in Listing 3-1.

    清单 3-1。 初始化 enchant.js 库

    enchant();
    

    这个命令告诉 enchant.js 初始化创建和运行游戏所需的所有代码。

  3. Under that, type in the code shown in Listing 3-2.

    清单 3-2。 创建 window.onload()

    window.onload = function() {
    }
    

这指示浏览器只有在加载了所有其他内容之后才运行花括号({})中的代码。这确保了在游戏真正开始之前,enchant.js 运行所需的一切都已存在。每个 enchant.js 游戏都必须有这两个组件才能运行。我们在花括号中输入了几乎所有的游戏代码。

制作核心物品并开始游戏

既然我们已经为我们的游戏完成了必要的基础工作,我们可以创建游戏的核心,即Core对象。Core对象是游戏本身,在创建时定义了游戏的大小。游戏的所有元素(场景、标签、精灵等等)都是在这个Core对象中创建的。要创建它,请执行以下操作:

  1. Modify your window.onload statement to match Listing 3-3. This creates the Core object, specifying the size of the game to be 320 pixels wide (first argument) by 320 pixels tall (second argument). Assume that all code instructions past this point should be entered within the curly brackets, beneath the last line of code entered unless stated otherwise.

    清单 3-3。 创建核心对象

    window.onload = function() {
            var game = new Core(320, 320);
    }
    

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意在 0.6 版本之前,Core对象被称为Game对象。如果你使用早期版本的 enchant.js 创建的游戏,你可能会看到使用Game对象而不是Core对象(var game = new Game(320,320))的符号。这种情况已经改变,因为 enchant.js 越来越多地用于非游戏应用。

    实际上,如果你遇到一个Game对象,你可以把它当作一个Core对象。

  2. Place your cursor at the end of the line that reads var game = new Core(320, 320); and press Enter a few times to move your cursor down a few lines. Type in the code in Listing 3-4. This command tells the game to start and should always appear at the end of your window.onload statement.

    清单 3-4。 开始游戏

    game.start();
    

创建标签

下一步是创建一个带有消息的标签。执行以下操作来创建一个:

  1. After the line var game = new Core(320, 320);, type in the code in Listing 3-5. This creates a label with the text we designate in quotes.

    清单 3-5。 创建标签

    var label = new Label("Hello World!");
    

将标签添加到根场景

如果此时单击 Run 按钮,将不会发生任何事情。正如我们前面提到的,游戏中的物体必须添加到活动场景中才能可见。执行以下操作来添加它:

  1. Type in the code in Listing 3-6 below the last line of code entered. This adds the label we created to the rootScene.

    清单 3-6。 给 rootScene 添加标签

    game.rootScene.addChild(label);
    
  2. 单击运行按钮。“你好世界!”出现在屏幕的左上角,因为标签现在是默认场景rootScene的一部分。

更改标签的属性

我们之前讨论了 enchant.js 中的对象如何拥有自己的属性,这些属性控制着游戏中这些对象的特征。要更改标签的特征,请执行以下操作:

  1. Above the line game.rootScene.addChild(label);, type in the code in Listing 3-7. This makes several changes to the appearance of the label.

    清单 3-7。 改变标签的属性

    label.font = "16px sans-serif";
    label.color = "rgb(255,0,0)";
    label.x = 50;
    label.y = 100;
    
  2. 单击运行。标签以不同的位置、字体和颜色出现。

格式化字体

在清单 3-7 中,我们用label.font = "16px sans-serif"改变了标签的字体。

指定的第一个属性是字体的大小。这由一个数字表示,以像素为单位指定字体的大小,后跟字母“px ”,两者之间没有空格。

接下来,指定字体的名称。可以使用预定义的字体名称(字体系列名称),如“MS PGothic”,但有些设备不包含这些字体。如果没有特定字体的设备试图呈现标签,用户可能会遇到错误。对于用户来说,错误从来都不是有趣的事情,这就是为什么你的字体最好使用通用名称,如下所示。请注意,衬线是字母末端的风格化点,最常见于印刷中使用的字母。

  • 无衬线字体:哥特式字体(无衬线)
  • 衬线:罗马字体(带衬线)
  • 单空间:固定宽度字体

格式颜色

在清单 3-7 中,我们用label.color = "rgb(255,0,0)";改变了标签的颜色。

enchant.js 中的颜色可以为标签和任何其他接受颜色的元素设置,使用任何对 CSS(级联样式表)中的颜色有效的格式。如果您不熟悉 CSS,请不要担心,因为我们将在这里介绍不同的格式。CSS 中有六种有效的颜色分配方式,如表 3-1 所示。由于该属性被定义为一个字符串,请确保将赋值用双引号("")括起来。

表 3-1 。不同的方式指定颜色红色

值(本例中为红色)描述
" #ff0000 "" #RRGGBB "格式。这些值在“00 FF”之间定义为以 16 为基数的数字。
" #f00 "“#RGB”格式。这些值定义在“0 \u F”之间,以 16 为基数。这种格式创建的颜色与“#ff0000”相同,只是一种缩写格式。
rgb(255,0,0)“rgb(R,G,B)”格式。这些值被定义为以 10 为基数的“0 \u 255”之间的数字。
" rgb(100%,0%,0%)"“rgb(R,G,B)”格式。这些值被定义为以 10 为基数的百分比,介于“0%∞100%”之间。
「rgba(255,0,1.0)」“rgba(R,G,B,A)”格式。RGB 定义在“0 \u 255”之间,透射率(alpha 透明度)定义在“0.0 \u 1.0”之间(0 表示完全透明,1 表示完全不透明)。
“红色”颜色由名称定义。

此外,表 3-1 中的大多数列表表示三种颜色的混合:红色、绿色和蓝色。为了指定红色,我们选择红色的最大值(以 16 为基数的 ff)和绿色和蓝色的最小值(以 16 为基数的 00)。在 16 进制中,0–9 与 10 进制相同(正常计数),然后 10 = A,11 = B,依此类推,直到 16 = F,16 进制中字母的大小写没有区别(也称为十六进制格式)。

定义位置

通过设置标签的 x 和 y 属性值来定义位置。在清单 3-7 中,我们用label.x = 50;将标签的位置设置为距离游戏屏幕左边缘 50 像素,用label.y = 100;设置为距离游戏屏幕上边缘 100 像素。

创建一个为我们创建标签的函数

优化是编程中的一个常见概念。这意味着使用尽可能少的代码,或者使用代码快捷方式,来创建一个游戏或其他应用。在我们的游戏中,我们将创建多个标签,因此创建一个为我们创建和配置标签的函数要比手动多次创建标签容易得多,而且这个函数可以被调用无数次。请执行以下操作来了解如何操作:

  1. Delete the code you wrote from Listings 3-6 and 3-7 and replace it with the code in Listing 3-8. This function will accept four arguments, create a Label with the text argument, specify the color to be whatever was indicated for the color argument, set the position with the x and y arguments, and then add the label to the rootScene.

    ***清单 3-8。***创建 addLabel 函数

    game.addLabel = function(text, color, x, y) {
            var label = new Label(text);
            label.font = "16px sans-serif";
            label.color = color;
            label.x = x;
            label.y = y;
            game.rootScene.addChild(label);
    };
    

    这本身不会产生标签。相反,它包含创建标签的说明。要创建标签,我们必须调用函数并提供参数。

  2. Under the preceding code, type in the code in Listing 3-9.

    清单 3-9。 调用 addLabel

    game.addLabel("50 Points", "rgb(255,0,0)", 50, 50);
    game.addLabel("100 Points", "rgb(50,0,100)", 50, 200);
    
  3. 单击运行。将出现红色标签和紫色标签。

创建随机数函数

为什么我们需要随机数?因为我们要给我们创建的标签分配随机属性,并且需要随机数来完成。执行以下操作创建随机数函数:

  1. Go to the very bottom of your code, below the last semicolon of the window.onload statement, and type in the code in Listing 3-10.

    清单 3-10。 随机数功能

    function rand(num){
            return Math.floor(Math.random() * num);
    }
    

floor()random()都是Math对象的方法,这是 JavaScript 中预定义的对象。rand()函数的定义接受一个参数num,该参数乘以Math.random()的结果。Math.random()将返回一个介于 0 和 1 之间的小数值。Math.floor将结果向下舍入到最接近的整数,然后该数字将作为rand()函数的结果返回(提供)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意十进制值Math.random()可以返回的范围包括 0 但不包括 1。例如,如果我们将Math.random()乘以 100,理论上可以返回的最小值是 0,理论上可以返回的最大值是非常接近 100 的值,但不完全是 100(换句话说,接近 99.99999999999)。用Math.floor()将它向下舍入,得到一个介于 0 和 99 之间的随机整数。

例如,如果我们调用rand(100),程序返回 0.88134 作为Math.random()的返回值,它将首先乘以我们指定的参数(100),变成 88.134。然后通过Math.floor()将其向下舍入到 88 并返回。创建这个函数的理由将在下一节中变得显而易见。

使用 ENTER_FRAME 事件监听器自动创建标签,并定期处理

现在我们已经有了轻松创建标签所必需的函数,我们需要能够以固定的时间间隔调用该函数的东西,也称为周期性处理。我们可以用一个事件监听器来做这件事。事件侦听器是代码的一部分,它不断地寻找特定的事件,当事件发生时,事件侦听器触发我们创建的特定代码。请执行以下操作来了解如何操作:

  1. Delete the two game.addLabel() statements you created in Listing 3-9 and replace them with the code in Listing 3-11. This code instructs the program to execute the code within the curly braces ({}) every time the ENTER_FRAME event occurs. This event occurs every frame.

    清单 3-11。 ENTER_FRAME 事件监听器

    game.rootScene.addEventListener(Event.ENTER_FRAME, function() {
    });
    

    您可以为任何Node对象(不仅仅是rootScene)创建事件监听器,并设置它们监听 enchant.js 中的任何事件。表 3-2 列出了 enchant.js 中的主要事件

    表 3-2。事件

    事件类型描述事件发布者
    Event.A_BUTTON_DOWN按下 a 按钮时发生的事件核心,场景
    EventA_BUTTON_UP释放 a 按钮时发生的事件核心,场景
    Event.ADDED将节点添加到组时发生的事件结节
    Event.ADDED_TO_SCENE将节点添加到场景中时发生的事件结节
    Event.B_BUTTON_DOWN按下 b 按钮时发生的事件核心,场景
    Event.B_BUTTON_UP释放 b 按钮时发生的事件核心,场景
    Event.DOWN_BUTTON_DOWN按下向下按钮时发生的事件核心,场景
    Event.DOWN_BUTTON_UP释放向下按钮时发生的事件核心,场景
    Event.ENTER场景开始时发生的事件事件
    Event.ENTER_FRAME处理新帧时发生的事件核心,场景
    Event.EXIT场景结束时发生的事件事件
    Event.EXIT_FRAME帧处理即将结束时发生的事件核心
    Event.INPUT_CHANGE按钮输入改变时发生的事件核心,场景
    Event.INPUT_END按钮输入结束时发生的事件核心,场景
    Event.INPUT_START按钮输入开始时发生的事件核心,场景
    Event.LEFT_BUTTON_DOWN按下左键时发生的事件核心,场景
    Event.LEFT_BUTTON_UP释放左键时发生的事件核心,场景
    Event.LOAD游戏加载完成时调度的事件核心
    Event.PROGRESS游戏加载期间发生的事件核心
    Event.REMOVED从组中删除节点时发生的事件结节
    Event.REMOVED_FROM_SCENE从场景中移除节点时发生的事件结节
    Event.RENDER呈现实体时发生的事件实体
    Event.RIGHT_BUTTON_DOWN按下右键时发生的事件核心,场景
    Event.RIGHT_BUTTON_UP释放右键时发生的事件核心,场景
    Event.TOUCH_END当与节点相关的触摸结束时发生的事件结节
    Event.TOUCH_MOVE当与节点相关的触摸移动时发生的事件结节
    Event.TOUCH_START与节点相关的触摸开始时发生的事件结节
    Event.UP_BUTTON_DOWN按下向上按钮时发生的事件核心,场景
    Event.UP_BUTTON_UP释放向上按钮时发生的事件核心,场景
  2. Type in the code in Listing 3-12 inside the curly braces to create and assign variables to represent a random score to be displayed; the value of red (in the RGB color component of the label), green, and blue; and the x and y position.

    清单 3-12。 创建变量并分配随机值

    var score = rand(100);
    var r = rand(256);
    var g = rand(256);
    var b = rand(256);
    var x = rand(300);
    var y = rand(300);
    
  3. Below the code you just entered, but still inside the curly braces, call the addLabel() function we created earlier, passing the random variables as the arguments of the function, by typing in the code in Listing 3-13.

    清单 3-13。 调用 addLabel()函数

    game.addLabel(score + " Points", "rgb(" + r + "," + g + "," + b + ")", x, y);
    
  4. 单击运行。标签可以在屏幕上快速创建。

使用帧和模数 减慢处理速度

标签的创建在这一点上可能看起来有点失控,因为在您单击 Run 按钮之后,不久整个屏幕就会完全充满标签。幸运的是,你可以放慢速度。请执行以下操作来了解如何操作:

  1. Enter the code you wrote in Listing 3-12 and 3-13 inside an if statement, as shown in Listing 3-14. Here, game.frame is equal to the number of frames that have elapsed in a game, and the modulo operator (%) will return the remainder after dividing the number of frames by 3. If that value is equal to 0, a label will be created. The final effect of this code is to cause a label to be created every third frame.

    清单 3-14。 控制标签创建的频率

    if (game.frame % 3 === 0) {
            var score = rand(100);
            var r = rand(256);
            var g = rand(256);
            var b = rand(256);
            var x = rand(300);
            var y = rand(300);
            game.addLabel(score + " Points", "rgb(" + r + "," + g + "," + b + ")", x, y);
    }
    
  2. 单击运行。标签的创建速度要慢得多。

指定时间后移除标签

现在创建标签的速度更慢了,但过不了多久,它们仍然会填满屏幕。要在标签创建后清除它,我们需要使用另一个事件监听器。

  1. Type in the code in Listing 3-15 under game.rootScene.addChild(label); (still inside the window.onload function curly braces). Here, we add an event listener to the labels we create, specifying to remove the label from the document object tree if the label’s age, or the number of frames the label has been part of the document object tree, exceeds 10 frames.

    清单 3-15。 去除标签

    label.addEventListener(Event.ENTER_FRAME, function() {
            if (label.age > 10) game.rootScene.removeChild(label);
    });
    

    你有没有注意到在if语句后面没有花括号?这是因为只有一个语句。如果没有花括号,if语句只触发后续的单行代码。

  2. 单击运行。标签是随机创建的,并在创建后不久从屏幕上删除。

使标签移动

作为标签的最后一个效果,我们希望它们在创建后向上移动。执行以下操作,指示它们每帧向上移动一个像素:

  1. Directly above the if statement you entered from Listing 3-15, but still within the event listener curly braces, enter the code from Listing 3-16. This simply reduces the y position of the label by one.

    清单 3-16。 移动标签

    label.y --;
    
  2. Because the ENTER_FRAME event listener executes its code every frame, the label moves up the screen at a rate of 30 frames every second, as the frames per second (fps) setting of the Core object is set to 30 fps by default.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意你可以通过修改Core对象的fps属性来改变每秒帧数的设置(换句话说就是game.fps = 16;)。

  3. 单击运行。标签会显示出来,并在消失之前在屏幕上向上移动。

标签用于显示游戏中的分数等,前面的练习简要介绍了如何创建标签。随着我们的继续,我们将更多地使用它们。如果你遇到任何问题,你可以在http://code.9leap.net/codes/show/27211找到一个完整的工作代码样本。

创建精灵

虽然也有例外,但大多数游戏都有一个主角,或者敌人,或者盟友,或者某种角色。这些角色由图像表示,通常以某种身份四处活动。在 enchant.js 中,角色由精灵表示。创建精灵时,它配备了许多属性和方法,使其更容易操作。

为精灵设置游戏

要为精灵设置游戏,您需要为精灵预加载图像并创建一个game.onload语句。执行以下操作,查看如何创建一个在屏幕上行走的熊精灵:

  1. http://code.9leap.net/codes/show/27204分叉空白的 enchant.js 模板。

  2. Type in the code in Listing 3-17 to create the basic structure of the game. Here, we use the preload function to load in the image of a bear to be used for the sprite. This image is included in the project on code.9leap.net and was included when you forked it in the preceding step.

    清单 3-17。 熊游戏的基本结构

    enchant();
            window.onload = function() {
            var game = new Core(320, 320);
            game.preload('chara1.gif');
    
            game.onload = function() {
    
            };
    
            game.start();
    };
    

这个代码示例还包含了game.onload函数,当加载图像或者不仅仅是添加和删除节点和事件监听器时,这个函数是必需的。这个函数类似于window.onload,在游戏完全加载后执行它的代码。

创建精灵

要创建 sprite,必须声明一个代表 sprite 的变量,必须给它分配一个图像,然后必须将其添加到文档对象树中。以下步骤向您展示了如何完成此过程:

  • 1.  Create a variable to represent a 32-pixel-wide by 32-pixel-tall sprite by typing in the code in Listing 3-18 inside the game.onload function. You can assume that all future references to placing code inside a function mean to place that code inside the curly braces at the end of that function.

    清单 3-18。 创建精灵变量

    var bear = new Sprite(32, 32);
    
  • 2.  Assign the image you preloaded in the last section by typing in the code in Listing 3-19 on the next line.

    清单 3-19。 将图像分配给图像属性

    bear.image = game.assets['chara1.gif'];
    
  • 3.  On the next line, add the bear to the rootScene to make it visible by typing in the code in Listing 3-20.

    清单 3-20。 使熊可见

    game.rootScene.addChild(bear);
    
  • 4.单击运行。这只熊出现在屏幕的左上角。

指定精灵的框架

如果您在这个项目中使用code.9leap.net,您将会看到chara1.gif在屏幕右侧以缩略图的形式出现。这张图片包含了几只熊的图片,那么为什么目前只有一只熊出现在我们的游戏中呢?答案与框架有关。

当你用Sprite(32,32)创建一个精灵时,程序会创建一个尺寸为 32×32 像素的精灵。当您将图像指定给精灵时,程序会将该图像分割成相同大小的帧,并从 0 开始用数字标识它们。这个概念被称为帧索引,如图 3-3 中的chara1.gif所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-3 。帧索引

通过将所需的帧数设置为 frame 属性,可以为 sprite 选择帧。为此,请执行以下操作:

  • 5.  Select the white standing bear as the frame by inserting the code in Listing 3-21 above the game.rootScene.addChild(bear); statement. Inserting the code after the addChild function carries the risk of the brown bear appearing onscreen and then switching to the image of the white bear.

    清单 3-21。 分配白熊帧

    bear.frame = 5;
    
  • 6.单击运行。精灵看起来像一只白熊。

制作精灵动画

我们有图像是很好的,但是一个画面的真正意义是创造运动的幻觉。最后,我们将指示熊在屏幕上来回移动,因为我们希望熊看起来像是在走路。在我们的 chara1.gif 图像中,有一些白熊的图像,我们可以快速连续显示来实现这一点。请执行以下操作来了解如何操作:

  1. Replace the bear.frame line you just added with the code shown in Listing 3-22. This notation is an array of numbers and acts as a shortcut for animation. For each frame, the frame will move to the next indicated frame in the sequence.

    清单 3-22。 动画熊

    bear.frame = [5, 6, 5, 7];
    
  2. 单击运行。熊精灵在帧中快速循环。这是我们的目标,但现在看来,这只熊似乎有点神经质。让我们让他慢一点。

  3. Rewrite your bear.frame statement to match the code in Listing 3-23. This slows down the rate of the frame change by assigning the same image for two frames instead of just one.

    清单 3-23。 减缓熊的定格

    bear.frame = [5,5,6,6,5,5,7,7];
    

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意不要使用清单 3-23 ,你可以在游戏开始前写一个game.fps = 16;语句,让游戏每秒处理 16 帧,而不是默认的 30 帧,来减缓熊改变帧的速度。请记住,这将降低游戏中所有实体的帧速率。

  4. 单击运行。为了行走,熊以更正常的速率改变帧。

移动精灵

精灵现在有适当的动画行走,但不移动。执行以下操作,在屏幕上移动小熊:

  1. Create an event listener on the bear sprite registered to the ENTER_FRAME event by typing in the code in Listing 3-24 under game.rootScene.addChild(bear);. Enter the code inside the curly braces of the game.onload function.

    清单 3-24。 在 Bear 上创建事件监听器

    bear.addEventListener(Event.ENTER_FRAME, function() {
    });
    
  2. Create periodic processing inside the event listener to move the bear to the right by increasing the x position by 3, as shown in Listing 3-25.

    清单 3-25。 动人的熊

    bear.x += 3;
    
  3. 单击运行。熊跑过屏幕。

  4. Create an if statement to move the bear only to the right if the bear’s location is less than the edge of the screen by modifying Listing 3-25 to match Listing 3-26. We use 320 – 32 because, while 320 is the edge of the right side of the game screen, the position of the sprite is measured from the top-left corner. When the sprite is at x = 320, the bear will not be visible. Since 32 is the width of the sprite, putting the limit of the bear at 320 – 32 ensures the bear stays onscreen.

    清单 3-26。 用 If 语句约束运动

    if (bear.x < 320 - 32) bear.x += 3;
    

确定精灵的方向以匹配其运动

让我们让熊精灵在屏幕上来回行走,面向它行走的任何方向。为此,我们使用了scaleX属性。请执行以下操作来了解如何操作:

  1. Insert the code in Listing 3-27 above the game.rootScene.addChild(bear); statement. The scaleX property defaults to the value of 1 when the sprite is created and can be modified to change the size of the bear (in other words, scaleX = 2; will scale the bear to 200%). By making scaleX a negative value, the image of the bear is flipped across the x-axis, making the bear face the left side of the screen.

    清单 3-27。 反转熊横过 X 轴

    bear.scaleX = -1;
    

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意使用sprite.scaleY = -1;可以在 y 轴上反转精灵图像。

  2. 单击运行。这只熊似乎在屏幕上向后走。这不是我们想要的最终结果,但是它让您了解了scaleX属性是如何工作的。我们将使用scaleX属性来指示熊在接下来的几个步骤中如何移动。

  3. 删除您在清单 3-26 中输入的代码。

  4. Replace the if statement (if (bear.x < 320 - 32) bear.x += 3;) in the bear’s event listener with Listing 3-28. This code sample specifies that if the bear is facing right, it should move to the right by 3 pixels for each frame and should be flipped to face left if the bear reaches the right side of the screen. If the bear faces left, the bear should move to the left by 3 pixels for each frame and should be turned around to face right again when it reaches the left side of the screen.

    清单 3-28。 定向熊

    if (bear.scaleX === 1) {
            bear.x += 3;
            if (bear.x > 320 - 32) bear.scaleX = -1;
    } else {
            bear.x -= 3;
            if (bear.x < 0) bear.scaleX = 1;
    }
    
  5. 单击运行。熊按照描述移动。

到目前为止,您应该已经熟悉了使用事件侦听器来处理每一帧上的代码。这是 enchant.js 中很多游戏的核心,如果你遇到任何 Sprite 代码的问题,可以在http://code.9leap.net/codes/show/27365找到完全工作的代码样例。

用曲面绘制地图

enchant.js 中的地图是由几个叫做 tiles 的小图像组成的。假设你正在创建一个游戏,背景是一片片绿草,一个角色在屏幕上来回移动。要在 enchant.js 中创建一个充满绿草瓷砖的地图,您需要首先将这些瓷砖添加到一个Surface对象中。

Surface对象是 enchant.js 中用于绘图的对象。绘画是指在一个物体上创造形状(这里不讨论)或图像的行为。一旦绘制了表面,就将其指定为 sprite 的 image 属性,以将其加入到显示对象树中。使用一个Surface对象允许在一个对象上绘制多个图像,这使得它成为显示地图的主要候选对象。在下面的代码示例中,我们创建了一个完全由绿草平铺组成的地图。

设置游戏

执行以下操作来设置一个使用Surface对象的示例游戏:

  1. http://code.9leap.net/codes/show/27204分叉空白的 enchant.js 模板。

  2. Set the groundwork for your game by typing in the code in Listing 3-29. The preloaded map0.gif file, shown in Figure 3-4, contains the component tile images that we will use to create the map.

    清单 3-29。 设置游戏

    enchant();
    window.onload = function() {
            var game = new Core(320, 320);
            game.fps = 16;
    
            game.preload('http://enchantjs.com/assets/img/map0.gif');
    
            game.start();
    };
    

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 3-4 。map0.gif

为地图创建容器

在我们用切片填充地图之前,地图必须有几个容器可以使用。执行以下操作来创建它们:

  1. Below the preload statement, type in the code in Listing 3-30. Here, we create a variable to act as the sprite, which will display the map. We assign our preloaded map image to the variable maptip, which makes it easier to reference later. Finally, we create a new Surface, which is what we will draw our map tiles on.

    清单 3-30。 创建容器

    game.onload = function() {
            var bg = new Sprite(320, 320);
            var maptip = game.assets['http://enchantjs.com/assets/img/map0.gif'];
            var image = new Surface(320, 320);
    };
    

用图块推广地图

draw()命令绘制一个Surface对象。在本节中,我们认为draw()命令是用来复制和粘贴图像到一个表面上的。由于我们的 16x16 瓷砖图像必须一次一个地粘贴到我们的空白表面上,我们可以编写一个很长的这些语句的列表来绘制瓷砖,但是使用循环来这样做可以节省我们的时间。执行以下操作来创建循环:

  1. Create two for loops to represent x and y coordinates by typing in the code in Listing 3-31 below var image = new Surface(320,320); but still inside the game.onload function.

    清单 3-31。 平铺循环

    for (var j = 0; j < 320; j += 16) {
            for (var i = 0; i < 320; i += 16) {
    
            }
    }
    

这一开始可能会令人困惑,但是将两个for循环放在一起是一个非常有用的工具,可以在一个Surface上增量移动,这正是我们在地图上以特定间隔放置图块所需要做的。

将变量ji分别视为空白背景上的虚拟光标的 y 和 x 坐标。想象一下这个空白背景被切割成 16 像素乘 16 像素的正方形,做成一个巨大的桌子。变量j代表我们假想的光标的行位置,变量i代表列位置。这个假想的光标总是指向一个 16 x 16 方块的左上角,因为那是所有使用draw()功能的操作的起点。

当进入第一个for循环时,j的值为0。然后进入第二个for循环,其中i也具有初始值0。我们假想的光标当前在(0,0),在表格的左上角。我们将在一个draw()命令中使用这个位置来复制一个图块,它还没有显示。在draw()命令之后,第二个for循环重复,这次i值为 16。我们的draw()命令现在将在(16,0)运行。如此重复,直到i变为 320。这时,第一排瓷砖将被绿色瓷砖填满。然后,重复第一个for循环,该过程从第二行开始,依此类推。

但是我们不要想太多。我们必须首先创建draw()命令,这样才能工作。

  • 2.   Inside the second for loop, create the draw() command to actually copy the tiles throughout the for loop by copying Listing 3-32 into the second for loop (for (var i = 0; i < 320; i += 16) {}).

    清单 3-32。 绘制命令复制图块

    image.draw(maptip, 0, 0, 16, 16, i, j, 16, 16);
    

是的,这个命令有很多参数。他们是这样做的:

  • maptip:这是要用作源图像的预加载图像资产(要在地图上使用的图块的图像)。
  • 0, 0:这是一个假想矩形左上角的 x 和 y 坐标,将用于从原始图像中捕捉一个区域。如果你想象在一幅图像上点击并拖动一个选择框来复制它的一部分,这将是点击的起点。
  • 16, 16:这是假想矩形右下角的 x 和 y 坐标,用来从源图像中捕捉一个区域。如果您单击并拖动来创建选择框,这些将是您放开单击的坐标。
  • i, j:目的地Surface上的 x 和 y 坐标,表示所拍摄图像粘贴位置的左上角。在调用几个draw()语句的过程中,通过for循环来改变这些值,以完美地分隔瓦片。
  • 16, 16:最后两个值表示要粘贴的图像的宽度和高度。如果这些从捕获区域的大小改变,它将在粘贴之前缩放图像。

将地图分配给背景并显示它

既然我们已经将图块复制到目的地Surface,我们需要将它添加到bg sprite 中,这样我们就可以将它添加到显示对象树中。

  1. Under the for loops, but still inside the game.onload function, type in the code in Listing 3-33.

    清单 3-33。 添加地图

    bg.image = image;
    game.rootScene.addChild(bg);
    
  2. 单击运行。地图出现,充满了绿色的草地瓷砖。

在 enchant.js 中,地图构成了许多游戏的背景。尽管创建地图的技术可能很难掌握,但熟悉地图对于创建更具沉浸感的游戏来说是无价的。

使用触摸进行交互

创建一个在草地上移动玩家的游戏的下一步是创建一个角色,当玩家点击屏幕时,他移动到屏幕上的那个点。这是通过用户点击游戏屏幕时发生的触摸事件来实现的。

创建角色

记住 enchant.js 中的游戏主要由每一帧运行的循环控制,这一点很重要。如果我们有一个角色在屏幕上走来走去,它将不得不为每个移动方向设置精灵,并进行相应的处理。请执行以下操作来查看这是如何实现的:

  1. At the very top of your code, before the enchant() command, add constants (values that will not change) by typing in the code in Listing 3-34. These values are used for specifying sprites for movement.

    清单 3-34。 创建方向常数

    var DIR_LEFT  = 0;
    var DIR_RIGHT = 1;
    var DIR_UP    = 2;
    var DIR_DOWN  = 3;
    
  2. Add chara0.gif (Figure 3-5) to the list of images to be preloaded by modifying the game.preload statement to the one shown in Listing 3-35.

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    图 3-5 。chara0.gif

    清单 3-35。 给要加载的图片添加 chara0.gif

    game.preload('http://enchantjs.com/assets/img/chara0.gif',
            'http://enchantjs.com/assets/img/map0.gif');
    
  3. Create a variable to represent our character, the girl from chara0.gif, and set the basic properties of that character by typing in the code in Listing 3-36 directly under game.rootScene.addChild(bg);. Setting the x and y coordinates to 160 – 16 causes the character to appear directly in the center of the screen. The frame is set to 7 to show the girl facing down first.

    清单 3-36。 塑造基础少女角色

    var girl = new Sprite(32, 32);
    girl.image = game.assets['http://enchantjs.com/assets/img/chara0.gif'];
    girl.x     = 160 - 16;
    girl.y     = 160 - 16;
    girl.frame = 7;
    
  4. Create secondary properties for the girl and add her to the document object tree by typing in the code in Listing 3-37 directly below the preceding code. The toX and toY properties are created to represent the location the girl will head toward when a player clicks the screen. The girl.anim array represents frame numbers used for animating the walking motion of the girl for all four directions.

    清单 3-37。 为女孩创造次级属性

    girl.toX   = girl.x;
    girl.toY   = girl.y;
    girl.dir   = DIR_DOWN;
    girl.anim  = [
            15, 16, 17, 16, //Left
            24, 25, 26, 24, //Right
            33, 34, 35, 34, //Up
            6,  7,  8,  7]; //Down
    game.rootScene.addChild(girl);
    
  5. 单击运行。女孩出现在草砖前的屏幕上。

处理触摸动作

最后一步是建立一个事件监听器,如果toXtoY与女孩的当前位置实质上不同,则移动女孩,并处理用户做出的触摸事件。请执行以下操作来了解如何操作:

  1. Create an event listener for the girl character to process movement by typing in the code in Listing 3-38 under game.rootScene.addChild(girl);. Like all ENTER_FRAME event listeners, this will be processed on the girl sprite for every frame.

    清单 3-38。 为女孩创建事件监听器

    girl.addEventListener(Event.ENTER_FRAME, function() {
    };
    
  2. Within the event listener you just added, create an if statement to process the upward movement of the girl by typing in the code in Listing 3-39. This code sample states that if the current Y position of the girl is lower (greater) than the girl’s destination (toY), the girl’s direction should be set as DIR_UP and the girl should be moved up by 3 pixels each frame, unless the girl’s current Y position is within 3 pixels of the destination. This is done by checking to see if the absolute value (Math.abs()) of the girl’s Y position minus the girl’s destination Y position is less than 3 pixels.

    清单 3-39。 加工向上运动

    if (girl.y > girl.toY) {
            girl.dir = DIR_UP;
            if (Math.abs(girl.y - girl.toY) < 3) {
                    girl.y=girl.toY;
            } else {
                    girl.y -= 3;
            }
    }
    
  3. Add the code to process the movement for the remaining directions (down, left, and right) by typing in the code in Listing 3-40 under the code you just added, but still within the girl’s event listener. This code uses the exact same approach as the preceding code to move the girl in the appropriate direction.

    清单 3-40。 加工其他方向的运动

    else if (girl.y < girl.toY) {
            girl.dir = DIR_DOWN;
            if (Math.abs(girl.y - girl.toY) < 3) {
                    girl.y = girl.toY;
            } else {
                    girl.y += 3;
            }
    }
    
    if (girl.x > girl.toX) {
            girl.dir = DIR_LEFT;
            if (Math.abs(girl.x - girl.toX) < 3) {
                    girl.x = girl.toX;
            } else {
                    girl.x -= 3;
            }
    }
    
    else if (girl.x < girl.toX) {
            girl.dir = DIR_RIGHT;
            if (Math.abs(girl.x- girl.toX) < 3) {
                    girl.x = girl.toX;
            } else {
                    girl.x += 3;
            }
    }
    
  4. Specify how the girl should be animated by adding Listing 3-41 directly under the last code you entered, still inside the girl’s event listener. This code sample states that if the girl is not moving, her age should be made to equal 1. Every frame, the girl’s age will increase; however, if she is standing still, her age will be reset to 1. This is used in the frame assignment on the next line to keep the girl from being animated if she is not moving. In the next line, the frame is assigned as a number from the array of values we specified earlier. The code means that the frame of the girl should cycle through the four frames of a given direction the girl is traveling in or facing.

    清单 3-41。 给女孩做动画

    if (girl.x == girl.toX && girl.y == girl.toY) girl.age = 1;
    girl.frame = girl.anim[girl.dir * 4 + (girl.age % 4)];
    
  5. Create the TOUCH_START and TOUCH_MOVE event listeners to capture clicks from the player and save those values to the girl’s toX and toY properties by modifying the last part of your code to match Listing 3-42. The two event listeners should be added inside the game.onload function, but outside the girl’s ENTER_FRAME event listener. Here, the TOUCH events are being passed into the functions as an argument (function(e)) and include the X and Y coordinates of where the touch event happens. Assigning those coordinates to the girl’s toX and toY properties (with -16 to center the girl) move the girl to the location being touched by the player.

    清单 3-42。 包括事件监听器进行触摸

                            ...if (girl.x == girl.toX && girl.y == girl.toY) girl.age = 1;
                            girl.frame = girl.anim[girl.dir * 4 + (girl.age % 4)];
    
                    });
    
                    bg.addEventListener(Event.TOUCH_START, function(e){
                            girl.toX = e.x - 16;
                            girl.toY = e.y - 16;
                    });
    
                    bg.addEventListener(Event.TOUCH_MOVE, function(e){
                            girl.toX = e.x - 16;
                            girl.toY = e.y - 16;
                    });
            };
            game.start();
    };
    
  6. 单击运行。女孩现在跟着屏幕上的鼠标点击,向他们走去。

本节介绍了一些用触摸事件控制精灵的复杂技巧。为你的精灵们启用这个能力将会为你的玩家们创造更流畅更有趣的游戏。

使用数字键盘进行交互

到目前为止,我们看到的玩家和游戏之间的唯一交互是触摸事件。然而,这并不是玩家与游戏互动的唯一方式。为了支持触摸事件之外的交互,enchant.js 附带了一个插件,用于将数字和模拟方向键(d-pads)放入游戏中。数字 d-pad(图 3-6 )只包含四个方向按钮(上、下、左、右),而模拟 pad 是由用户拇指操纵的控制杆。Playstation 2 和 3 控制器上的控制杆是现实生活中模拟垫的好例子。模拟板传递操纵杆相对于其中心的当前位置的 X 和 Y 值。本书不涉及模拟焊盘;相反,我们专注于数字键盘。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-6 。数字键盘

在本节的代码示例中,我们创建了一个数字 d-pad,为您提供了一个具有熊角色和地板的侧滚游戏的基础。按下 d-pad,使轴承向指定方向移动。

创建数字键盘

执行以下操作创建数字键盘:

  1. Fork the code at http://code.9leap.net/codes/show/27476 to create the basis of the game. If you are not using code.9leap.net, copy the code from Listing 3-43 into a new code file.

    ***清单 3-43。***D-Pad 游戏基础

    var STATUS_WAIT = 0;
    var STATUS_WALK = 1;
    var STATUS_JUMP = 2;
    
    enchant();
    window.onload = function() {
        //create game object
        var game = new Core(320, 320);
        game.fps = 16;
    
        //load images
        game.preload('http://enchantjs.com/assets/img/chara1.gif',
            'http://enchantjs.com/assets/img/map0.gif');
    
        //called when the loading is complete
        game.onload = function() {
            //create the background
            var bg = new Sprite(320, 320);
            bg.backgroundColor = "rgb(0, 200, 255)";
            var maptip = game.assets['http://enchantjs.com/assets/img/map0.gif'];
            var image = new Surface(320, 320);
            for (var i = 0; i < 320; i += 16) {
                image.draw(maptip, 3 * 16, 0, 16, 16, i, 320 - 16, 16, 16);
            }
            bg.image = image;
            game.rootScene.addChild(bg);
    
            //The d-pad should be created below this line
    
            //create bear
            var bear = new Sprite(32, 32);
            bear.image  = game.assets['http://enchantjs.com/assets/img/chara1.gif'];
            bear.x      = 160 - 16;
            bear.y      = 320 - 16 - 32;
            bear.status = STATUS_WAIT;
            bear.anim   = [10, 11, 10, 12];
            bear.frame  = 10;
            game.rootScene.addChild(bear);
    
            //frame loop for the bear
            bear.addEventListener(Event.ENTER_FRAME, function() {
    
                //frame setting
                if (bear.status == STATUS_WAIT) {
                    bear.frame = bear.anim[0];
                } else if (bear.status == STATUS_WALK) {
                    bear.frame = bear.anim[bear.age % 4];
                } else if (bear.status == STATUS_JUMP) {
                    bear.frame = bear.anim[1];
                }
            });
        };
    
        //start game
        game.start();
    };
    

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 注意D-pad 需要加载ui.enchant.js 插件。这显示在 code.9leap 示例中的 index.html 文件中,包括在调用 enchant.js 游戏脚本的 index.html 文件的文件头中添加<script src='/static/enchant.js-latest/plugins/ui.enchant.js'></script>或类似的指针。

  2. Create the D-pad by typing in the code in Listing 3-44 under the comment line that says //The d-pad should be created below this line. This creates the D-pad at (0,220).

    清单 3-44。 创建一个数字键盘

    var pad = new Pad();
    pad.x   = 0;
    pad.y   = 220;
    game.rootScene.addChild(pad);
    
  3. 单击运行。D-pad 出现在屏幕的左下角。

用 D-Pad 处理移动

您已经创建了 D-pad,但是您仍然需要对它进行编程来移动熊。请执行以下操作:

  1. Tie the D-pad in with the movement of the bear by adding Listing 3-45 to the inside of the Bear’s ENTER_FRAME event listener (directly under bear.addEventListener(Event.ENTER_FRAME, function() { }. This ties in the input from the d-pad with commands to move the bear.

    清单 3-45。 用 D-Pad 加工运动

    //up
    if (bear.status != STATUS_JUMP) {
            bear.status = STATUS_WAIT;
            if (game.input.up)  {
                    bear.status = STATUS_JUMP;
                    bear.age = 0;
            }
    }
    
    //left
    if (game.input.left)  {
            bear.x -= 3;
            bear.scaleX = -1;
            if (bear.status != STATUS_JUMP) bear.status = STATUS_WALK;
    }
    
    //right
    else if (game.input.right) {
            bear.x += 3;
            bear.scaleX =  1;
            if (bear.status != STATUS_JUMP) bear.status = STATUS_WALK;
    }
    
    //when jumping
    if (bear.status == STATUS_JUMP) {
            if (bear.age < 8) {
                    bear.y -= 8;
            } else if (bear.age < 16) {
                    bear.y += 8;
            } else {
                    bear.status = STATUS_WAIT;
            }
    }
    
  2. 单击运行。D-Pad 现在控制熊的移动。

与触摸事件一样,d-pad 可用于移动字符,如果您不想通过触摸事件来定位,它是一个有用的元素。如果你想给你的游戏一种复古的感觉,它们特别有用。

结论

关于 enchant.js 基础的章节到此结束。我们已经使用代码示例创建了标签、精灵、表面、触摸事件和虚拟面板。你现在已经为在 enchant.js 中创建自己的基本游戏打下了坚实的基础。当你创建自己的游戏时,你可能不会使用我们检查过的所有元素,但很有可能你会至少使用其中的一些,因为大多数 enchant.js 游戏都使用标签和精灵。

在下一章中,我们将介绍 enchant.js 的一些更高级的功能,例如在场景之间导航,添加开始屏幕和游戏结束屏幕,创建高级地图,以及建立声音播放。这些工具允许你把你的游戏带到一个更高的复杂和创造性的水平。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值