七、创建一个独立的三维游戏
我们在第六章中创造的街机射击游戏就是一个二维游戏的例子。标准 enchant.js 游戏中的精灵、标签甚至场景都存在于一个平面上,就像游戏中只存在 x 和 y 轴一样。尽管我们可以将实体堆叠在彼此之上,但这只是为了操纵可见性。没有可以控制的“深度”。
Enchant.js 附带了一个名为 gl.enchant.js 的插件,可以创建三维游戏。在本章中,我们将探索如何使用 gl.enchant.js 来创建我们之前创建的打地鼠游戏的 3d 版本。在路上,我们讨论了 gl.enchant.js 的基本主题,即 3-D 场景、3-D 相机和 3-D 精灵。
然而,在我们进入 3d 游戏之前,让我们再来看看如何在code.9leap.net
之外创建自己的 enchant.js 游戏,并简单探索一下从头开始创建一个 enchant.js 游戏需要什么。在撰写本书时,code.9leap.net
支持 enchant.js 插件的大部分功能,但不是全部。我们需要在 3d 版的打地鼠游戏中使用其中一个函数。
单机游戏
到目前为止,为了简单起见,实际上我们所有的代码示例和指令都推荐使用code.9leap.net
。这是一种跟踪代码和动态开发的简单方法。也就是说,为了让你的游戏开发更上一层楼,如果需要的话,了解如何从头开始组装一个 enchant.js 游戏是很重要的。
你可能需要或想要创建一个单机游戏的原因有很多。首先,因为code.9leap.net
处于测试阶段,某些文件格式不支持上传到项目中。目前,3d 模型文件不能上传到code.9leap.net
项目中。这就是为什么当你制作一个 3D 游戏时,它不能写在code.9leap.net
里面。创建一个单机游戏而不是在code.9leap.net
上运行的另一个原因是在你自己的网站上运行它。
从头开始创建游戏包括在您的计算机上本地准备游戏所需的所有文件。虽然游戏创作和测试可以在标准的本地文件上完成(换句话说,双击 index.html 文件在浏览器中打开它),但一些功能,如从文件中加载 3d 数据,需要浏览器有证据表明该文件正被 web 服务器访问。这是由于被称为同源策略 的安全限制。
同源策略
同源策略是一种安全措施,用于限制脚本加载某些文件的能力。在 enchant.js 游戏中,通常受策略影响的文件是那些包含声音或 3d 数据的文件。但是,最好将除图像之外的所有文件都视为受此策略限制。根据您的浏览器,可以使用特定的命令或设置来覆盖同源策略。
铬
在 Chrome 中,你可以用一个特定的参数打开 Chrome 来覆盖同源策略。打开终端(Mac)或命令提示符(Windows)并键入以下内容:
- Mac :
open /applications/Google\ Chrome.app --args --allow-file-access-from-files
- Windows??:
火狐浏览器
在 Firefox 中,您可以通过设置来覆盖同源策略:
- 在地址栏中输入
about:config
。如果 Firefox 警告您更改这些设置可能会影响浏览器的性能,请单击以接受警告消息。 - 在地址栏下出现的搜索框中,键入
origin
。 - 双击 security . file uri . strict _ origin _ policy 将值设置为
false
。
旅行队
Safari 还支持禁用同源策略:
- 进入 Safari 偏好设置(Safari
偏好设置(Mac),文件
偏好设置(Windows)),点击高级选项卡,勾选菜单栏中显示开发菜单的复选框。
- 关闭“设置”窗口,点按“开发”菜单,然后选取“停用本地文件限制”。
微软公司出品的 web 浏览器
我们强烈建议不要在 Internet Explorer 中开发游戏,因为 HTML5 的一些功能不受支持。
虽然禁用同源策略是一种快速解决方案,但我们建议为较大的开发项目安装 web 服务器。这将有助于更容易地过渡到最终版本。
本地 web 服务器
本地网络服务器 允许组成一个网站的文件以类似于从互联网上的标准服务器访问文件的方式被访问。网上有各种免费的服务器模拟器。仿真器是硬件的虚拟版本。您可以下载并运行带有仿真软件的虚拟服务器,而不是让物理服务器运行网站。这使得在网站上工作更容易,因为你不需要上传你的文件到互联网上的服务器来测试它。我们在http://sourceforge.net/projects/xampp/
向 Windows、Mac 或 Linux 推荐 XAMPP,在http://www.mamp.info/
推荐 MAMP,后者仅适用于 Mac。这些模拟器是免费的,很容易获得。
在这个练习中,我们使用 XAMPP,但是如果你熟悉的话,也可以使用其他的网络服务器。
设置
首先,从 SourceForge 的项目页面下载并安装 XAMPP,如图 7-1 所示。
图 7-1 。SourceForge 项目 XAMPP 官方页面(【http://sourceforge.net/projects/xampp/】??
如果您在安装时遇到任何问题,或者如果您想了解更多关于 XAMPP 的技术细节,您可以在http://www.apachefriends.org/en/xampp-macosx.html
(Mac)或http://www.apachefriends.org/en/xampp-windows.html
(Windows)找到官方文档和安装说明。安装后打开 XAMPP,确保 Apache 旁边的指示灯是绿色的,或者 Apache 服务已经启动,然后再继续。
一旦安装了 XAMPP(或另一个 web 服务器包)并且它当前正在运行,导航到 web 服务器的根文件夹。如果你在 Mac 上使用 XAMPP,你可以在/Applications/XAMPP/htdocs/
(Mac)或C:\xampp\htdocs
(Windows)访问它。这是你放置游戏所有文件的地方。例如,如果你把一个名为index.html
的文件放入这个htdocs
文件夹,你就可以通过浏览器访问http://localhost/index.html
来查看它。
3d 游戏
2d 游戏基于在平面空间移动的实体,而 3d 游戏基于深度。对于玩家来说,这意味着有更多的东西可以看,有更多的角度可以看。游戏空间存在于三维空间中:长度、宽度和高度(x、y 和 z)。这种环境支持从任何角度查看其中的对象。然而,对于程序员来说,这意味着游戏创建过程更加复杂。
虽然 3-D 游戏的好处包括创造一个更加身临其境的环境的可能性(换句话说,让玩家通过一个可以移动和环视游戏世界的虚拟角色的眼睛来看),3-D 也可以用来创建简单的游戏,并通过视觉升级来增强。具体来说,通过在游戏过程中改变相机的位置,你可以创建一个深度级别,与在 enchant.js 中创建的大多数游戏相比,这在视觉上令人印象深刻。
当你创建一个三维的游戏时,你需要考虑比二维游戏更多的变量。许多发生在 3d 游戏中的事件不能使用与 2d 游戏中相同的函数来创建。因此,在 enchant.js 中有一套完全独立的插件来创建 3d 游戏。
创建一个 3d 的重击机器人游戏
在本章的游戏制作练习中,我们制作了一个之前制作的 3d 版的重击机器人游戏。为此,我们使用 gl.enchant.js 并学习如何实现 GL . enchant . js 3d 游戏的各种元素,包括 3d 场景、3d 摄像机和 3d 精灵。图 7-2 显示了游戏完成后的样子。
图 7-2 。3d 重击机器人
我们一步一步地完成这个游戏的创作。我们开始吧!
-
转到
http://enchantjs.com/?p=731
并下载第七章的的 WhackADroid3D-initial zip 文件,并将其解压缩到您的本地 web 服务器正在使用的目录中。另一个文件 WhackADroid3D-Steps 位于 WhackADroid3D-initial zip 文件下的页面中,该文件包含本章中每个主要步骤之后显示的全部源代码。与命名文件夹相对应的步骤(换句话说,步骤 1->/步骤 1/)在本章的代码列表中有标记。 -
Open
index.html
in a text editor and make sure the code matches the code in Listing 7-1.清单 7-1。【index.html】包含插件引用
<html> <head> <title>Whack-A-Mole 3D</title> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="lib/glMatrix-1.3.7.min.js"></script> <script type="text/javascript" src="lib/enchant.js"></script> <script type="text/javascript" src="lib/nineleap.enchant.js"></script> <script type="text/javascript" src="lib/gl.enchant.js"></script> <script type="text/javascript" src="lib/collada.gl.enchant.js"></script> <script type="text/javascript" src="lib/primitive.gl.enchant.js"></script> <script type="text/javascript" src="main.js"></script> <style type="text/css"> body { margin: 0; } </style> </head> <body> </body> </html>
下面的列表显示了加载的不同插件,并对每个插件进行了解释:
-
glMatrix-1.3.7.min.js :一个开源的 JavaScript 库,包含了用 gl.enchant.js 执行各种操作所必需的数学计算。
-
nine leap . enchant . js:enchant . js 的 9leap 插件,我们在这里用它来显示游戏开始和结束画面。
-
GL . enchant . js:enchant . js 的核心 WebGL 使能插件*
-
collada.gl.enchant.js :允许在 collada(.dae)格式加载到 enchant.js 游戏中。
-
primitive.gl.enchant.js :包含几个预先制作的 3d 对象,可以在 3d 游戏中使用。
-
WebGL 是一个 JavaScript API(或接口),它允许网页中的元素,特别是 canvas 元素——它是用于绘制图形的 HTML5 网页的一部分——与计算机的显卡通信,以通过硬件加速来渲染这些图形。enchant.js 插件,允许在 enchant.js 游戏中使用 WebGL,gl.enchant.js,附随 enchant.js 包,主要用于用 enchant . js 制作 3d 游戏。
如果这些插件中的任何一个缺失,你将会在游戏中遇到问题,所以在继续之前确保它们都在代码中。
创建场景 3D 和灯光
就像普通的 enchant.js 游戏一样,3d enchant . js 游戏也需要一个场景,在这个场景中所有的事情都会发生。然而,这些场景被归类为“场景 3D ”,以表明它们在代码中的 3d 性质。当你创建一个新的场景 3D 时,你是在告诉 enchant.js 初始化并创建一个三维空间,该空间将支持向其中添加对象。
-
1. Open
main.js
, which should be empty, and type in the code in Listing 7-2 to set up the basics of the game. Notice how there is nothing new here just yet.清单 7-2。 三维游戏的框架
enchant(); var game; window.onload = function(){ game = new Core(320, 320); game.fps = 60; game.onload = function(){ }; game.start(); };
-
2. Inside the
game.onload
function, create a newScene3D
by typing in the code in Listing 7-3.清单 7-3。 创建场景 3D
scene = new Scene3D();
Scene3D
创建一个维度空间,如图图 7-3 所示。图 7-3 。场景 3D
三维空间中的点被指定在一组括号(x,y,z)内的 x,y 和 z 轴上。如果从 x = 0,y = 0,z = 10 的某一点看三维空间中的原点(x = 0,y = 0,z = 0),x 轴将从左(-x)到右(+x),y 轴将从下(-y)到上(+y),z 轴将从屏幕内部(-z)到屏幕外部,朝向您(+z)。
这就是所谓的右手系统。如果你伸出拇指和前两个手指,每个手指与其他两个手指成 90 度角,想象你的拇指代表 x 轴,你的食指代表 y 轴,你的中指将形成 z 轴。每个手指代表每个轴的正方向。在左手系统中,z 轴的正方向会指向远离你的方向。
需要注意的是,这个坐标系不同于标准 enchant . js 2d 游戏中确定位置的方式。在正常的二维环境中,屏幕的左上角被指定为(0,0),值在该点的右侧和下方增加。在三维系统中,原点或(0,0,0)被认为是环境的中心,如图图 7-3 所示。正因为如此,正值和负值都是常见的。
-
3. Under the creation of the new
Scene3d
, but still inside thegame.onload
function, type in the code in Listing 7-4 to create a new directional light.清单 7-4。 创建平行光
scene.setDirectionalLight(new DirectionalLight());
平行光只是创建一个光波阵列,从场景中的物体反射回来。这些光波中的一部分被物体反射,可以被其他物体(如相机)拾取,从而让玩家可以看到它们。在写这本书的时候,没有参数的平行光是在默认点(0.5,0.5,1)创建的。从这个缺省点,画一条线到场景的原点(0,0,0)。从这条线的方向,产生了虚拟光波,在整个场景中平行于这条线传播,如图 7-4 中的所示。
图 7-4 。从右上角开始的方向光源的二维表示
我们也可以通过写(var light = new DirectionalLight(); scene.setDirectionalLight(light);
)而不是(scene.setDirectionalLight(new DirectionalLight());
)来创建平行光。如果你使用这个var
方法,你可以将光源的原点从默认位置(0.5, 0.5, 1
)改变到另一个具有directionX
、directionY
和directionZ
属性的位置。
创建照相机 3D
尽管我们现在有了场景和平行光,我们仍然需要一个观察场景的视角。如果我们在三维空间中有物体,物体看起来如何将取决于我们从哪里看它。这些视点在 gl.enchant.js 中被指定为Camera3D
对象。它们从平行光拾取场景中对象反射的虚拟光波。
-
1. Create a
Camera3D
by typing in the code in Listing 7-5 under the creation of theDirectionalLight
, but still insidegame.onload
.清单 7-5。 创建新的摄像机 3D
camera = new Camera3D(); camera.y = 1.1; camera.z = -1.65; camera.centerZ = -10; camera.upVectorZ = 10; camera.upVectorY = 100;
摄像机在创建时有一个默认位置(0,0,10),所以我们在图 7-5 的中添加了,摄像机位于(0,1.1,-1.65)。相机对象还具有属性centerX
、centerY
和centerZ
。这些值指定了相机应该“注视”或指向的点。
图 7-5 。屏幕上显示一个机器人
如果相机位于一个点,并指向另一个点,相机可以在任何方向旋转,仍然指向指定的坐标。这样想:如果我正倒着看着你,我还在看着你。这就是为什么有“上向矢量”属性。这些属性指定了一个点,相机应该将该点视为“向上”通过改变上矢量,相机(以及相机的视图)可以轴向旋转。
你可以随心所欲地在三维空间中放置物体和摄像机。可以毫无问题地创建多个摄像机。只要相机指向你在三维场景中创建的实体,你就能看到它们。你可能需要调整你的相机来获得你想要的物体的视图,但是最好的方法是练习。
虽然我们现在已经创建了相机,指定了它应该存在的位置,应该指向什么,哪个方向是向上的,但我们仍然需要告诉Scene3D
使用它。
-
2. Make the scene use our new camera as the view for the player by typing the code in Listing 7-6 beneath
camera.upVectorY = 100;
, but still inside thegame.onload
function.清单 7-6。 指定场景的摄像机
scene.setCamera(camera);
如果Scene3D
内有多个Camera3D
对象,可以随时调用此函数(setCamera
)在它们之间切换。
创建三维精灵
精灵也作为Sprite3D
对象存在于 gl.enchant.js 中,并包含许多类似的属性和功能。在我们的游戏中,我们创建了多个机器人角色,每个角色都是Sprite3D
的一个实例。为了避免我们每次需要另一个机器人时手动创建一个新的Sprite3D
实例,让我们创建一个包含所有必要变量的Droid
类,然后在需要机器人时调用它。为此,请执行以下操作:
-
In the
window.onload
function, undergame.fps=60;
, add a line to preloaddroid.dae
by typing in the code in Listing 7-7. This file was included in the download package earlier and is a 3-D model of the Droid image.清单 7-7。 预压 droid.dae
game.preload('img/droid.dae');
以结尾的文件。dae 采用一种称为 Collada 的格式。Collada 是一种用于保存三维数据的文件格式,大多数主流三维建模软件都支持它。Collada 文件甚至可以用 Adobe Photoshop 打开。
-
Above the
window.onload
function, create theDroid
class as an extension of theSprite3D
class by typing in the code in Listing 7-8. Theinitialize
function should include arguments forx
,y
, andz
, which represent the position of the Droid on the x, y, and z axes respectively.清单 7-8。 创建机器人类
var Droid = Class.create(Sprite3D, { initialize: function(x, y, z) { } });
-
Inside the initialize function, make
Droid
an instance of theSprite3D
class and set it to use the Collada file as its model by typing in the code in Listing 7-9. Notice how when working withSprite3D
, the image is not set through theimage
property, but rather through theset
function.清单 7-9。 调用 Sprite3D 并设置 Collada 文件
Sprite3D.call(this); this.set(game.assets["img/droid.dae"]);
-
In its current form, the
droid.dae
file is too large, so scale it to 30 percent by typing in the code in Listing 7-10 on the next line.清单 7-10。 缩放机器人
this.scaleX = 0.3; this.scaleY = 0.3; this.scaleZ = 0.3;
-
Assign the arguments
x
,y
, andz
to theirSprite3D
counterparts by typing in the code in Listing 7-11.清单 7-11。 分配 x、y、z
this.x = x; this.y = y; this.z = z;
-
Inside the
game.onload
function, under the linescene.setCamera(camera);
, add a newDroid
to theScene3D
by typing in the code in Listing 7-12.清单 7-12。 给场景 3D 添加一个新机器人
scene.addChild(new Droid(0, 0, -8));
-
Save the file you are working on (
main.js
), but do not close it. If you are using a virtual web server, open up a web browser other than Internet Explorer and go to the path where index.html is stored (most likelyhttp://localhost/index.html
). Your screen should appear as it does in Figure 7-5.如果您在本节的代码中遇到任何问题,您可以在本章前面提到的 zip 文件的 Step2 文件夹中找到一个工作代码示例。
我们现在有了一个合法的、可见的 3d 精灵,但是为了让它更接近真实的游戏,我们需要添加一些交互性。
机器人互动
我们需要一些互动来使这成为一个真正的游戏。执行以下操作,让游戏进入下一步:
-
1. Near the top of the code, under var
game;
, type in the code in Listing 7-13 to create a function to generate random numbers and some variables we’ll use to keep track of the total number of Droids.清单 7-13。 创建随机数函数和变量
function rand(n) { return Math.floor(Math.random() * n); } //Variables to keep track of droids var maxDroid = 100; var hitDroid = 0; var combo = 1;
-
2. Below that, create a
ScoreLabel
by typing in the code in Listing 7-14. ThisScoreLabel
contains anadd
function to easily add and update the score.***清单 7-14。***创建 ScoreLabel
//Define ScoreLabel var ScoreLabel = Class.create(Label, { //Extends Label class initialize: function(x, y) { enchant.Label.call(this, "SCORE:0"); //Call the Label class constructor this.x = x; this.y = y; this.score = 0; this.color = "#ffffff"; }, add: function(pts) { //Add the score this.score += pts; this.text = "SCORE:" + this.score; //Update display } });
-
3. In the
game.onload
function, at the very end, create a new instance ofScoreLabel
and add it torootScene
by typing in the code in Listing 7-15.清单 7-15。 创建和添加评分标签
//Display score label scoreLabel = new ScoreLabel(5, 5); game.rootScene.addChild(scoreLabel);
-
4. Edit the contents of the
Droid
class to match Listing 7-16. New code is in boldface. This will prepare the class for some interactivity upgrades in the next section, which will use thea
andmode
variables shown in the code sample. Thetick
function will be called every frame, and thehit
function will be called whenever the player clicks on the Droid.清单 7-16。 重组的机器人类
//Define Droid class var Droid = Class.create(Sprite3D, { //Extend Sprite3D class initialize: function(x, y, z) { Sprite3D.call(this); //Call the Sprite3D constructor this.set(game.assets["img/droid.dae"]); this.scaleX = 0.3; this.scaleY = 0.3; this.scaleZ = 0.3; this.x = x; this.y = y; this.z = z; this.a = 0.01; this.addEventListener('enterframe', this.tick); //Define event listener this.addEventListener('touchstart', this.hit); //Define event listener for hit this.mode = 2; //Set initial Droid mode to wait, and then appear this.nextMode = 0; this.waitFor = game.rootScene.age + rand(100) + 75; }, tick: function() { //Iterate Droid animation based on mode }, hit: function() { //Hit Droid } });
机器人外观行为
在打机器人游戏中,机器人必须有特定的行为方式。首先,在游戏开始之前,它们是在一个洞里被创造出来的。然后,在一段随机的时间后,他们从那个洞里出现。(现在,不要太担心那个洞,而是关注机器人的移动。)它们等待另一段随机的时间,然后藏在它们第一次出现的洞里。在我们的游戏中,当他们在洞外被击中时,他们会飞起来,离开屏幕,一个新的机器人会出现在它的位置上。
从这个描述中,我们可以推断出机器人在任何给定的时刻都会处于五种状态中的一种。表 7-1 显示了这些状态的列表以及驱动该行为的逻辑。表格中显示的模式编号是我们在 Droid 处于该状态时分配给它的编号,以便跟踪它。
表 7-1 。机器人的状态
状态(模式编号) | 描述 |
---|---|
出现(1) | 每帧增加机器人的 y 位置,直到某一点。切换到等待模式,并打算在一段随机时间后进入隐藏模式。 |
隐藏(2) | 每帧减少机器人的 y 位置,直到某个点。切换到等待模式,并打算在一段随机时间后进入显示模式。 |
等待(3) | 一旦规定的时间过去,就进入下一个模式。 |
停用(4) | 什么都不做。这个洞不应该再出现机器人了。 |
飞走了(5) | 每一帧增加机器人的 y 位置(在某一点上,机器人会飞出屏幕)。在一段随机的时间后,重置机器人在洞下的位置,并设置为出现模式。 |
这些状态将与我们接下来在Droid
类声明中创建的switch
语句相匹配。
-
5. There is already an event listener that calls the
tick
function inside theDroid
class definition. Type in the code in Listing 7-17 inside thetick
function to create a system for moving the Droids.清单 7-17。 勾选功能
if (game.rootScene.age === 0) { this.waitFor++; } switch (this.mode) { case 0: //Appear from hole this.a *= 0.98; this.y += this.a; if (this.y >= -1.2) { this.mode = 2; //Go to wait mode after fully appearing this.nextMode = 1; //After wait mode, go to mode 1 (hide) this.waitFor = game.rootScene.age + rand(100) + 10; } break; case 1: //Hide in hole this.y -= this.a; this.a *= 0.98; if (this.y <= -1.5) { this.mode = 2; //After fully hiding, go to wait mode this.nextMode = 0; //After waiting, go to mode 0 (appear) this.waitFor = game.rootScene.age + rand(100); //Reduce number of max droids (to control length of game) maxDroid--; //If number of max droids has been reached, and the given //Droid is instructed to hide, block the hole if (maxDroid <= 0) this.mode = 3; } break; case 2: //Wait if (this.y < -1.5) this.y += 0.05; if (game.rootScene.age > this.waitFor) { this.mode = this.nextMode; this.a = 0.05; } break; case 3: //Deactivated (no more Droids will appear from this hole) break; case 4: //Fly this.y += this.a; this.a *= 1.1; if (game.rootScene.age > this.waitFor) { this.nextMode = 0; this.waitFor = game.rootScene.age+rand(50) + 30; this.mode = 2; this.y = -3; this.a = 0.05; } break; }
首先,我们告诉帧在继续增加一帧之前等待一帧,这种情况很少见,在rootScene
的第 0 帧上创建了一个 Droid。这最有可能不会发生,但我们想保护我们的基地。
代码中的a
变量用于动态移动。在每一帧中,a
的值根据 Droid 所处的模式而变化。例如,如果机器人正在飞走,a
的值将每帧增加 10%(this.a *= 1.1;
),由于机器人的 y 位置每帧增加a
( this.y += this.a;
)的值,随着时间的推移,机器人将越来越快地飞起来。这一切发生得非常快,但增加了一个很好的物理模拟效果,看起来更真实。
请注意,在案例 4 ( fly
)中,在游戏达到waitFor
值之后(换句话说,在机器人飞离屏幕之后),机器人被重新定位回(y = -3;
),重新开始这个过程,表现得像一个“新”机器人。
-
6. Define the
hit
function by entering Listing 7-18 into thehit
function in theDroid
class definition. This function is called whenever the player clicks a Droid.清单 7-18。 点击功能
if (this.y >= -1.4) { //If Droid is over halfway out of hole this.mode = 4; //Enter fly mode this.a = 0.02; this.waitFor = game.rootScene.age + 30; //Wait for 30 frames (0.5s) scoreLabel.add(combo); //Add combo score combo++; hitDroid++; } else { //If Droid is whacked before appearing out of hole, reset combo combo = 1; }
如果在游戏过程中没有机器人被玩家击中,机器人会在出现、等待和隐藏模式之间循环。然而,这个hit
函数,当在 Droid 类定义的前面从touchstart
事件监听器调用时,将逐行导致下面的事情发生:
-
如果机器人离洞超过一半:
-
进入
fly
模式。 -
设置修改器(
a
)将 y 值(在fly
模式下)最初增加 0.02。 -
告诉机器人在 30 帧内不要改变模式。
-
将用户当前的组合(从 1 开始)添加到总得分中。
-
将当前组合增加 1。
-
将
hitDroid
的值增加 1。 -
30 帧过去后,将模式更改为 2(等待),并将 Droid 从 Droid 定义中的情况 4 重新定位到(
y = -3
)。 -
否则(换句话说,如果玩家试图击中尚未出洞一半的机器人):
-
将玩家当前的连击重置为 1。
最后,我们将添加到Scene3D
中的 Droid 的位置更改为(0,-1.5,-9.2)。这不是完全必要的,但我们这样做是为了感受一下机器人在屏幕上出现和消失的样子。
-
7. Finally, reposition the Droid created and added to
rootScene
by replacing the line that readsscene.addChild(new Droid(0, 0, -8));
in thegame.onload
function with the line shown in Listing 7-19.清单 7-19。 添加不同位置的机器人
scene.addChild(new Droid(0, -1.5, -9.2));
我们在这里改变机器人的位置,因为现在它四处移动,否则它最初不会出现在摄像机的视野中。
-
8.保存代码并在浏览器中查看游戏。Droid 应该随着时间的推移而上下弹出,并且当它处于向上状态时应该是可点击的。当机器人被点击时,它应该会飞上屏幕,直到消失,另一个应该会取代它的位置。
如果您在本节中遇到问题,您可以在下载包的 Step3 文件夹中找到一个工作代码示例。
飞机:gl.enchant.js 的招牌和更多
enchant.js 包包含插件 primitive.gl.enchant.js 。这个插件包含游戏中使用的最常见的三维形状的预定义对象。我们将在本节中使用的对象是一个平面,,它只是一个可以加载图像或颜色的平面。因为所有这些对象都建立在Sprite3D
之上,所以任何Sprite3D
方法或属性对于一个平面也是可用或可访问的。在游戏中执行以下操作来实现位面:
-
1. Change the
game.preload('img/droid.dae');
line in thewindow.onload
function to match what is shown in Listing 7-20. This is just loading in pictures to be used by the planes coming up.清单 7-20。 预压图像
game.preload('img/pit.png', 'img/sign.png', 'img/droid.dae');
-
2. Create a
Plane
to represent the pit (containing the holes the Droids come out of) by typing in the code in Listing 7-21 after the linescene.setCamera(camera);
in thegame.onload
function.清单 7-21。 造坑
var pit = new PlaneXZ(); pit.scaleX = 3.0; pit.scaleY = 3.0; pit.scaleZ = 3.0; var texture = new Texture(game.assets['img/pit.png'], { flipY: false }); texture.ambient = [1.0, 1.0, 1.0, 1.0]; pit.mesh.texture = texture; pit.y = -1; pit.z = -10; scene.addChild(pit);
首先,我们创建 pit 变量作为新的PlaneXZ
。这是 primitive.gl.enchant.js 中的一个预定义三维对象。由于平面是一个二维对象,它将只存在于三个三维轴中的两个轴上,这就是我们创建这个坑作为PlaneXZ
的原因。这个指定告诉 enchant.js 应该在由 X 和 Z 轴创建的二维空间中创建平面。
接下来,我们用scaleX
、scaleY
和scaleZ
将坑缩放 3 倍。使用等于-0.5 或 0.5 的坐标为平面的每个角或顶点(例如,-0.5,0,-0.5,(0.5,0,-0.5)等)来创建平面。).通过在所有三个轴上将它们缩放三倍,对于每个值,该平面的最终坐标要么是-1.5,要么是 1.5(例如,-1.5,0,-1.5),(1.5,0,-1.5),等等。).当你创建自己的游戏时,你会想尝试缩放设置,看看在你的场景摄像机的角度下什么看起来最好。
下一步是创建一个纹理,它最终可以应用到您刚刚创建的平面上。这里,我们加载 pit.png 作为图像,并传递一个参数(flipY: false
)。我们为什么要这样做?当将纹理应用到平面时,enchant.js 会尽力找出如何应用纹理,使其正面朝上。但是,有时候 enchant.js 会出错。
在 WebGL 中,任何可以存储像素的对象都包含沿着垂直轴翻转图像的属性UNPACK_FLIP_Y_WEBGL,
,并被赋给 gl.enchant.js 中的属性flipY
,flipY
属性默认为true
,因此通过这种方式将其设置为false
会沿着 Y 轴翻转图像。虽然从技术上来说,XZ 平面上没有 Y 轴,但是纹理是二维的,所以flipY
的指定会像预期的那样工作,因为纹理没有 Z 轴。(如果你准备好迎接挑战,你可以通过搜索 OpenGL 中的纹理坐标信息,找到更多关于如何在 WebGL 中处理纹理的信息。WebGL 基于 OpenGL。)
移动到texture.ambient
行,我们设置一个值[1.0,1.0,1.0,1.0]。前三个值对应红色、绿色和蓝色,最后一个值对应灯光的可见性或透明度。值 1.0 等于 100%,因此这转化为完全可见的白光。visibility 值仅在非常特殊的情况下使用,这里不做介绍。
最后,我们将新创建的纹理应用到坑的网格纹理属性,并调整坑的位置,将其放置在屏幕上适当的位置。最后一步是将其添加到Scene3D
中,坑将出现在屏幕上。
-
3. Directly under the line
scene.addChild(pit);
, type in the code in Listing 7-22 to create a red base for our pit. This adds a nice touch to the finished product.清单 7-22。 创建基地
var base = new PlaneXY(); base.z = -8.6; base.y = -2.5; base.scaleX = 3.0; base.scaleY = 3.0; base.scaleZ = 3.0; base.mesh.setBaseColor('#ff0000'); scene.addChild(base);
这段代码非常简单。我们简单地创建一个新的PlaneXY
作为基础,定位它,缩放它,然后设置一个基础颜色。注意基色方法如何接受颜色的十六进制值。这里可以接受任何对 CSS 颜色属性有效的值,但是为了简单起见,我们喜欢使用十六进制值。
值#ff0000
转换为红色,因为前两个数字对应红色,后两个数字对应绿色,最后两个数字对应蓝色。因为这些值是十六进制的,所以这个值是十六进制的。ff
的值对应于 256。因为只有红色占位符有值,并且值是 256,所以PlaneXY
底座的颜色会是红色。
最后,我们给Scene3D
添加碱基,使它出现在屏幕上。
-
4. Beneath that, create a sign to make our game even snazzier by typing in the code in Listing 7-23.
清单 7-23。 创造标志
var sign = new PlaneXY(); sign.scaleX = 2.0; sign.scaleY = 2.0; sign.scaleZ = 2.0; var signTexture = new Texture(game.assets['img/sign.png']); signTexture.ambient = [1.0, 1.0, 1.0, 1.0]; sign.mesh.texture = signTexture; sign.y = 0.5; sign.z = -8.6; scene.addChild(sign);
这里没有什么新东西。就像坑一样,我们创建一个新的Plane
,这一次是一个PlaneXY
,缩放它,创建一个新的纹理(这一次没有使用false flipY
参数,因为 enchant.js 根据我们的需要正确定位图像),为纹理设置环境光,并将其分配给标志。用 y 和 z 属性定位标志后,我们将它添加到场景中。
-
5. Save the code and run it through a web browser. It should appear as it does in Figure 7-6.
图 7-6 。用飞机重击机器人 3d
如果您遇到问题,您可以在本章开头提到的下载包的 Step4 文件夹中找到一个工作代码示例。
复制机器人并完成游戏
我们现在已经非常接近完成游戏了,但是我们的屏幕上仍然只有一个机器人。让我们复制那个 Droid 以得到一个完整的集合,填充我们的 pit 图像。
-
1. In your code, create a Droid in each one of the holes shown in the pit by replacing
scene.addChild(new Droid(-1.1, -1.5, -9.2));
in thegame.onload
function with the code shown in Listing 7-24.清单 7-24。 创造多个机器人
//Create all Droids for (var j = 0; j < 3; j++) { for (var i = 0; i < 4; i++) { scene.addChild(new Droid(i * 0.75 - 1.1, -1.5, -9.2 - j * 0.9)); } }
我们将
Droid
创建为一个可以调用的类,并指定该类的所有实例的行为,因此复制 Droid 就像使用for
循环遍历我们想要创建的所有实例一样简单。由
j
变量控制的for
循环表示每行,由i
变量控制的for
循环表示给定行中的每列。请注意,在新的Droid
声明中,我们如何将 x 位置乘以 0.75,以向右移动将创建一个新机器人的空间。类似地,我们将j
的值乘以 0.9,然后从-9.2 中减去它,以将新机器人的位置向后移动一两行。在你的 enchant.js 游戏中创建任何东西的多个实例是一种非常有效的方法。 -
2. Directly underneath this, type in the code in Listing 7-25 to create an event listener that ends the game once the maximum number of Droids has reached zero or lower.
清单 7-25。 结束游戏
game.rootScene.addEventListener('enterframe', function() { if (maxDroid <= 0) { game.end(scoreLabel.score, "You whacked " + hitDroid + " Droids for a score of " + scoreLabel.score + " points!"); } });
因为重击机器人或允许他们退回到他们的洞里会导致变量
maxDroid
每次递减 1,所以我们还添加了一个enterframe
事件监听器,以便在maxDroid
达到 0 或更低时结束游戏,显示被玩家分数重击的机器人数量。注意请记住,因为
game.end
功能只有 nineleap.enchant.js 插件才完全支持,所以只有在9leap.net
上传游戏时,才会出现带有玩家分数和机器人命中数的最终消息。 -
3. Save the code and run it from a web browser. You should have a working game that appears as it does in Figure 7-7.
图 7-7 。复制机器人后
如果您在本节中遇到问题,您可以在本章前面提到的下载包的 Step5 文件夹中找到一个完整的工作代码示例。
平移相机效果
虽然我们现在有一个工作的游戏,但让我们添加一个最后的点睛之笔:游戏开始时的平移相机效果。当游戏开始时,玩家将鸟瞰这个坑,然后摄像机将向下移动到我们到目前为止的视野。这可以让你看到你刚刚创建的游戏的 3d 特性。
执行以下操作来创建平移相机效果:
-
1. Inside the
game.onload
function, replace the lines that readcamera.y = 1.1;
andcamera.z = -1.65;
with the code in Listing 7-26 to change the initial camera position.清单 7-26。 改变摄像机位置
camera.y = 14; camera.z = -8.1;
这个摄像机位置离坑更远,但是仍然朝向坑。这使得声相效果更加强烈和明显。
-
2. After the line that reads
if (maxDroid <= 0) {game.end(scoreLabel.score, "You whacked " + hitDroid + " Droids for a score of " + scoreLabel.score + " points!");}
, but still inside the event listener, type in the code in Listing 7-27 to make the camera pan down at the beginning of the game.清单 7-27。 使摄像机开始平移
//Pan camera down at beginning if (game.rootScene.age < 130) { camera.z += 0.05; camera.y -= 0.1; }
实际的平移效果发生在这里。对于游戏的前 130 帧,相机会越来越靠近坑,停在完美的视点。这是通过每帧对 z 轴和 y 轴位置进行非常小的修改,以在经过 130 帧时到达特定点来实现的。当开发这样的东西时,它有助于计算你希望相机从哪里开始,你希望它在哪里结束,然后计算出相机需要移动每一帧多少才能实现这一点。
-
3. Save the code and run the game through a web browser. The game should start from the viewpoint shown in Figure 7-8 and quickly pan down to the view that is featured in preceding code samples.
图 7-8 。具有全新视角的 3d 重击机器人
如果您在本节中遇到问题,您可以在本章前面提到的 zip 文件的 Step6 文件夹中找到一个工作代码示例。
结论
在这最后一章,我们看了看如何开发一个独立的 3d enchant . js 游戏。我们简要介绍了 WebGL 和 enchant.js 的各种支持 WebGL 的插件:gl.enchant.js、primitive.gl.enchant.js 和 collada.gl.enchant.js。
我们创建了一个 3d 版本的重击机器人游戏,并看到了如何使用Scene3D
、Camera3D
和Sprite3D
的实例来构建一个 3d 环境并与玩家进行交互。通过创建平面实例和我们自己创作的Droid
类,我们能够将我们的重击机器人游戏的 3d 版本放在一起,甚至在结尾添加了俯冲相机效果来展示我们游戏的 3d 本质。
我们希望这一章能启发你通过 enchant.js 自己尝试 3d 游戏,并最终尝试创作你自己的 3d 游戏。由于 9leap.net 支持任何用 enchant.js 创建的游戏,我们鼓励你在 9leap 上发布你的游戏并与世界分享!
与我们保持联系:
- 官方网站 :
enchantjs.com
- Reddit:
reddit.com/r/enchantjs
–在这里提问! - Facebook 页面 :
facebook.com/enchantjs
- 推特 : @enchantjs_en
- GitHub :
github.com/wise9/enchant.js
祝你的游戏创作好运!
enchant.js 团队
八、附录 A:类
本附录包含 enchant.js 中最常见的类的信息。类首先根据它们来自 enchant.js 的哪一部分(核心库或插件)列出,然后按字母顺序组织。每个类页都包含对该类的总体功能的简要说明,列出从其继承属性和方法的类,提供该类最常见的属性和方法,对于某些类,还包括如何使用该类的示例。
类被组织在一个层次结构中,并从它们的父类继承方法和属性。从其继承属性和方法的类在每个类列表的继承部分中列出,并以一系列类的形式显示。最高级别的父类显示在左侧,列出的类显示在右侧。例如,标签类的继承树如下所示:
EventTarget-Node-Entity-Label
因此,除了能够使用在Label
类中指定的所有属性和方法,作为标签创建的对象将能够使用来自Entity, Node
和EventTarget
的所有适用方法。addEventListener
方法(来自EventTarget
)可以在标签上运行,age 属性(来自Node
)也可以在Label
上调用。
关于 enchant.js 中类的完整列表,请参考http://enchantjs.com
处参考部分下的官方 API。
附录内容:
- 核心类
- a.核心
- b.EventTarget(事件目标)
- c.比赛
- d.组
- e.标签
- f.地图
- g.结节
- h.事件
- 一.声音
- j.鬼怪;雪碧
- gl .很高兴见到你. js
- a.故意的
- b.相机 3D
- c.方向灯
- d.Light3D
- e.场景 3D
- f.Sprite3D
- ui.enchant.js
- a.阿帕德
- b.纽扣
- c.生活标签
- d .可变文本
- e.Pad(垫)
- f.分数标签
核心类
核心类包含在主 enchant.js 文件中。除了基本库(enchant.js)之外,不需要向一组文件中添加任何东西来访问核心类。
核心
Core
类是主要的游戏容器。整个游戏必须驻留在一个Core
对象中。一次只能存在一个,如果创建了另一个,原始的将被停用。
Core
类还负责管理游戏中的Scene
对象。改变活动场景、删除场景和添加Scene
都是Core
类对象的一部分。
延伸
EventTarget
Core
公共属性
assets
:存储预装图像的对象。currentScene
:当前显示的场景。fps
:游戏的帧率。frame
:自从Core
对象被创建以来已经过去的当前帧数。height
:游戏画面的高度。- 游戏加载时显示的场景。
rootScene
:一个游戏的默认场景。width
:游戏画面的宽度。
常用方法
所有的例子都假设变量game
已经被创建为Core
类的一个实例。
方法 | 说明 | 例子 |
---|---|---|
popScene(); | 结束当前场景并激活底层场景。 | game.popScene(); |
preload(assets); | 预装一个图像或声音文件,以便在游戏中使用。 | game.preload("img/chara1.jpg"); |
pushScene(scene); | 将场景推到场景堆栈的顶部,使其成为活动场景。 | game.pushScene(Scene3); |
removeScene(scene); | 从场景堆栈中移除场景。 | game.removeScene(Scene2); |
replaceScene(scene); | 用指定的场景替换当前场景。 | game.replaceScene(Scene4); |
start(); | 开始游戏。 | game.start(); |
例子
var game = new Core(320,320);
实体
Entity
类包含显示为 DOM 元素的对象,或者在网页中创建为对象的元素。这个类不是直接使用的(也就是你从来没有指定过var bear = new Entity();)
,而是包含了 enchant.js 中大多数可视元素共有的属性和方法的集合,因为大多数可视元素(Sprite, Label
等)。)是Entity
类的子类,可视元素也可以访问这些属性和方法。
延伸
EventTarget-Node-Entity
公共属性
backgroundColor:
指定背景的颜色。应以对 CSS 颜色属性有效的任何格式指定颜色。(如#ffffff、红色等。)buttonMode:
将此Entity
指定为按钮。当随后点击Entity
时,相应的按钮事件被调度。有效值包括左、右、上、下、a 和 b。- 如果此
Entity
被点击,则buttonPressed:
设置为true
。这仅在设置了buttonMode
时有效。 height:
以像素为单位的Entity
的高度。opacity:``Entity
的不透明度。这是从 0(完全透明)到 1(完全不透明)测量的。originX
:用于旋转和缩放的原点的 X 位置。origin
:用于旋转和缩放的原点的 Y 位置。rotation
:旋转Entity
的角度(单位为度)。visible
:表示是否显示Entity
。默认为true
。注意,一个Entity
仍然必须被添加为一个Scene
的子节点,以显示在屏幕上。
常用方法
所有的例子都假设变量game
已经被创建为Sprite
类的实例,它扩展了Entity
类。这是因为Entity
本身不能被创建。
方法 | 说明 | 例子 |
---|---|---|
intersect(Entity); | 如果Entity 与指定的Entity 接触或相交,则返回true 。 | bear.intersect(ball); |
rotate(degree); | 将Entity 旋转指定的度数。 | bear.rotate(15); |
scale(x,y); | 按照指定的因子在 x 和 y 方向缩放Entity 。 | bear.scale(2,2); (将熊缩放 200%) |
within(Entity, distance); | 如果Entity 的中心点在指定Entity 的中心点的指定距离内(以像素为单位),则返回true 。 | bear.within(ball, 50); |
事件
事件不是由开发者直接创建的,而是通常由一个Core
、Scene
或Node
对象发出的。使用EventListener
,可以监听这些事件,然后在事件发生时执行指定的代码。
延伸
事件是在 enchant.js 的最高层定义的,不从任何类继承。
常见事件
请注意,下表中描述的“A”和“B”按钮是指作为 ui.enchant.js 中的Button
类的一部分创建的虚拟按钮,并被指定为“A”和“B”按钮。有关更多信息,请参见本附录末尾的 ui.enchant.js 部分中的Button
类条目。
事件类型 | 描述 | 发布的对象 |
---|---|---|
Event.A_BUTTON_DOWN | 按下“A”按钮时发生的事件 | Core, Scene |
Event.A_BUTTON_UP | 释放“A”按钮时发生的事件 | Core, Scene |
Event.ADDED | 将节点添加到组时发生的事件 | Node |
Event.ADDED_TO_SCENE | 将节点添加到场景中时发生的事件 | Node |
Event.B_BUTTON_DOWN | 按下“B”按钮时发生的事件 | Core, Scene |
Event.B_BUTTON_UP | 释放“B”按钮时发生的事件 | Core, Scene |
Event.DOWN_BUTTON_DOWN | 按下向下按钮时发生的事件 | Core, Scene |
Event.DOWN_BUTTON_UP | 释放向下按钮时发生的事件 | Core, Scene |
Event.ENTER | 场景开始时发生的事件 | Scene |
Event.ENTER_FRAME | 处理新帧时发生的事件 | Core, Scene |
Event.EXIT | 场景结束时发生的事件 | Scene |
Event.EXIT_FRAME | 帧处理即将结束时发生的事件 | Core |
Event.INPUT_CHANGE | 按钮输入改变时发生的事件 | Core, Scene |
Event.INPUT_END | 按钮输入结束时发生的事件 | Core, Scene |
Event.INPUT_START | 按钮输入开始时发生的事件 | Core, Scene |
Event.LEFT_BUTTON_DOWN | 按下左键时发生的事件 | Core, Scene |
Event.LEFT_BUTTON_UP | 释放左键时发生的事件 | Core, Scene |
Event.LOAD | 游戏加载完成时调度的事件 | Core |
Event.PROGRESS | 游戏加载期间发生的事件 | Core |
Event.REMOVED | 从组中删除节点时发生的事件 | Node |
Event.REMOVED_FROM_SCENE | 从场景中移除节点时发生的事件 | Node |
Event.RENDER | 呈现实体时发生的事件 | Entity |
Event.RIGHT_BUTTON_DOWN | 按下右键时发生的事件 | Core, Scene |
Event.RIGHT_BUTTON_UP | 释放右键时发生的事件 | Core, Scene |
Event.TOUCH_END | 当与节点相关的触摸结束时发生的事件 | Node |
Event.TOUCH_MOVE | 当与节点相关的触摸移动时发生的事件 | Node |
Event.TOUCH_START | 与节点相关的触摸开始时发生的事件 | Node |
Event.UP_BUTTON_DOWN | 按下向上按钮时发生的事件 | Core, Scene |
Event.UP_BUTTON_UP | 释放向上按钮时发生的事件 | Core, Scene |
比赛
在 0.6 版本中,Game
对象被重新命名为Core
对象。请参见Core
对象条目。高于 0.6 的 enchant.js 版本向后兼容Game
对象,但是由于Game
对象已经过时,我们强烈建议使用Core
对象。
组
Group
类用于将多个Node
对象链接在一起,目的是将它们作为一个单元移动,或者作为一个单元以另一种方式对它们进行操作。因为 enchant.js 中所有可见的实体都属于扩展了Node
类的Entity
类,所以所有可见的实体都可以添加到一个Group
对象中。
延伸
EventTarget-Node-Group
公共属性
childNodes
:包含所有节点的对象数组,这些节点是Group
的成员。firstChild
:Group
中的第一个Node
。lastChild
:?? 中的最后一个Node
。
常用方法
所有的例子都假设变量set
已经被创建为Group
类的一个实例。因为Group
扩展了Node
类,任何对Node
有效的方法都将作用于Group
对象。(如moveTo, moveBy
等。)
方法 | 说明 | 样品 |
---|---|---|
addChild(node); | 在Group 的末尾添加一个Node 。 | set.addChild(bear); |
insertBefore(node, reference); | 在Node 对象数组中的参考位置之前,将一个Node 插入到一个Group 中。 | set.insertBefore(bear,3); |
removeChild(node); | 从Group 中删除一个Node 。 | set.removeChild(bear); |
示例使用
var stage = new Group();
stage.addChild(player);
stage.addChild(enemy);
stage.addChild(map);
stage.addEventListener('enterframe', function() {
// Moves the entire frame based on the player's x coordinate.
if (this.x > 64 - player.x) {
this.x = 64 - player.x;
}
});
标签
标签用于显示游戏中的文本。
延伸
EventTarget-Node-Entity-Label
公共属性
color
:Label
中文本的颜色。应以对 CSS 颜色属性有效的任何格式指定颜色。(如#ffffff、红色等。)font
:Label
中文本的字体。字体应该以对 CSS 字体属性有效的任何格式指定。(如 16px 衬线;12px 无衬线字体;等等。)text
:由Label
显示的文本。textAlign
:文本的水平对齐。应以对 CSS text-align 属性有效的任何格式指定对齐方式。(例如,左、右、中心等。)
常用方法
除了从Entity, Node
和EventTarget
继承的方法之外,Label
没有其他通用的方法。
示例使用
var title = new Label();
title.color = "blue";
title.font = "16px serif";
score.text = "Example Title";
game.rootScene.addChild(title);
地图
地图用于从 tilesets 创建地图并显示它们。
延伸
EventTarget-Node-Entity-Map
公共属性
collisionData
:二维数组,指定是否应该在Map
中的特定图块上检测碰撞。image
:用于Map
中图块的图块集合图像。tileHeight
:在Map
中使用的瓷砖的高度。tileWidth
:在Map
中使用的瓷砖的宽度。
常用方法
所有的例子都假设变量map1
已经被创建为Map
类的一个实例。
方法 | 说明 | 例子 |
---|---|---|
checkTile(x, y); | 检查在给定位置出现了什么牌。 | map1.checkTile(50, 50); |
hitTest(x, y); | 如果指定点在collisionData 数组中被指定为包含障碍物,则返回true 。 | map1.hitTest(50, 50); |
loadData(data); | 从图块集图像设置地图中的图块。 | map1.loadData(array); |
示例使用
var map = new Map(16, 16);
map.image = game.assets['http://enchantjs.com/assets/img/map0.gif'];
map.loadData([
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,0],
[0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,0],
[0,2,2,2,2,0,0,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,0],
[0,0,2,2,0,0,0,2,2,0,0,0,0,2,2,0,0,0,0,2,2,0,0],
[0,0,2,2,0,0,0,2,2,0,0,0,0,2,2,0,0,0,0,2,2,0,0],
[0,0,2,2,0,0,0,2,2,0,0,0,0,0,0,0,0,2,2,2,2,0,0],
[0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,0,0],
[0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,2,2,0,0,0,0],
[0,0,0,0,0,2,2,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0],
[0,0,0,0,0,2,2,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0],
[0,0,0,2,2,2,2,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0],
[0,0,2,2,2,2,2,0,0,0,0,0,2,2,2,2,2,2,2,2,2,0,0],
[0,0,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,0,0],
[0,0,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0],
[0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0,0],
[0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,0],
[0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,0],
[0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
]);
结节
Node
类用于 enchant.js 中通过显示树显示的对象。Node
类的实例不是由开发人员直接创建的。
延伸
EventTarget-Node
公共属性
age
:物体已经存活的帧数。scene
:Node
所属的Scene
。x
:物体的 x 位置。y
:Node
对象的 y 位置。
常用方法
所有的例子都假设变量bear
已经被创建为Sprite
类的实例,它扩展了Entity
类,后者扩展了Node
类。
方法 | 说明 | 例子 |
---|---|---|
moveBy(x, y); | 将节点对象在 x 和 y 轴上移动指定的量(以像素为单位)。 | bear.moveBy(50, 50); |
moveTo(x, y); | 将节点对象移动到 x 和 y 轴上指定的位置。 | bear.moveTo(60, 60); |
事件
显示对象树的根。所有的Entity
对象必须添加到一个Scene
对象中才可见。
延伸
EventTarget-Node-Group-Scene
公共属性
除了从EventTarget, Node
和Group
继承的属性之外,场景没有公共属性。
常用方法
除了从EventTarget, Node
和Group
继承的方法之外,Scene
没有其他通用的方法。
示例使用
var scene = new Scene();
scene.addChild(player);
scene.addChild(enemy);
core.pushScene(scene);
鬼怪;雪碧
精灵用于在游戏中显示图像,通常是角色或游戏元素的图像。
延伸
EventTarget-Node-Entity-Sprite
公共属性
frame
:要显示的帧的索引号。height
:以像素为单位的Sprite
的高度。image
:图像(sprite-sheet ),从中拉出一个帧来表示屏幕上的Sprite
。width
:以像素为单位的Sprite
的宽度。
常用方法
除了从EventTarget, Node
和Entity
继承的属性之外,Scene
没有共同的属性。
示例使用
var bear = new Sprite(16,16);
sprite.image = game.assets("img/chara1.gif");
sprite.frame = [0, 1, 0, 2];
//shows frame 0, 1, 0, and 2 in sequence, incrementing up one each frame
game.rootScene.addChild(bear);
gl .很高兴见到你. js
该插件将 WebGL 支持扩展到 enchant.js,允许创建 3d 游戏。
环境光
AmbientLight
类表示从光源的原点向所有方向产生光的光源。
延伸
EventTarget-Light3D-AmbientLight
公共属性
除了从EventTarget, Node
和Entity
继承的属性之外,AmbientLight
没有共同的属性。
常用方法
除了从EventTarget
和Light3D
继承的属性之外,AmbientLight
没有共同的属性。
示例使用
var scene = new Scene3D();
var light = new AmbientLight();
light.color = [1.0, 1.0, 0.0];
scene.setAmbientLight(light);
相机 3D
类创建了一个视图,玩家可以从这个视图中看到一个Scene3D
的内部。
延伸
这个类是在 gl.enchant.js 的最高层定义的,它没有父类。
公共属性
centerX
:相机指向的 X 轴上的点。centerY
:相机指向的 Y 轴上的点。centerZ
:相机指向的 Z 轴上的点。upVectorX
:X 轴上的点,相机认为该点“向上”upVectorY
:Y 轴上的点,相机认为该点“向上”upVectorZ
:Z 轴上的点,相机认为该点“向上”x
:摄像机在 X 轴上的位置。y
:相机在 Y 轴上的位置。z
:摄像机在 Z 轴上的位置。
常用方法
所有的例子都假设变量camera
已经被创建为Camera3D
类的一个实例。
方法 | 说明 | 例子 |
---|---|---|
altitude(amount); | 沿 Y 轴移动摄像机 3D。 | camera.altitude(2); |
forward(amount); | 沿 Z 轴移动摄像机 3D。 | camera.forward(2); |
lookAt(sprite); | 将摄像机 3D 指向场景 3D 中的 Sprite3D。 | camera.lookAt(droid); |
rotatePitch(degrees); | 沿 X 轴旋转摄像机 3D。 | camera.rotatePitch(15); |
rotateRoll(degrees); | 沿 Z 轴旋转摄像机 3D。 | camera.rotateRoll(15); |
rotateYaw(degrees); | 沿 Y 轴旋转摄像机 3D。 | camera.rotateYaw(15); |
sidestep(amount); | 沿 X 轴移动相机。 | camera.sidestep(2); |
示例使用
camera = new Camera3D();
camera.y = 1.1;
camera.z = -1.65;
camera.centerZ = -10;
camera.upVectorZ = 10;
camera.upVectorY = 100;
方向灯
DirectionalLight
类代表一种向一个方向而不是所有方向投射光线的灯光。
延伸
EventTarget-Light3D-DirectionalLight
公共属性
directionX
:点的 X 位置,该点是DirectionalLight
照射的方向。directionY
:点的 Y 位置,DirectionalLight
将光线射向该点。directionZ
:点的 Z 位置,DirectionalLight
将光线射向该点。
常用方法
除了从EventTarget
和Light3D
继承的方法之外,DirectionalLight
没有通用的方法。
示例使用
var scene = new Scene3D();
var light = new DirectionalLight();
light.color = [1.0, 1.0, 0.0];
light.directionY = 10;
light.directionX = 4;
light.directionZ = 1;
scene.setDirectionalLight(light);
Light3D
Light3D
是三维灯光的基类。Light3D
类的实例不是由开发人员直接创建的。
延伸
EventTarget-Light3D
公共属性
color
:光源的颜色。
常用方法
除了从EventTarget
继承的方法之外,Light3D
没有通用的方法。
场景 3D
Scene3D
类是Scene
类的三维等价物。
遗产
EventTarget-Scene3D
公共属性
backgroundColor
:Scene3D
的背景颜色。childNodes
:一个Scene3D
的子元素数组。lights
:在Scene3D
中的 Light3D 元素的数组。
常用方法
所有的例子都假设变量scene
已经被创建为Scene3D
类的一个实例。
方法 | 说明 | 例子 |
---|---|---|
addChild(sprite); | 将 Sprite3D 添加到 Scene3D 中。 | scene.addChild(droid); |
addLight(light); | 向 3D 场景添加灯光。 | scene.addLight(light3); |
getAmbientLight(); | 检索场景 3D 中的环境光源。 | scene.getAmbientLight(); |
getCamera(); | 检索场景 3D 中的摄像机源。 | scene.getCamera(); |
getDirectionalLight(); | 检索场景 3D 中的平行光源。 | scene.getDirectionalLight(); |
removeChild(sprite); | 从场景 3D 中删除 Sprite3D。 | scene.removeChild(droid); |
removeLight(light); | 从 3D 场景中删除 Light3D。 | scene.removeLight(light2); |
setAmbientLight(light); | 在场景 3D 中设置环境光源。 | scene.setAmbientLight(light2); |
setCamera(camera); | 在场景 3D 中设置活动的摄像机 3D。 | scene.setCamera(camera); |
setDirectionalLight(light); | 设置场景 3D 中的平行光源。 | scene.setDirectionalLigh(light6); |
示例使用
var scene = new Scene3D();
var sprite = new Sprite3D();
scene.addChild(sprite);
Sprite3D
Sprite3D
类是Sprite
类的三维等价物。
延伸
EventTarget-Sprite3D
公共属性
childNodes
:子Sprite3D
元素的数组。scaleX
:X 轴上的比例因子。scaleY
:Y 轴上的比例因子。scaleZ
:Z 轴上的比例因子。x
:X 轴上Sprite3D
的位置。y
:Y 轴上Sprite3D
的位置。z
:Z 轴上Sprite3D
的位置。
常用方法
所有的例子都假设变量droid
已经被创建为Sprite3D
类的一个实例。
方法 | 说明 | 例子 |
---|---|---|
addChild(sprite); | 向 Sprite3D 对象添加子 Sprite3D。 | droid.addChild(droid2); |
altitude(amount); | 沿 Y 轴移动 Sprite3D。复制 Sprite3D 对象。 | droid.altitude(2); |
clone(); | 复制 Sprite3D 对象。 | droid.clone(); |
forward(amount); | 沿 Z 轴移动 Sprite3D。 | droid.forward(2); |
intersect(object); | 如果 Sprite3D 与指定的 3D 对象相交,则返回 true。 | droid.intersect(droid2); |
removeChild(sprite); | 从 Sprite3D 中移除子 Sprite3D 对象。 | droid.removeChild(droid2); |
rotatePitch(amount); | 沿 X 轴旋转 Sprite3D。 | droid.rotatePitch(15); |
rotateRoll(amount); | 沿 Z 轴旋转 Sprite3D。 | droid.rotateRoll(15); |
rotateYaw(amount); | 沿 Y 轴旋转 Sprite3D。 | droid.rotateYaw(15); |
scale(x,y,z); | 沿 x、y 和 z 轴缩放 Sprite3D。 | droid.scale(2,2,2); |
set(colladaFile); | 将 Collada 文件设置为用于 Sprite3D 的模型。 | droid.set(game.assets["img/droid.dae"]); |
sidestep(amount); | 沿 X 轴移动 Sprite3D。 | droid.sidestep(2); |
ui.enchant.js
这个插件包含各种元素来创建 enchant.js 游戏的用户界面,并支持各种按钮、面板和标签。对于大多数类,所需的图像也必须加载到给定的 enchant.js 游戏中。所需的图像与其各自的类具有相同的名称。
你爸爸
这个类是为一个模拟垫,可以控制任何二维方向的运动。
延伸
EventTarget-Node-Group-APad
公共属性
isTouched
:如果当前正在触摸APad
,则返回true
。
常用方法
除了从EventTarget,
Node
和Group
继承的方法之外,APad
没有通用的方法。
纽扣
这个类创建了一个带有文本的按钮,玩家可以点击它。
延伸
EventTarget-Node-Entity-Button
公共属性
color
:文字的颜色。font
:文字的字体。size
:文字的字体大小。text
:按钮上显示的文本。
常用方法
除了从EventTarget,
Node
和Entity
继承的方法之外,Button
没有通用的方法。
示例使用
//Creates a virtual 'a' button at (260, 250) and adds it to the rootScene
abtn = new Button(260, 250, 'a');
生活标签
这个类创建了一个标签,显示了一些代表角色健康的心。
延伸
这个类是在 ui.enchant.js 的最高层定义的,它没有父类。
公共属性
life
:当前寿命由LifeLabel
显示。maxLife
:由LifeLabel
显示的最大寿命。x
:LifeLabel
的 X 位置。y
:LifeLabel
的 Y 位置。
常用方法
这个类没有方法。
可变文本
这个类允许使用每个字符的图像来显示文本,允许文本在不同的操作系统和浏览器中完全相同地显示。
延伸
这个类是在 ui.enchant.js 的最高层定义的,它没有父类。
公共属性
posX
:物体的 X 位置。posY
:物体MutableText
的 Y 位置。text
:由MutableText
对象显示的文本。width
:以像素为单位的MutableText
对象的宽度。
常用方法
所有的例子都假设变量message
已经被创建为MutableText
类的一个实例。
方法 | 说明 | 例子 |
---|---|---|
setText(text); | 设置MutableText 对象的文本。 | message.setText("Hello!"); |
衬垫
这个类为玩家创建了一个四方向的方向板。当按下面板上的按钮时,会发出与其方向相对应的Events
(例如UP,
DOWN,
LEFT,
RIGHT
)。
延伸
EventTarget-Node-Entity-Sprite-Pad
公共属性
除了从EventTarget,
Node,
Entity
和Sprite
继承的属性之外,Pad
没有共同的属性。
常用方法
除了从EventTarget,
Node,
Entity
和Sprite
继承的方法之外,Pad
没有通用的方法。
分数标签
这个类是专门设计的MutableText
类的版本,用来显示游戏的分数。
延伸
这个类是在 ui.enchant.js 的最高层定义的,它没有父类。
公共属性
score
:指定ScoreLabel
要显示的分数。x
:ScoreLabel
的 X 位置。y
:ScoreLabel
的 Y 位置。
常用方法
这个类没有方法。