游戏开发 – Babylon.js: 构建 Web 基本游戏

最后更新于:2022-04-01 06:52:54

# 游戏开发 - Babylon.js: 构建 Web 基本游戏 作者 [Raanan Weber](https://msdn.microsoft.com/zh-cn/magazine/mt149362?author=Raanan+Weber) | 2015 年 12 月 | [获取代码](http://download.microsoft.com/download/D/5/4/D54647CC-A404-4374-B7EF-E469FB5136B9/Code_Weber.Babylon.1215.zip) Babylon.js 是一款基于 WebGL 的 3D 引擎,主要以游戏开发和易用性为主。作为 3D 引擎,它包含的工具可用于创建和显示网格,以及在空间中设置纹理,并能添加光源和照相机。由于是以游戏为主,因此 Babylon.js 还具有常规 3D 引擎不需要的一些额外功能。它提供了对碰撞检测、场景重力、面向游戏的照相机(例如,跟踪移动对象的跟随照相机),以及对 Oculus Rift 和其他虚拟现实 (VR) 设备的本地支持。它具有物理引擎插件系统、本地音频支持、基于用户输入的操作管理器等。在本教程中,我将介绍所有这些功能。 ## 关于本教程 在本教程中,我将开发一个简单的保龄球游戏。我将创建一个保龄球球道,添加 10 个保龄球瓶和一个保龄球,并提供掷球功能。我的游戏当然不会发布,但我会用它来向您展示如何使用 Babylon.js 提供的工具开发游戏。在开发期间,我会刻意避免使用任何外部工具。我将只使用 JavaScript 代码创建对象、照相机、纹理等。 在本教程中,我将使用最新的稳定版本 Babylon.js 2.1。David Catuhe 和 Babylon 开发团队正在尝试尽可能保持框架的后向兼容性,因此,我只能假设本教程适用于今后发布的版本(至少在下一主要版本发布之前)。我使用的是 Visual Studio 2015 Community Edition,但您也可以根据需要使用任意 IDE。 本教程分为两个部分。在本文中,我将概述 Babylon.js 的构建基块。我将创建网格、设置纹理、添加照相机和光源,并启用简单的用户交互。在第二部分中,我将添加碰撞和物理特性、音频、用户操作和特殊的照相机类型,从而展现 Babylon.js 的真正闪光之处。 ## 入门: 新建 Babylon.js 项目 简单的 Babylon.js 项目是一个静态网站。由于我使用的是 Visual Studio,因此我将使用嵌入 Visual Studio 的本地 IIS 服务器来托管这些静态文件。Visual Studio 没有静态网站模板,所以需要采用不同的方法。 首先,新建一个空白解决方案。打开 Visual Studio,然后转到“文件 | 新建 | 项目”。选择左窗格中的“其他项目类型”,然后选择“空白解决方案”(如图 1 所示)。为解决方案命名(我命名的是“BabylonBowling”),然后单击“确定”。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a8107da3.png)  图 1:在 Visual Studio 中新建空白解决方案 若要新建静态网站,您首先需要新建一个托管目录。右键单击空解决方案,然后单击“在文件资源管理器中打开文件夹”(如图 2 所示)。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a811ff69.png) 图 2:在文件资源管理器中打开解决方案文件夹 为 BabylonBowling 项目新建一个目录,然后关闭文件资源管理器。 右键单击解决方案,然后选择“添加 | 现有网站”。选择新创建的文件夹(务必选择刚创建的文件夹,而不是解决方案的文件夹),然后单击“打开”。此时,您应该有一个空白网站作为此解决方案的唯一项目了。 创建项目后,您需要添加框架和框架依赖项。有几种方法可以做到这一点。最简单的方法是使用 NuGet 包管理器。 右键单击项目,然后选择“管理 NuGet 包”。单击搜索字段(键盘快捷方式为 Ctrl+E),然后键入 babylon。此时,您会看到一个窗口(如图 3 所示)。选择“BabylonJS”。请确保选定版本是 2.1(或最新的稳定版本),然后单击“安装”。在弹出的“预览”窗口(若有)中,单击“确定”,然后 Babylon.js 会安装至您的空项目中(包括演示场景)。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a813e75f.png)  图 3:使用 NuGet 包管理器添加 Babylon.js 如果您将 npm 用作包管理器,则可以使用下列命令安装 Babylon.js: ~~~ npm install babylonjs ~~~ 在安装包后,您应该会在脚本文件夹中看到下列文件: * babylon.js:Babylon.js 的简化版本 * babylon.max.js:Babylon.js 的调试版本 * Oimo.js:Oimo JS 物理引擎,本教程的第二部分中将会用到 * poly2tri.js:可选的三边转换库 ([github.com/r3mi/poly2tri.js](http://github.com/r3mi/poly2tri.js)) * hand-minified.js:指针事件填充代码;在使用 npm 时缺失,因此使用下列命令进行安装: ~~~ npm install handjs ~~~ NuGet 安装程序也会创建 index.html 文件和 index.js 文件。 NuGet 包中的错误会在 web.config 中添加不需要的行。请双击此文件,并删除图 4 中突出显示的行(在我的解决方案中,为第 9 行),直至修复完成。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a815e533.png) 图 4:从 web.config 中删除突出显示的行 您现在可以测试项目了。使用 Ctrl+Shift+W 或通过单击顶部导航栏的“运行”按钮,在您的默认浏览器中打开项目。如果您看到图 5 中显示的 3D 宇宙飞船,则表明您的项目已准备就绪。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a8179fb7.png) 图 5:Babylon 默认宇宙飞船 如果您使用的是其他 IDE,只需按 Babylon.js 文档页中的“创建基本场景”教程执行操作,即可达到当前状态。如果您没有使用 NuGet,我仍然建议您使用 npm 安装依赖项。有关此教程,请访问[bit.ly/1MXT6WP](http://bit.ly/1MXT6WP)。 若要从头开始,请删除 index.js 中的 createScene 函数。 ## 构建基块 我首先将介绍的两个元素是引擎和场景。 引擎是负责与低级 WebGL API 通信的对象(WebGL 1 以 OpenGL ES2 为基础,语法非常相似)。引擎提供了更易于理解的较高级 API,这样您就不必编写低级 WebGL 代码了。这对开发者来说也是透明的。除了初始项目设置之外,我根本不会直接使用引擎。虽然使用此引擎可以完成特定的较低级功能,但我不会涉及这一点。 引擎需要两个参数才能初始化。第一个参数是用于绘制的画布。画布是 index.html 中已有的 HTML 元素。第二个参数是抗锯齿状态(开或关)。 打开当前的空白 index.js,然后添加下列代码行: ~~~ function init() {   var engine = initEngine(); } function initEngine() {   // Get the canvas element from index.html   var canvas = document.getElementById("renderCanvas");   // Initialize the BABYLON 3D engine   var engine = new BABYLON.Engine(canvas, true);   return engine; } ~~~ 在开发期间,我将使用 init 函数为每一步添加新功能。我创建的每个元素都会有自己的函数。 为了更好地了解场景代表什么,请将场景看成是包含不同网页的网站。一个网页中包含文本、图像、事件监听器以及呈现一个网页所需的其他所有资源。加载不同的网页就是加载不同的资源。 如同一个网页,场景包含显示一个 3D“网页”所需的资源。 此场景可能非常大,包含大量资源(网格、照相机、光、用户操作等)。不过,若要从一个网页移到另一个网页,我建议使用新场景。场景也负责呈现它自己的资源,并将所需的信息传达给引擎。保龄球游戏只需要一个场景。不过,如果我计划添加新等级或奖分游戏,那么我会使用新场景创建它们。 若要初始化场景,只需要我创建的引擎。在 index.js 中添加以下代码: ~~~ function createScene(engine) {   var scene = new BABYLON.Scene(engine);   // Register a render loop to repeatedly render the scene   engine.runRenderLoop(function () {       scene.render();   }); } ~~~ 首先,我将创建场景对象。接下来的代码行是我与引擎的唯一交互。它们会指示引擎,每当呈现循环运行时,呈现此特定场景。 将以下代码行添加到 init 函数的末尾,以真正创建场景: ~~~ var scene = createScene(engine); ~~~ 在继续前,我还需要执行两项操作。当您重设浏览器窗口大小时,画布也会重设大小。引擎还必须重设其内部宽度和高度,以使场景比例正确。就在返回引擎前,向 initEngine 函数添加下列代码行;声明会使场景比例正确。 ~~~ // Watch for browser/canvas resize events window.addEventListener("resize", function () {   engine.resize(); }); ~~~ 第二项操作是,将 index.html 更改为使用新的 init 函数。打开 index.html,然后查找包含 createScene 调用的脚本标记。将 createScene 更改为 init,然后保存 index.html 并关闭。 此场景的调试层极为高级,可方便您调试正在呈现的场景。它显示正在呈现的网格数以及当前的每秒帧数 (FPS)。借助它,您可以关闭纹理和阴影等功能,并能轻松找到丢失的网格。开启调试层非常简单: ~~~ scene.debugLayer.show(); ~~~ 开启后,您便能自行调试场景。 此时,我已有引擎和场景,我可以开始添加照相机、光源和网格来创建我的保龄球馆场景了。 ## 相机 Babylon.js 提供很多类型的照相机,每个都有自己的特定用途。在为游戏选择照相机之前,让我们先回顾一下最常见的类型: * 自由照相机是一种由第一人称拍摄的照相机。使用键盘上的箭头键,可以自由地在整个场景中移动它,并能使用鼠标设置方向。还可以视需要选择启用重力和碰撞检测。 * 弧形旋转照相机用于围绕特定的目标旋转。使用鼠标、键盘或触摸事件,用户可以全方位地查看对象。 * 触控照相机是一种使用触摸事件作为输入的自由照相机。它适合所有的移动平台。 * 跟随照相机自动跟踪特定目标。 Babylon.js 对 WebVR 和设备方向照相机提供本地支持。也就是说,您很容易就可以将此类设备列为 Oculus Rift 或 Google Cardboard。 第 2.1 版中引入的新概念让每种类型的照相机都支持 3D。也就是说,每种类型的照相机都可以设置为适应 Oculus Rift 式立体视图和红蓝眼镜(3D 立体)。图 6 展示了使用非立体照相机呈现的宇宙飞船场景,图 7 展示了使用立体照相机呈现的场景。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a819d870.png)  图 6:非 3D 立体照相机 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a81b79e3.png) 图 7:立体照相机 对于我的保龄球游戏,我将使用两种类型的照相机。第一种是玩家的主要照相机,用于设置保龄球的掷出位置。这就体现了自由照相机的确切用途。我还想添加不同的视图,即当球在球道中时,我想跟随它直到其撞击到保龄球瓶。 首先,我将添加自由照相机。createFreeCamera 函数将场景视作一个变量: ~~~ function createFreeCamera(scene) {   var camera = new BABYLON.FreeCamera(     "player camera", BABYLON.Vector3.Zero(), scene);   return camera; } ~~~ 我在场景的 0,0,0 位置处创建了照相机位置。稍后,我将把此函数扩展(必要时)为进一步配置照相机。 当然,别忘了最后将它添加到 init 函数中: ~~~ ... // Create the main player camera var camera = createFreeCamera(scene); // Attach the control from the canvas' user input camera.attachControl(engine.getRenderingCanvas()); // Set the camera to be the main active camera scene.activeCamera = camera; ~~~ attachControl 函数注册特定照相机所需的本地 JavaScript 事件监听器(如鼠标、触摸或键盘输入的事件监听器)。设置场景的活动照相机可以指示场景,此照相机应该用于呈现。 在启用掷球后,我将在第二部分中添加第二种照相机。 ## 创建球道 保龄球球道是一种相对简单的几何结构。我将先设置一些常量作为保龄球球道的实际尺寸(以米为单位)。我以米为单位是因为使用的是物理引擎(我将在本文的第二部分中予以解释)。 您可以在项目文件中看到常量。为了计算这些值,我参考了网上关于保龄球球道的可用信息。 在设置这些常量后,我就可以开始创建构成保龄球球道的网格了。图 8 展示了我的 (2D) 规划。我将先创建网格。然后,我会设置网格纹理(即指定材料)。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a81d2000.png)  图 8:保龄球球道场景的 2D 规划 首先,我将为场景创建全场地板: ~~~ function createFloor(scene) {   var floor = BABYLON.Mesh.CreateGround("floor", 100, 100, 1, scene, false);   return floor; } ~~~ 这会创建一块简单的 100x100 米地板。使用 Babylon.js 内部函数创建的所有网格都集中位于场景的 0,0,0 位置处。有三个重要的变量用于转换网格并在场景中正确定位网格: * mesh.position 是网格在空间中的位置的矢量 * mesh.scaling 是网格在每个轴中的比例系数 * mesh.rotation 是每个轴的旋转欧拉角(以弧度为单位);如果您更愿意使用四元(我知道我是这样),则可以改用 mesh.rotationQuaternion 在向 init 函数添加函数并启动场景后,我注意到一个有趣的现象,即我根本看不到我所添加的地板! 原因是照相机和地板两者均创建于空间的同一点 (0,0,0)。由于地面是完全平坦的,因此只有从高空(或低空)审视才会在屏幕上看到它。回到 createCamera 函数中的照相机初始化,我将第二个变量(照相机的初始位置)更改为一个新矢量。现在,照相机离地面有 1.7 个单位(在此示例中,单位为米): ~~~ var camera = new BABYLON.FreeCamera(   "cam", new BABYLON.Vector3(0,1.7,0), scene); ~~~ 如果您现在启动场景,则会看到地板拉伸超过屏幕的一半(如图 9 所示)。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a81f14d5.png) 图 9:向场景添加地板 尝试使用箭头和鼠标进行移动,以掌握如何控制自由照相机。 您会注意到地板是全黑的。就缺少光! 我将添加新的函数 createLight(稍后我将会扩展)。 ~~~ function createLight(scene) {   var light = new BABYLON.DirectionalLight(     "dir01", new BABYLON.Vector3(-0.5, -1, -0.5), scene);   // Set a position in order to enable shadows later   light.position = new BABYLON.Vector3(20, 40, 20);   return light; } ~~~ 别忘了将以下代码行添加到 init 函数中: ~~~ var light = createLight(scene); ~~~ Babylon.js 提供四种类型的光: * 半球光: 环境光,用地面颜色(正面向下的像素)、天空颜色(正面向上的像素)和反射颜色预定义。 * 点光: 从一个点向所有方向发射的光(如阳光)。 * 投射光: 从名称我们就可以看出,这是从一个点以特定发射半径向特定方向发射的光。此类光可以产生阴影。 * 定向光: 从任意位置向特定方向发射的光。虽然阳光可以为点光,但定向光可以更好地模拟阳光。此类光也可以产生阴影,我的示例中使用的就是这种光。 现在,地板将变成白色。Babylon.js 向尚未分配材料的每个网格分配默认的白色材料。 球道本身就是一个盒子,“躺”在我刚刚创建的地板上: ~~~ function createLane(scene) {   var lane = BABYLON.Mesh.CreateBox("lane", 1, scene, false);   lane.scaling = new BABYLON.Vector3(     laneWidth, laneHeight, totalLaneLength);   lane.position.y = laneHeight / 2; // New position due to mesh centering   lane.position.z = totalLaneLength / 2;   return lane; } ~~~ 再强调一次,别忘了将此函数添加到 init 中。 您可以看到我是如何使用缩放参数的。我创建了一个大小为 1x1x1 的盒子,然后将它的缩放设置更改为适应我预定义的常量。 使用同样的技术,我创建了两个盒子,它们将用作我球道两边的球槽(若以错误的方向掷出,则球会落入此槽)。您可以自己尝试创建看看,也可以查看随附的项目,看我是如何创建的。 ## 保龄球瓶和球 现在就差保龄球瓶和球了。为了创建保龄球瓶,我将使用圆柱体,只需将一个圆柱体倍增多次即可(确切地说,是 10 次)。在 Babylon.js 中,我们将这样倍增的对象称为实例。实例就是网格的精确副本(在空间中的转换除外)。也就是说,不能更改实例的几何图形和纹理,但可以更改实例的位置、缩放和旋转。我个人从未在场景中使用过原始对象;如果我想要 10 个保龄球瓶,我将会创建 1 个保龄球瓶并禁用它,然后在 10 个预定义位置上创建 10 个保龄球瓶实例: ~~~ function createPins(scene) {   // Create the main pin   var mainPin = BABYLON.Mesh.CreateCylinder(     "pin", pinHeight, pinDiameter / 2, pinDiameter, 6, 1, scene);   // Disable it so it won't show   mainPin.setEnabled(false);   return pinPositions.map(function (positionInSpace, idx) {     var pin = new BABYLON.InstancedMesh("pin-" + idx, mainPin);     pin.position = positionInSpace;     return pin;   }); } ~~~ 此函数中缺少的变量可以在项目文件中找到,包括 pinPositions(包含所有 10 个保龄球瓶的全局位置的数组)。 现在就差保龄球了。保龄球是一种简单的球体,上有 3 个方便手指插入的孔。为了创建此球体,我将使用 Babylon.js 提供的 CreateSphere 函数: ~~~ var sphere = BABYLON.Mesh.CreateSphere("sphere", 12, 0.22, scene); ~~~ 现在,我需要钻孔。为此,我将使用已集成到 Babylon.js 中的构造实体几何 (CSG) 功能。借助此功能,我可以向现有网格添加网格或从中去掉网格,或者可以向另一个几何体添加几何体或从中去掉几何体(如果能这样,就更好了)。也就是说,如果两个网格相交,我可以从中“去掉”一个网格,获得另一个经过更改的网格。在我的示例中,我想在一个球体中创建三个圆孔。圆柱体就完全适合。 首先,我将创建用于第一个孔的圆柱体: ~~~ var cylinder = BABYLON.Mesh.CreateCylinder(   "cylinder", 0.15, 0.02, 0.02, 8, 1, scene, false); ~~~ 接下来,我将把圆柱体的位置更改为与球体相交: ~~~ cylinder.position.y += 0.15; ~~~ 然后,我将创建 CSG 对象,并使用它们从球体中去掉圆柱体: ~~~ var sphereCSG = BABYLON.CSG.FromMesh(sphere); var cylinderCSG = BABYLON.CSG.FromMesh(cylinder); sphereCSG.subtractInPlace(cylinderCSG); var ball = sphereCSG.toMesh("test", sphere.material, scene, false); ~~~ 图 10 展示了球体和圆柱体,紧靠着的是使用 CSG 创建的保龄球。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a820b30d.png) 图 10:创建保龄球 图 11 和 [babylonjs-playground.com/#BIG0J](http://babylonjs-playground.com/#BIG0J) 上的园地均展示了从头开始创建保龄球的全部代码。 图 11:使用 CSG 创建保龄球 ~~~ // The original sphere, from which the ball will be made var sphere = BABYLON.Mesh.CreateSphere("sphere", 10.0, 10.0, scene); sphere.material = new BABYLON.StandardMaterial("sphereMat", scene); // Create pivot-parent-boxes to rotate the cylinders correctly var box1 = BABYLON.Mesh.CreateBox("parentBox", 1, scene); var box2 = box1.clone("parentBox"); var box3 = box1.clone("parentBox"); // Set rotation to each parent box box2.rotate(BABYLON.Axis.X, 0.3); box3.rotate(BABYLON.Axis.Z, 0.3); box1.rotate(new BABYLON.Vector3(0.5, 0, 0.5), -0.2); [box1, box2, box3].forEach(function (boxMesh) { // Compute the world matrix so the CSG will get the rotation correctly   boxMesh.computeWorldMatrix(true);   // Make the boxes invisible   boxMesh.isVisible = false; }); // Create the 3 cylinders var cylinder1 = BABYLON.Mesh.CreateCylinder(   "cylinder", 4, 1, 1, 30, 1, scene, false); cylinder1.position.y += 4; cylinder1.parent = box1; var cylinder2 = cylinder1.clone("cylinder", box2); var cylinder3 = cylinder1.clone("cylinder", box3); // Create the sphere's CSG object var sphereCSG = BABYLON.CSG.FromMesh(sphere); // Subtract all cylinders from the sphere's CSG object [cylinder1, cylinder2, cylinder3].forEach(function (cylinderMesh) {   sphereCSG.subtractInPlace(BABYLON.CSG.FromMesh(cylinderMesh)); }); // Create a new mesh from the sphere CSG var ball = sphereCSG.toMesh("bowling ball", sphere.material, scene, false); ~~~ ## 纹理 我创建的全部网格均分配有默认的白色材料。为了使场景更具吸引力,我应该添加其他材料。标准 Babylon.js 材料(默认着色器)有很多定义,我不会在此进行介绍。(若要详细了解默认 Babylon.js 着色器,您可以试用 [materialeditor.raananweber.com](http://materialeditor.raananweber.com/) 上的 BabylonJS 材料编辑器。) 不过,我将介绍我是如何设置球道和保龄球的纹理的。 为了设置保龄球的纹理,我将使用另一项精彩的 Babylon.js 功能,即过程化纹理。过程化纹理不是使用 2D 图像的标准纹理,而是以编程方式创建的纹理(由 GPU(而不是 CPU)生成),能够对场景的效果产生积极影响。Babylon 提供多种类型的过程化纹理(木质、砖块、火、云、草等)。我将要使用的是大理石纹理。 在创建保龄球的网格后,添加以下代码行会让保龄球变成绿色的大理石球(如图 12 所示): ~~~ var marbleMaterial = new BABYLON.StandardMaterial("ball", scene); var marbleTexture = new BABYLON.MarbleProceduralTexture(   "marble", 512, scene); marbleTexture.numberOfTilesHeight = 2; marbleTexture.numberOfTilesWidth = 2; marbleMaterial.ambientTexture = marbleTexture; // Set the diffuse color to the wanted ball's color (green) marbleMaterial.diffuseColor = BABYLON.Color3.Green(); ball.material = marbleMaterial; ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a8230a07.png) 图 12:应用于保龄球的大理石纹理 可以使用标准材料的漫射纹理,向球道添加木质纹理。不过,这不是我要谈论球道材料的原因所在。如果您看过真实的保龄球球道,则会注意到球道上面有多组点和一组箭头或三角形。为了模拟这样的球道,我可以创建一个非常大的纹理,其上包含所有这些元素,但这样做可能会影响性能(由于纹理非常大)或降低图像质量。 我也可以使用贴花纸,这是 Babylon.js 2.1 中引入的一项新功能。借助贴花纸,您可以在已设置纹理的网格之上“绘制”图形。例如,贴花纸可用于模拟墙上的枪孔,或在保龄球球道上添加装饰(如我的示例所示)。由于贴花纸是网格,因此使用标准材料设置纹理。图 13 展示了我是如何添加边线的,图 14 展示了在我添加贴花纸后保龄球球道的外观,以及在我将过程化纹理(砖块和草)用作材料后地板和球槽的外观。 图 13:添加边线贴花纸 ~~~ // Set the decal's position var foulLinePosition = new BABYLON.Vector3(0, laneHeight, foulLaneDistance); var decalSize = new BABYLON.Vector3(1,1,1); // Create the decal (name, the mesh to add it to, position, up vector and the size) var foulLine = BABYLON.Mesh.CreateDecal("foulLine", lane, foulLinePosition, BABYLON.Vector3.Up(), decalSize); // Set the rendering group so it will render after the lane foulLine.renderingGroupId = 1; // Set the material var foulMaterial = new BABYLON.StandardMaterial("foulMat", scene); foulMaterial.diffuseTexture =   new BABYLON.Texture("Assets/dots2-w-line.png", scene); foulMaterial.diffuseTexture.hasAlpha = true; foulLine.material = foulMaterial; // If the action manager wasn't initialized, create a new one scene.actionManager = new BABYLON.ActionManager(scene); // Register an action to generate a new color each time I press "c" scene.actionManager.registerAction(new BABYLON.ExecuteCodeAction({ trigger: BABYLON.ActionManager.OnKeyUpTrigger, parameter: "c" },   // The function to execute every time "c" is pressed"   function () {     ball.material.diffuseColor =       new BABYLON.Color3(Math.random(), Math.random(), Math.random());   } )); ~~~ ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-08_568f2a8254ce6.png) 图 14:添加了贴花纸的球道 ## 用户输入 - Babylon.js 操作管理器 作为功能齐全的游戏引擎,Babylon.js 提供了一种与用户输入进行交互的简单方式。假设我想使用 C 键更改保龄球的颜色。每次按下 C,我都想为保龄球设置一种随机颜色: ~~~ // If the action manager wasn't initialized, create a new one scene.actionManager = new BABYLON.ActionManager(scene); // Register an action to generate a new color each time I press C scene.actionManager.registerAction(   new BABYLON.ExecuteCodeAction({ trigger:   BABYLON.ActionManager.OnKeyUpTrigger, parameter: "c" },   // The function to execute every time C is pressed   function () {     ball.material.diffuseColor =       new BABYLON.Color3(Math.random(), Math.random(), Math.random());   } )); ~~~ Babylon.js 操作管理器是一款功能强大的工具,可用于根据触发器控制操作。触发器可以是鼠标移动或单击、网格相交或键盘输入。有很多触发器和操作可供选择。请访问 Babylon.js 教程站点 ([bit.ly/1MEkNRo](http://bit.ly/1MEkNRo)),了解全部触发器和操作。 我将使用操作管理器控制保龄球并重置场景。我将在本教程的第 2 部分中添加这些操作。 ## 使用外部资源 我已使用 Babylon.js 的内部函数创建了所需的网格。大多数情况下,这是不够的。Babylon.js 提供了很多网格(从球体和盒子到复杂的带状物),但创建复杂的模型是很难的,如人、Web 版 Doom 中的武器或 Space Invaders 克隆中的宇宙飞船。 Babylon.js 为很多知名的 3D 工具(如 Blender 和 3D-Studio)提供了导出程序插件。您也可以从出色的 Clara.io 中导出您的模型,然后下载 .babylon 文件。 Babylon.js 使用自己的文件格式,这种格式可以包含整个场景,包括网格、照相机、光、动画、几何体和其他信息。因此,如果您愿意,可以将 Blender 仅用于模拟整个场景。您还可以导入单个网格。 不过,这并不在本教程的范围之内。对于本文,我只想展示如何只使用 Babylon.js 创建简单的游戏。 ## 下一步是什么? 我已跳过 Babylon.js 中集成的许多功能。它具有大量功能,我强烈建议您查看园地 ([babylonjs-playground.com](http://babylonjs-playground.com/))、文档页 ([doc.babylonjs.com](http://doc.babylonjs.com/)) 和 Babylon.js 主页 ([babylonjs.com](http://babylonjs.com/)),看看如何开创无限可能。如果您觉得本教程的任何部分比较难懂,请联系我或十分活跃的 Babylon.js HTML5 游戏开发论坛 ([bit.ly/1GmUyzq](http://bit.ly/1GmUyzq)) 上的任何一位 Babylon.js 大神。 在下一篇文章中,我将创建实际的游戏,即添加物理特性和碰撞检测、掷球功能、音频等。 * * * Raanan Weber *既是一名 IT 顾问、完整堆栈开发者,也是一名丈夫和父亲。空闲时,他为 Babylon.js 和其他开放源代码项目献计献策。您可以阅读他的博客 ([blog.raananweber.com](http://blog.raananweber.com/))。*
';