From 823d901af9407f554bbcc6206dff1e20a2fa5d3a Mon Sep 17 00:00:00 2001 From: allo Date: Sun, 3 Jul 2022 15:16:30 +0800 Subject: [PATCH] convert to markdown for games zh-CN --- files/zh-cn/games/anatomy/index.md | 297 ++++++------- files/zh-cn/games/examples/index.md | 200 ++++----- files/zh-cn/games/index.md | 132 +++--- files/zh-cn/games/introduction/index.md | 149 +++---- .../index.md | 135 +++--- .../game_distribution/index.md | 134 +++--- .../game_monetization/index.md | 86 ++-- .../publishing_games/game_promotion/index.md | 76 ++-- files/zh-cn/games/publishing_games/index.md | 16 +- .../2d_collision_detection/index.md | 84 ++-- .../3d_collision_detection/index.md | 151 ++++--- .../3d_on_the_web/basic_theory/index.md | 124 +++--- .../index.md | 286 ++++++------ .../3d_on_the_web/glsl_shaders/index.md | 197 +++++---- .../games/techniques/3d_on_the_web/index.md | 116 +++-- .../games/techniques/async_scripts/index.md | 52 ++- .../techniques/control_mechanisms/index.md | 60 +-- .../control_mechanisms/mobile_touch/index.md | 156 ++++--- .../techniques/controls_gamepad_api/index.md | 190 ++++---- files/zh-cn/games/techniques/index.md | 36 +- files/zh-cn/games/tools/index.md | 45 +- .../animations_and_tweens/index.md | 106 ++--- .../bounce_off_the_walls/index.md | 40 +- .../build_the_brick_field/index.md | 115 ++--- .../2d_breakout_game_phaser/buttons/index.md | 93 ++-- .../collision_detection/index.md | 44 +- .../extra_lives/index.md | 97 ++-- .../game_over/index.md | 40 +- .../2d_breakout_game_phaser/index.md | 64 ++- .../initialize_the_framework/index.md | 95 ++-- .../index.md | 57 ++- .../move_the_ball/index.md | 35 +- .../2d_breakout_game_phaser/physics/index.md | 79 ++-- .../player_paddle_and_controls/index.md | 124 +++--- .../randomizing_gameplay/index.md | 54 ++- .../2d_breakout_game_phaser/scaling/index.md | 56 ++- .../the_score/index.md | 65 ++- .../win_the_game/index.md | 35 +- .../bounce_off_the_walls/index.md | 106 +++-- .../build_the_brick_field/index.md | 97 ++-- .../collision_detection/index.md | 121 ++--- .../create_the_canvas_and_draw_on_it/index.md | 121 ++--- .../finishing_up/index.md | 103 +++-- .../game_over/index.md | 78 ++-- .../2d_breakout_game_pure_javascript/index.md | 56 +-- .../mouse_controls/index.md | 50 +-- .../move_the_ball/index.md | 107 ++--- .../paddle_and_keyboard_controls/index.md | 117 ++--- .../track_the_score_and_win/index.md | 82 ++-- .../index.md | 418 ++++++++++-------- files/zh-cn/games/tutorials/index.md | 18 +- 51 files changed, 2698 insertions(+), 2697 deletions(-) diff --git a/files/zh-cn/games/anatomy/index.md b/files/zh-cn/games/anatomy/index.md index aeb8445aae68d3..51b55bb451cd87 100644 --- a/files/zh-cn/games/anatomy/index.md +++ b/files/zh-cn/games/anatomy/index.md @@ -8,57 +8,56 @@ tags: - requestAnimationFrame translation_of: Games/Anatomy --- -
{{GamesSidebar}}
+{{GamesSidebar}} -
-

本文从技术角度分析了一般电子游戏的结构和工作流程,就此介绍主循环是如何运行的。它有助于初学者了解在现代游戏开发领域构建游戏时需要什么,以及如何将 JavaScript 这样的 Web 标准工具作为自己的工具使用。游戏开发经验丰富但不熟悉 Web 开发的开发者也能从中受益。

-
+本文从技术角度分析了一般电子游戏的结构和工作流程,就此介绍主循环是如何运行的。它有助于初学者了解在现代游戏开发领域构建游戏时需要什么,以及如何将 JavaScript 这样的 Web 标准工具作为自己的工具使用。游戏开发经验丰富但不熟悉 Web 开发的开发者也能从中受益。 -

呈现,接收,解释,计算,重复

+## 呈现,接收,解释,计算,重复 -

所有电子游戏的目标都是向用户(们)呈现一个场景,接收他们的输入,将这些输入信号解释为动作,并计算出由这些动作产生的新场景。游戏不断地循环遍历,一遍又一遍,直到遇到某些终止条件(比如赢,输或者退出睡觉)。毫不奇怪,这种模式与游戏引擎的编程方式相呼应。

+所有电子游戏的目标都是向用户(们)**呈现**一个场景,**接收**他们的输入,将这些输入信号**解释**为动作,并**计算**出由这些动作产生的新场景。游戏不断地循环遍历,一遍又一遍,直到遇到某些终止条件(比如赢,输或者退出睡觉)。毫不奇怪,这种模式与游戏引擎的编程方式相呼应。 -

具体情况取决于游戏本身。

+具体情况取决于游戏本身。 -

一些游戏通过用户输入来驱动这个循环。想象一下,你正在开发一种“大家来找茬”类型的游戏。这些游戏向用户呈现两张图片,游戏接收点击(或触摸);将用户输入解释为成功,失败,暂停,菜单交互等。最后,游戏根据用户的输入计算并更新游戏场景。这种游戏是由用户的输入驱动,也就是说,它会在用户进行输入之后冻结画面,等待玩家进行新的输入。这是一种基于回合的游戏类型,它不需要每帧持续更新画面,只有当玩家作出反应时才会。

+一些游戏通过**用户输入**来驱动这个循环。想象一下,你正在开发一种“大家来找茬”类型的游戏。这些游戏向用户**呈现**两张图片,游戏**接收**点击(或触摸);将用户输入**解释**为成功,失败,暂停,菜单交互等。最后,游戏根据用户的输入**计算并更新**游戏场景。这种游戏是由用户的输入驱动,也就是说,它会在用户进行输入之后冻结画面,等待玩家进行新的输入。这是一种基于回合的游戏类型,它不需要每帧持续更新画面,只有当玩家作出反应时才会。 -

另一些游戏需要尽可能控制每一个细微的时间片(动画)。与上述原理有点小区别:每个动画帧都将循环遍历,并在之后第一个可用的轮次捕获玩家输入的任何变化。这种 每帧一次 的模型是通过一个叫主循环的东西实现的。如果您的游戏循环是基于时间的,则必须保证对主循环精准的模拟。

+另一些游戏需要尽可能控制每一个细微的时间片(动画)。与上述原理有点小区别:每个动画帧都将循环遍历,并在之后第一个可用的轮次捕获玩家输入的任何变化。这种 **每帧一次** 的模型是通过一个叫**主循环**的东西实现的。如果您的游戏循环是基于时间的,则必须保证对主循环精准的模拟。 -

但它也可能不需要逐帧控制。您的游戏循环可能类似找不同的例子,并以输入事件作为基础。它可能需要输入和模拟时间片。它甚至可以基于其他的东西来循环。

+但它也可能不需要逐帧控制。您的游戏循环可能类似找不同的例子,并以输入事件作为基础。它可能需要输入和模拟时间片。它甚至可以基于其他的东西来循环。 -

现代 JavaScript - 正如下一节中所描述的 - 它可以轻松开发出一个高效的,逐帧执行的主循环,这很值得庆幸。当然,您的游戏只会按照您所做的那样优化。如果某些东西看起来应该被添加到一个更罕见的事件里,那么将它从主循环中剥离出来通常是个好主意(但并非总是如此)。

+现代 JavaScript - 正如下一节中所描述的 - 它可以轻松开发出一个高效的,逐帧执行的主循环,这很值得庆幸。当然,您的游戏只会按照您所做的那样优化。如果某些东西看起来应该被添加到一个更罕见的事件里,那么将它从主循环中剥离出来通常是个好主意(但并非总是如此)。 -

在 JavaScript 中构建一个主循环

+## 在 JavaScript 中构建一个主循环 -

JavaScript 能很好的处理事件和回调函数。现代浏览器努力在需要的时候调用方法,并在间隙中闲下来(或做其他任务)。将您的代码附加到适合它们的时刻是一个很好的主意。考虑一下你的函数是需要在严格的时间周期内,还是每一帧,或者仅仅是在发生了其他情况之后执行。当您的函数需要被调用时,要更具体地使用浏览器,这样浏览器就可以在调用时进行优化。而且,这可能会让你的工作更轻松。

+JavaScript 能很好的处理事件和回调函数。现代浏览器努力在需要的时候调用方法,并在间隙中闲下来(或做其他任务)。将您的代码附加到适合它们的时刻是一个很好的主意。考虑一下你的函数是需要在严格的时间周期内,还是每一帧,或者仅仅是在发生了其他情况之后执行。当您的函数需要被调用时,要更具体地使用浏览器,这样浏览器就可以在调用时进行优化。而且,这可能会让你的工作更轻松。 -

有些代码需要逐帧运行,所以应将其附加到浏览器的重绘周期中,没有比这更好的了!在 Web 中,通常 window.requestAnimationFrame()方法是大多数良好的逐帧循环的基础。在调用该方法时必须传入一个回调函数,这个回调函数将在下一次重新绘制之前执行。下面是一个简单的主循环的例子。:

+有些代码需要逐帧运行,所以应将其附加到浏览器的重绘周期中,没有比这更好的了!在 Web 中,通常 `window.requestAnimationFrame()`方法是大多数良好的逐帧循环的基础。在调用该方法时必须传入一个回调函数,这个回调函数将在下一次重新绘制之前执行。下面是一个简单的主循环的例子。: -
window.main = function(){
+```js
+window.main = function(){
   window.requestAnimationFrame(main);
 
   //无论你的主循环需要做什么
 };
 
-main(); //开始循环
+main(); //开始循环 +``` -
-

备注: 在这里讨论的每个 main() 方法中,在执行循环内容之前,我们会递归调用一个新的requestAnimationFrame,这不是随意的,它被认为是最佳实践。如果你的当前帧错过了它的垂直同步窗口的周期,你也在下一个帧通过requestAnimationFrame 尽早的调用main(),从而确保浏览器能够及时地执行。

-
+> **备注:** 在这里讨论的每个 `main()` 方法中,在执行循环内容之前,我们会递归调用一个新的`requestAnimationFrame`,这不是随意的,它被认为是最佳实践。如果你的当前帧错过了它的垂直同步窗口的周期,你也在下一个帧通过`requestAnimationFrame` 尽早的调用`main()`,从而确保浏览器能够及时地执行。 -

上面的代码块有两个语句。第一个语句创建一个名为main()中的全局变量的函数。这个函数做一些工作,也告诉浏览器在下一帧通过window.requestAnimationFrame()调用本身。第二个语句调用第一个语句中定义的main()函数。因为main()中在第二个语句中被调用一次,而每次调用都将自身又放置到下一个帧的执行队列中,因此main()的调用与您的帧率同步。

+上面的代码块有两个语句。第一个语句创建一个名为`main()`中的全局变量的函数。这个函数做一些工作,也告诉浏览器在下一帧通过`window.requestAnimationFrame()`调用本身。第二个语句调用第一个语句中定义的`main()`函数。因为`main()`中在第二个语句中被调用一次,而每次调用都将自身又放置到下一个帧的执行队列中,因此`main()`的调用与您的帧率同步。 -

当然,这个循环并不完美。不过在讨论如何改善之前,让我们先讨论一下它已经做好了什么。

+当然,这个循环并不完美。不过在讨论如何改善之前,让我们先讨论一下它已经做好了什么。 -

将主循环的时机安排在浏览器每次的绘制显示中,允许您能像浏览器想要绘制的那样频繁的运行您的循环。你能够控制每一帧动画,并且main()是循环中唯一执行的函数,所以这很简单。主视角射击游戏(或类似的游戏)每一帧都会出现一个新的场景。没有比这种方法更平滑并绘制及时的了。

+将主循环的时机安排在浏览器每次的绘制显示中,允许您能像浏览器想要绘制的那样频繁的运行您的循环。你能够控制每一帧动画,并且`main()`是循环中唯一执行的函数,所以这很简单。主视角射击游戏(或类似的游戏)每一帧都会出现一个新的场景。没有比这种方法更平滑并绘制及时的了。 -

但是不要马上认为动画必需要帧帧控制。通过 CSS 动画或浏览器中的其他工具,可以很容易实现简单的动画,甚至 GPU 加速。有很多这样的东西,它们会让你的工作更轻松。

+但是不要马上认为动画必需要帧帧控制。通过 CSS 动画或浏览器中的其他工具,可以很容易实现简单的动画,甚至 GPU 加速。有很多这样的东西,它们会让你的工作更轻松。 -

在 Javascript 中构建一个更好的主循环

+## 在 Javascript 中构建一个更好的主循环 -

在前面的主循环中有两个明显的问题:main()污染了 window对象(所有全局变量存储的对象),并且示例代码没有给我们留下一个停止循环的方法,除非整个浏览器选项卡被关闭或刷新。对于第一个问题,如果您希望主循环只运行,并且不需要被简单(直接)访问它,您可以将它作为一个立即调用的函数表达式(IIFE)创建。

+在前面的主循环中有两个明显的问题:`main()`污染了 ` window``对象 `(所有全局变量存储的对象),并且示例代码没有给我们留下一个停止循环的方法,除非整个浏览器选项卡被关闭或刷新。对于第一个问题,如果您希望主循环只运行,并且不需要被简单(直接)访问它,您可以将它作为一个立即调用的函数表达式(IIFE)创建。 -
/*
+```js
+/*
 *
 */
 
@@ -70,17 +69,17 @@ main(); //开始循环
} main(); //开始循环 -})(); +})(); +``` -

当浏览器遇到这个 IIFE 时,它将定义您的主循环,并立即将其加入下一个帧的更新队列中。main(或main()方法)不会被附加到任何对象,在应用程序的其他地方仍是一个有效的未使用的名称,仍可以自由地定义为其他的东西。

+当浏览器遇到这个 IIFE 时,它将定义您的主循环,并立即将其加入下一个帧的更新队列中。`main`(或`main()`方法)不会被附加到任何对象,在应用程序的其他地方仍是一个有效的未使用的名称,仍可以自由地定义为其他的东西。 -
-

备注: 在实践中,更常见的终止下一个requestAnimationFrame()方式是使用 if 语句,而不是调用cancelAnimationFrame()

-
+> **备注:** 在实践中,更常见的终止下一个`requestAnimationFrame()`方式是使用 if 语句,而不是调用`cancelAnimationFrame()`。 -

对于第二个问题,要终止循环,您需要调用 window.cancelAnimationFrame()来取消main()的调用。该方法需要传入你最后一次调用requestAnimationFrame()时返回的 ID。让我们假设您的游戏的函数和变量是建立在您称为 MyGame 的名称空间上。扩展我们的最后一个例子,主循环现在看起来是这样的:

+对于第二个问题,要终止循环,您需要调用` ``window.cancelAnimationFrame()`来取消`main()`的调用。该方法需要传入你最后一次调用`requestAnimationFrame()`时返回的 ID。让我们假设您的游戏的函数和变量是建立在您称为 MyGame 的名称空间上。扩展我们的最后一个例子,主循环现在看起来是这样的: -
/*
+```js
+/*
 * 让我们假设 MyGame 是之前定义的。
 */
 
@@ -92,41 +91,42 @@ main(); //开始循环
} main(); //开始循环 -})(); +})(); +``` -

现在,我们在 MyGame 名称空间中声明了一个变量stopMain,其值为主循环最后调用requestAnimationFrame()时返回的 ID。任何时候,我们可以通过告诉浏览器取消与 ID 相对应的请求来停止主循环。

+现在,我们在 MyGame 名称空间中声明了一个变量`stopMain`,其值为主循环最后调用`requestAnimationFrame()`时返回的 ID。任何时候,我们可以通过告诉浏览器取消与 ID 相对应的请求来停止主循环。 -
window.cancelAnimationFrame(MyGame.stopMain);
+ window.cancelAnimationFrame(MyGame.stopMain); -

在 JavaScript 的中编写主循环的关键在于,考虑到任何会驱动你行为的事件,并注意不同的系统是如何相互作用的。您可能拥有多个由多个不同类型的事件驱动的组件。这看起来像是不必要的复杂性,但它可能就是一个很好的优化(当然,不一定是这样的)。问题是,您并不是在编写一个典型的主循环。在 Java 脚本中,您使用的是浏览器的主循环,并且您正在尝试这样做。

+在 JavaScript 的中编写**主循环**的关键在于,考虑到任何会驱动你行为的事件,并注意不同的系统是如何相互作用的。您可能拥有多个由多个不同类型的事件驱动的组件。这看起来像是不必要的复杂性,但它可能就是一个很好的优化(当然,不一定是这样的)。问题是,您并不是在编写一个典型的主循环。在 Java 脚本中,您使用的是浏览器的主循环,并且您正在尝试这样做。 -

用 JavaScript 构建一个更优化的主循环

+## 用 JavaScript 构建一个更优化的主循环 -

基本上,在 JavaScript 的中,浏览器有它自己的主循环,而你的代码存在于循环某些阶段。上面描述的主循环,试图避免脱离浏览器的控制。这种主循环附着于window.requestAnimationFrame()方法,该方法将在浏览器的下一帧中执行,具体取决于浏览器如何与将其自己的主循环关联起来。W3C 规范并没有真正定义什么时候浏览器必须执行 requestAnimationFrame 回调。这有一个好处,浏览器厂商可以自由地实现他们认为最好的解决方案,并随着时间的推移进行调整。

+基本上,在 JavaScript 的中,浏览器有它自己的主循环,而你的代码存在于循环某些阶段。上面描述的主循环,试图避免脱离浏览器的控制。这种主循环附着于`window.requestAnimationFrame()`方法,该方法将在浏览器的下一帧中执行,具体取决于浏览器如何与将其自己的主循环关联起来。[W3C 规范](/en-US/docs/Games/Anatomy)并没有真正定义什么时候浏览器必须执行 requestAnimationFrame 回调。这有一个好处,浏览器厂商可以自由地实现他们认为最好的解决方案,并随着时间的推移进行调整。 -

现代版的 Firefox 和 Google Chrome(可能还有其他版本)试图在框架的时间片的开始时将请求 AnimationFrame 回调与它们的主线程进行连接。因此,浏览器的主线程看起来就像下面这样:

+现代版的 Firefox 和 Google Chrome(可能还有其他版本)试图在框架的时间片的开始时将请求 AnimationFrame 回调与它们的主线程进行连接。因此,浏览器的主线程看起来就像下面这样: -
    -
  1. 启动一个新帧(而之前的帧由显示处理)。
  2. -
  3. 遍历 requestAnimationFrame 回调并调用它们。
  4. -
  5. 当上面的回调停止控制主线程时,执行垃圾收集和其他帧任务。
  6. -
  7. 睡眠(除非事件打断了浏览器的小睡),直到显示器准备好你的图像(VSYNC)并重复。
  8. -
+1. 启动一个新帧(而之前的帧由显示处理)。 +2. 遍历 requestAnimationFrame 回调并调用它们。 +3. 当上面的回调停止控制主线程时,执行垃圾收集和其他帧任务。 +4. 睡眠(除非事件打断了浏览器的小睡),直到显示器准备好你的图像(VSYNC)并重复。 -

您可以考虑开发实时应用程序,因为有时间做工作。所有上述步骤都必须在每 16 毫秒内进行一次,以保持 60 赫兹的显示效果。浏览器会尽可能早地调用您的代码,从而给它最大的计算时间。您的主线程通常会启动一些甚至不在主线程上的工作负载(如 WebGL 的中的光栅化或着色器)。在浏览器使用其主线程管理垃圾收集,其他任务或处理异步事件时,可以在 Web Worker 或 GPU 上执行长时间的计算。

+您可以考虑开发实时应用程序,因为有时间做工作。所有上述步骤都必须在每 16 毫秒内进行一次,以保持 60 赫兹的显示效果。浏览器会尽可能早地调用您的代码,从而给它最大的计算时间。您的主线程通常会启动一些甚至不在主线程上的工作负载(如 WebGL 的中的光栅化或着色器)。在浏览器使用其主线程管理垃圾收集,其他任务或处理异步事件时,可以在 Web Worker 或 GPU 上执行长时间的计算。 -

当我们讨论预算时,许多网络浏览器都有一个称为高分辨率时间的工具.{{ domxref("Date") }} 对象不再是计时事件的识别方法,因为它非常不精确,可以由系统时钟进行修改。另一方面,高分辨率的时间计算自 navigationStart(当上一个文档被卸载时)的毫秒数。这个值以小数的精度返回,精确到千分之一毫秒。它被称为{{ domxref("DOMHighResTimeStamp") }},但是,无论出于什么目的和目的,都认为它是一个浮点数。

+当我们讨论预算时,许多网络浏览器都有一个称为高分辨率时间的工具.{{ domxref("Date") }} 对象不再是计时事件的识别方法,因为它非常不精确,可以由系统时钟进行修改。另一方面,高分辨率的时间计算自 navigationStart(当上一个文档被卸载时)的毫秒数。这个值以小数的精度返回,精确到千分之一毫秒。它被称为{{ domxref("DOMHighResTimeStamp") }},但是,无论出于什么目的和目的,都认为它是一个浮点数。 -

注意:系统(硬件或软件)不能达到微秒精度,可以提供毫秒精度的最小值然而,如果他们能够做到这一点,他们就应该提供 0.001 的准确性。

+注意:系统(硬件或软件)不能达到微秒精度,可以提供毫秒精度的最小值然而,如果他们能够做到这一点,他们就应该提供 0.001 的准确性。 -

这个值本身并不太有用,因为它与一个相当无趣的事件相关,但它可以从另一个时间戳中减去,以便准确准确地确定这两个点之间的时间间隔。要获得这些时间戳中的一个,您可以调用 window.performance.now()并将结果存储为一个变量。

+这个值本身并不太有用,因为它与一个相当无趣的事件相关,但它可以从另一个时间戳中减去,以便准确准确地确定这两个点之间的时间间隔。要获得这些时间戳中的一个,您可以调用 window\.performance.now()并将结果存储为一个变量。 -
var tNow = window.performance.now();
-
+```js +var tNow = window.performance.now(); +``` -

回到主循环的主题。您将经常想知道何时调用主函数。因为这是常见的,window.requestAnimationFrame()总是提供一个 DOMHighResTimeStamp 执行时回调函数作为参数。这将导致我们之前的主循环的另一个增强。

+回到主循环的主题。您将经常想知道何时调用主函数。因为这是常见的,window\.requestAnimationFrame()总是提供一个 DOMHighResTimeStamp 执行时回调函数作为参数。这将导致我们之前的主循环的另一个增强。 -
/*
+```js
+/*
 * 以分号开始,以上例子中的代码行都是这样的
 * 依靠自动分号插入 (ASI)。浏览器可能会意外
 * 认为这个整个例子从上一行继续。领先分号
@@ -144,91 +144,82 @@ main(); //开始循环
} main(); //开始循环 -})(); +})(); +``` -

其他一些优化是可能的,这取决于你的游戏想要完成什么。你的游戏类型显然会有所不同,但它甚至可能比这更微妙。您可以在画布上单独绘制每个像素,也可以将 DOM 元素(包括具有透明背景的多个 WebGL 的画布)放入复杂的层次结构中。每条路径都将导致不同的机会和约束。

+其他一些优化是可能的,这取决于你的游戏想要完成什么。你的游戏类型显然会有所不同,但它甚至可能比这更微妙。您可以在画布上单独绘制每个像素,也可以将 DOM 元素(包括具有透明背景的多个 WebGL 的画布)放入复杂的层次结构中。每条路径都将导致不同的机会和约束。 -

决定......时间

+## 决定......时间 -

您将需要对您的主循环作出艰难的决定:如何模拟准确的时间进度。如果你想要控制每一帧,那么你需要确定你的游戏更新和绘制的频率,您甚至可能希望以不同的速率进行更新和绘制。您还需要考虑如果用户的系统无法跟上工作负载,那么您还需考虑如何优雅降级,以保证性能。让我们首先假定你会在每次绘制时,同时处理用户的输入,并更新游戏状态。我们稍后再细讲。

+您将需要对您的主循环作出艰难的决定:如何模拟准确的时间进度。如果你想要控制每一帧,那么你需要确定你的游戏更新和绘制的频率,您甚至可能希望以不同的速率进行更新和绘制。您还需要考虑如果用户的系统无法跟上工作负载,那么您还需考虑如何优雅降级,以保证性能。让我们首先假定你会在每次绘制时,同时处理用户的输入,并更新游戏状态。我们稍后再细讲。 -

注意:改变主循环如何处理时间是非常困难的,在进行主循环之前,请仔细考虑您的需求。

+注意:改变主循环如何处理时间是非常困难的,在进行主循环之前,请仔细考虑您的需求。 -

大多数浏览器游戏应该是什么样的

+### 大多数浏览器游戏应该是什么样的 -

如果你的游戏可以达到你所支持的任何硬件的最大刷新率,那么你的工作就变得相当容易了。你可以简单地进行更新,渲染,然后在垂直同步之前什么都不用做。

+如果你的游戏可以达到你所支持的任何硬件的最大刷新率,那么你的工作就变得相当容易了。你可以简单地进行更新,渲染,然后在垂直同步之前什么都不用做。 -
/*
-* 以分号开始,以上例子中的代码行都是这样的
-* 依靠自动分号插入 (ASI)。浏览器可能会意外
-* 认为这个整个例子从上一行继续。领先分号
-* 标记我们的新行的开始,如果前一个不是空或终止。
-*
-* 我们还假设 MyGame 是以前定义的。
-*/
+    /*
+    * 以分号开始,以上例子中的代码行都是这样的
+    * 依靠自动分号插入 (ASI)。浏览器可能会意外
+    * 认为这个整个例子从上一行继续。领先分号
+    * 标记我们的新行的开始,如果前一个不是空或终止。
+    *
+    * 我们还假设 MyGame 是以前定义的。
+    */
 
-;(function(){
-  function main(tFrame){
-    MyGame.stopMain = window.requestAnimationFrame(main);
+    ;(function(){
+      function main(tFrame){
+        MyGame.stopMain = window.requestAnimationFrame(main);
 
-    update(Frame); //调用 update 方法。在我们的例子中,我们给它 rAF 的时间戳。
-    render();
-  }
+        update(Frame); //调用 update 方法。在我们的例子中,我们给它 rAF 的时间戳。
+        render();
+      }
 
-  main(); //开始循环
-})();
- -

如果无法达到最大刷新率,可以调整画面质量设置以保持你的时间预算。这个概念最有名的例子是 ID Software 的 RAGE 游戏 ,这个游戏取消了用户的控制权,以使其计算时间保持在大约 16ms(或大约 60fps)。如果计算时间过长,则提交的解析度就降低,纹理和其他资源将无法加载或绘制等。这个(非网络)案例研究做了一些假设和折衷:

- - - -

处理可变刷新率需求的其他方法

- -

存在其他解决问题的方法。

- -

一种常见的技术是以恒定的频率更新模拟,然后绘制尽可能多的(或尽可能少的)实际帧。更新方法可以继续循环,而不用考虑用户看到的内容。绘图方法可以查看最后的更新以及发生的时间。由于绘制知道何时表示,以及上次更新的模拟时间,它可以预测为用户绘制一个合理的框架。这是否比官方更新循环更频繁(甚至更不频繁)无关紧要。更新方法设置检查点,并且像系统允许的那样频繁地,渲染方法画出周围的时间。在 Web 标准中分离更新方法有很多种方法:

- - - -

这些方法中的每一种都有类似的权衡:

- - - -

单独的更新和绘图方法可能如下面的示例。为了演示,该示例基于第三个项目符号,只是不使用 Web Workers 进行可读性(而且我们诚实地说可写性)。

- -

注意:这个例子,具体来说,需要进行技术审查。

- -
/*
+      main(); //开始循环
+    })();
+
+如果无法达到最大刷新率,可以调整画面质量设置以保持你的时间预算。这个概念最有名的例子是 ID Software 的 RAGE 游戏 ,这个游戏取消了用户的控制权,以使其计算时间保持在大约 16ms(或大约 60fps)。如果计算时间过长,则提交的解析度就降低,纹理和其他资源将无法加载或绘制等。这个(非网络)案例研究做了一些假设和折衷:
+
+- 每个动画帧都占用户输入。
+- 没有帧需要外推(猜测),因为每个绘图都有自己的更新。
+- 仿真系统基本上可以假定每次完全更新间隔约 16ms。
+- 给用户控制质量设置将是一场噩梦。
+- 不同的监视器以不同的速率输入:30FPS,75FPS,100FPS,120FPS,144FPS 等
+- 无法跟上 60 FPS 的系统会失去视觉质量,以保持游戏运行的最佳速度(最终如果质量太低,则会彻底失败)。
+
+### 处理可变刷新率需求的其他方法
+
+存在其他解决问题的方法。
+
+一种常见的技术是以恒定的频率更新模拟,然后绘制尽可能多的(或尽可能少的)实际帧。更新方法可以继续循环,而不用考虑用户看到的内容。绘图方法可以查看最后的更新以及发生的时间。由于绘制知道何时表示,以及上次更新的模拟时间,它可以预测为用户绘制一个合理的框架。这是否比官方更新循环更频繁(甚至更不频繁)无关紧要。更新方法设置检查点,并且像系统允许的那样频繁地,渲染方法画出周围的时间。在 Web 标准中分离更新方法有很多种方法:
+
+- 绘制`requestAnimationFrame`并更新 {{ domxref("window.setInterval") }}或{{domxref("window.setTimeout")}}。
+
+  - 即使在未聚焦或最小化的情况下,使用处理器时间,也可能是主线程,并且可能是传统游戏循环的工件(但是很简单)。
+
+- 绘制`requestAnimationFrame`和更新一个`setInterval`或`setTimeout`一个[Web 工作者](/en-US/docs/Web/Guide/Performance/Using_web_workers)。
+
+  - 这与上述相同,除了更新不会使主线程(主线程也没有)。这是一个更复杂的解决方案,并且对于简单更新可能会有太多的开销。
+
+- 绘制`requestAnimationFrame`并使用它来戳一个包含更新方法的 Web Worker,其中包含要计算的刻度数(如果有的话)。
+
+  - 这个睡眠直到`requestAnimationFrame`被调用并且不会污染主线程,加上你不依赖于老式的方法。再次,这比以前的两个选项更复杂一些,并且*开始*每个更新将被阻止,直到浏览器决定启动 rAF 回调。
+
+这些方法中的每一种都有类似的权衡:
+
+- 用户可以跳过渲染帧或根据其性能内插额外的帧。
+- 您可以指望所有用户以相同的恒定频率更改打嗝的更新非美容变量。
+- 程序比我们前面看到的基本循环要复杂得多。
+- 用户输入完全被忽略,直到下次更新(即使用户具有快速设备)。
+- 强制性内插具有性能损失。
+
+单独的更新和绘图方法可能如下面的示例。为了演示,该示例基于第三个项目符号,只是不使用 Web Workers 进行可读性(而且我们诚实地说可写性)。
+
+_注意:这个例子,具体来说,需要进行技术审查。_
+
+```js
+/*
 * 以分号开始,以上例子中的代码行都是这样的
 * 依靠自动分号插入 (ASI)。浏览器可能会意外
 * 认为这个整个例子从上一行继续。领先分号
@@ -263,11 +254,11 @@ main(); //开始循环
var nextTick = MyGame.lastTick + MyGame.tickLength; var numTicks = 0; - //如果 tFrame <nextTick,则需要更新 0 个 ticks(对于 numTicks,默认为 0)。 + //如果 tFrame nextTick){ var timeSinceTick = tFrame - MyGame.lastTick; numTicks = Math.floor(timeSinceTick / MyGame.tickLength); } @@ -278,7 +269,7 @@ main(); //开始循环 } function queueUpdates(numTicks){ - for(var i = 0; i <numTicks; i ++){ + for(var i = 0; i setInitialState(); main(performance.now()); //开始循环 -})(); +})(); +``` + +另一个选择是简单地做一些事情不那么频繁。如果您的更新循环的一部分难以计算但对时间不敏感,则可以考虑缩小其频率,理想情况下,在延长的时间段内将其扩展成块。这是一个隐含的例子,在火炮博物馆的炮兵游戏中,他们[调整垃圾发生率](http://blog.artillery.com/2012/10/browser-garbage-collection-and-framerate.html)来优化垃圾收集。显然,清理资源不是时间敏感的(特别是如果整理比垃圾本身更具破坏性)。 + +这也可能适用于您自己的一些任务。那些是当可用资源成为关注点时的好候选人。 + +## 概要 + +我知道上述的任何一种,或许没有适合你的游戏。正确的决定完全取决于你愿意(和不愿意)做出的权衡。主要关心的是切换到另一个选项。幸运的是,我没有任何经验,但我听说这是一个令人难以置信的游戏的 Whack-a-Mole。 -

另一个选择是简单地做一些事情不那么频繁。如果您的更新循环的一部分难以计算但对时间不敏感,则可以考虑缩小其频率,理想情况下,在延长的时间段内将其扩展成块。这是一个隐含的例子,在火炮博物馆的炮兵游戏中,他们调整垃圾发生率来优化垃圾收集。显然,清理资源不是时间敏感的(特别是如果整理比垃圾本身更具破坏性)。

+像 Web 这样的受管理平台,要记住的一件重要的事情是,您的循环可能会在相当长的一段时间内停止执行。当用户取消选择您的标签并且浏览器休眠(或减慢)其`requestAnimationFrame`回调间隔时,可能会发生这种情况。你有很多方法来处理这种情况,这可能取决于你的游戏是单人游戏还是多人游戏。一些选择是: -

这也可能适用于您自己的一些任务。那些是当可用资源成为关注点时的好候选人。

+- 考虑差距“暂停”并跳过时间。 -

概要

+ - 你可能会看到这对大多数多人游戏来说都是有问题的。 -

我知道上述的任何一种,或许没有适合你的游戏。正确的决定完全取决于你愿意(和不愿意)做出的权衡。主要关心的是切换到另一个选项。幸运的是,我没有任何经验,但我听说这是一个令人难以置信的游戏的 Whack-a-Mole。

+- 你可以模拟差距赶上。 -

像 Web 这样的受管理平台,要记住的一件重要的事情是,您的循环可能会在相当长的一段时间内停止执行。当用户取消选择您的标签并且浏览器休眠(或减慢)其requestAnimationFrame回调间隔时,可能会发生这种情况。你有很多方法来处理这种情况,这可能取决于你的游戏是单人游戏还是多人游戏。一些选择是:

+ - 这可能是长时间丢失和/或复杂更新的问题。 -
    -
  • 考虑差距“暂停”并跳过时间。 +- 您可以从联机设备或服务器恢复游戏状态。 -
      -
    • 你可能会看到这对大多数多人游戏来说都是有问题的。
    • -
    -
  • -
  • 你可以模拟差距赶上。 -
      -
    • 这可能是长时间丢失和/或复杂更新的问题。
    • -
    -
  • -
  • 您可以从联机设备或服务器恢复游戏状态。 -
      -
    • 除非联机设备/服务器的游戏状态已经过期,或者这是一个没有没服务器的纯单机游戏。
    • -
    -
  • -
+ - 除非联机设备/服务器的游戏状态已经过期,或者这是一个没有没服务器的纯单机游戏。 -

一旦你的主循环被开发出来,你已经决定了一套适合你的游戏的假设和权衡,现在只需要用你的决定来计算任何适用的物理,AI,声音,网络同步,以及你游戏可能需要。

+一旦你的主循环被开发出来,你已经决定了一套适合你的游戏的假设和权衡,现在只需要用你的决定来计算任何适用的物理,AI,声音,网络同步,以及你游戏可能需要。 diff --git a/files/zh-cn/games/examples/index.md b/files/zh-cn/games/examples/index.md index c12429037b2862..3d9c7d74841dac 100644 --- a/files/zh-cn/games/examples/index.md +++ b/files/zh-cn/games/examples/index.md @@ -5,113 +5,107 @@ tags: - 游戏 translation_of: Games/Examples --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

这个页面列出了许多令人印象深刻的 web 技术演示,你可以从中获得灵感和乐趣。这里证明了可以利用 JavaScript,WebGL 和相关的技术做些什么。前两个部分列出了可以玩的游戏,其中在第二个部分中列出的演示不一定是可交互的或是游戏。

+这个页面列出了许多令人印象深刻的 web 技术演示,你可以从中获得灵感和乐趣。这里证明了可以利用 JavaScript,WebGL 和相关的技术做些什么。前两个部分列出了可以玩的游戏,其中在第二个部分中列出的演示不一定是可交互的或是游戏。 -

免费/演示游戏

+## 免费/演示游戏 -
-
Beloola
-
一个连接充满激情的人们的网络虚拟现实(WebVR)平台。可以同时在 2D 屏幕和虚拟现实头盔显示器(设置/转为 VR 模式)上体验。
-
Tanx
-
一个多人坦克对战游戏,由PlayCanvas开发。
-
Hyper Vanguard Force
-
一个优雅的纵向卷轴太空射击游戏。
-
Swooop
-
一个飞行游戏:控制你的飞机并收集宝石。也是由PlayCanvas所开发。
-
Save the Day
-
在受灾区域驾驶你的救援直升机以拯救被困的受灾者(ga.me.)。
-
Polycraft
-
一个海难生存游戏。探索岛屿、打败怪物。
-
HexGL
-
一个快节奏、未来主义的赛车游戏。
-
Dead Trigger 2
-
经典的僵尸溅射游戏,使用Unity3D开发。
-
Angry Bots
-
一个未来风格的外星人式的第三人称射击游戏,使用Unity3D开发。
-
Nutmeg
-
可爱的复古卷轴平台动作游戏。
-
Back to Candyland
-
一个 match-3(Candy Crush)风格的游戏。
-
Biolab Disaster
-
横向卷轴平台射击游戏。
-
X-Type
-
纵向卷轴太空射击游戏演示。
-
Xibalba
-
复古(Doom 风格)的第一人称射击游戏。
-
Gorescript
-
另一个复古风格的第一人称射击游戏。
-
The Wizard
-
一个回合制的地下城解谜游戏。
-
Hextris
-
类似于俄罗斯方块的六边形解谜游戏。
-
2048
-
一个滑动数字方块的解谜游戏。
-
BananaBread
-
多玩家的 3D 第一人称射击游戏,使用 Emscripten,WebGL 和 WebRTC 开发。
-
Monster Madness
-
一个基于 WebGL 和 asm.js 的多人在线射击游戏,由 Nom Nom Games 和 Trendy entertainment 开发。
-
Auralux
-
基于 WebGL 和 asm.js 的策略游戏:捕获所有的太阳以获取胜利!
-
BrowserQuest
-
由 Little Workshop 和 Mozilla 开发的 MMORPG。
-
+- [Beloola](http://www.beloola.com) + - : 一个连接充满激情的人们的网络虚拟现实(WebVR)平台。可以同时在 2D 屏幕和虚拟现实头盔显示器(设置/转为 VR 模式)上体验。 +- [Tanx](http://playcanv.as/p/aP0oxhUr) + - : 一个多人坦克对战游戏,由[PlayCanvas](https://playcanvas.com/)开发。 +- [Hyper Vanguard Force](https://robertsspaceindustries.com/comm-link/transmission/14704-Hyper-Vanguard-Force) + - : 一个优雅的纵向卷轴太空射击游戏。 +- [Swooop](http://playcanv.as/p/JtL2iqIH) + - : 一个飞行游戏:控制你的飞机并收集宝石。也是由[PlayCanvas](https://playcanvas.com/)所开发。 +- [Save the Day](https://ga.me/games/save-the-day) + - : 在受灾区域驾驶你的救援直升机以拯救被困的受灾者(ga.me.)。 +- [Polycraft](https://ga.me/games/polycraft) + - : 一个海难生存游戏。探索岛屿、打败怪物。 +- [HexGL](http://hexgl.bkcore.com/) + - : 一个快节奏、未来主义的赛车游戏。 +- [Dead Trigger 2](http://beta.unity3d.com/jonas/DT2/) + - : 经典的僵尸溅射游戏,使用[Unity3D](http://unity3d.com/)开发。 +- [Angry Bots](http://beta.unity3d.com/jonas/AngryBots/) + - : 一个未来风格的外星人式的第三人称射击游戏,使用[Unity3D](http://unity3d.com/)开发。 +- [Nutmeg](http://sandbox.photonstorm.com/html5/nutmeg/) + - : 可爱的复古卷轴平台动作游戏。 +- [Back to Candyland](http://www.zibbo.com/game/match-3-games-top/back-to-candyland-episode-1) + - : 一个 match-3(Candy Crush)风格的游戏。 +- [Biolab Disaster](http://playbiolab.com/) + - : 横向卷轴平台射击游戏。 +- [X-Type](http://phoboslab.org/xtype/) + - : 纵向卷轴太空射击游戏演示。 +- [Xibalba](http://phoboslab.org/xibalba/) + - : 复古(Doom 风格)的第一人称射击游戏。 +- [Gorescript](https://timeinvariant.github.io/gorescript/play/) + - : 另一个复古风格的第一人称射击游戏。 +- [The Wizard](http://hypnoticowl.com/games/the-wizard/) + - : 一个回合制的地下城解谜游戏。 +- [Hextris](http://hextris.io/) + - : 类似于俄罗斯方块的六边形解谜游戏。 +- [2048](https://gabrielecirulli.github.io/2048/) + - : 一个滑动数字方块的解谜游戏。 +- [BananaBread](/en-US/demos/detail/bananabread) + - : 多玩家的 3D 第一人称射击游戏,使用 Emscripten,WebGL 和 WebRTC 开发。 +- [Monster Madness](https://hacks.mozilla.org/2013/12/monster-madness-creating-games-on-the-web-with-emscripten/) + - : 一个基于 WebGL 和 asm.js 的多人在线射击游戏,由 Nom Nom Games 和 Trendy entertainment 开发。 +- [Auralux](http://www.auraluxgame.com/game/) + - : 基于 WebGL 和 asm.js 的策略游戏:捕获所有的太阳以获取胜利! +- [BrowserQuest](http://browserquest.mozilla.org/) + - : 由 Little Workshop 和 Mozilla 开发的 MMORPG。 -

商业游戏

+## 商业游戏 -
-
Oort Online
-
一个大型多人网游:在游戏中探索、建造和战斗(目前仍在开发中)。
-
A Wizard's Lizard
-
自上而下的塞尔达式的探索/RPG游戏。
-
QbQbQb
-
一个科幻主题的解谜游戏。
-
Elliot Quest
-
复古的 8-bit 画面风格冒险游戏。
-
+- [Oort Online](http://oortonline.com/) + - : 一个大型多人网游:在游戏中探索、建造和战斗(目前仍在开发中)。 +- [A Wizard's Lizard](http://www.wizardslizard.com/) + - : 自上而下的塞尔达式的探索/RPG 游戏。 +- [QbQbQb](http://qbqbqb.rezoner.net/) + - : 一个科幻主题的解谜游戏。 +- [Elliot Quest](http://elliotquest.com/) + - : 复古的 8-bit 画面风格冒险游戏。 -

混合演示

+## 混合演示 -
-
WaveGL
-
音频资源的 WebGL 可视化展示。
-
Canvas Airport Simulation
-
可以显示飞机在机场起飞和降落的地图动画,也可以显示航线。
-
Animation Physics
-
地形和汽车的 3D 渲染,其中的物理计算使用了ammo.js
-
Volumetric Particle Flow
-
流体的物理模拟。
-
Explosion and chain reaction
-
会引发更多爆炸的爆炸粒子。
-
Canvas generated planet
-
一个具有小行星带的星球。
-
Digital Fireworks
-
在 canvas 上渲染出的焰火动画效果。
-
Autumn
-
秋叶飘落,光源在其后闪烁。使用Three.js开发。
-
Fire walk with me
-
翻腾的火云效果。
-
Rainbow Firestorm
-
下雨般的七彩粒子,在由圆组成的地形上跳跃。
-
Crowd Simulation
-
模拟想到达他们相反方向的拥挤人群。
-
SVG Masking Experiment
-
一台 X 光机,由 SVG 蒙版创建。
-
Realistic Water Simulation
-
如海浪的流水。
-
Dungeon demo
-
基于 Haxor 的地下城场景,拥有可行走的人物。
-
Massive Assault tech demo
-
渲染出的具有未来派的军用车辆的群岛。
-
Flight Stream
-
具有模拟航线的 3D 球体。
-
WebGL filters
-
用于向 HTML 元素添加效果的 WebGL 过滤器演示。
-
SVG isometic tiles
-
Generating isometric tiles with SVG matricies.
-
ThreeJS App Player
-
你可以在其中载入和运行 Three.js 的示例。
-
WebGL + Three.js Demo
-
警告:可能造成眩晕。
-
+- [WaveGL](http://greweb.me/wavegl/) + - : 音频资源的 WebGL 可视化展示。 +- [Canvas Airport Simulation](http://codepen.io/jackrugile/pen/CdKGx/) + - : 可以显示飞机在机场起飞和降落的地图动画,也可以显示航线。 +- [Animation Physics](http://alteredqualia.com/xg/examples/animation_physics_terrain.html) + - : 地形和汽车的 3D 渲染,其中的物理计算使用了[ammo.js](https://github.com/kripken/ammo.js) 。 +- [Volumetric Particle Flow](http://david.li/flow/) + - : 流体的物理模拟。 +- [Explosion and chain reaction](http://codepen.io/artzub/pen/gszpJ/) + - : 会引发更多爆炸的爆炸粒子。 +- [Canvas generated planet](http://codepen.io/AshKyd/pen/sylFw) + - : 一个具有小行星带的星球。 +- [Digital Fireworks](http://codepen.io/zadvorsky/pen/FAmuL) + - : 在 canvas 上渲染出的焰火动画效果。 +- [Autumn](http://oos.moxiecode.com/js_webgl/autumn/) + - : 秋叶飘落,光源在其后闪烁。使用[Three.js](https://github.com/mrdoob/three.js)开发。 +- [Fire walk with me](http://inear.se/fireshader/) + - : 翻腾的火云效果。 +- [Rainbow Firestorm](http://codepen.io/jackrugile/pen/AokpF) + - : 下雨般的七彩粒子,在由圆组成的地形上跳跃。 +- [Crowd Simulation](http://visualiser.fr/babylon/crowd/) + - : 模拟想到达他们相反方向的拥挤人群。 +- [SVG Masking Experiment](http://codepen.io/noeldelgado/pen/ByxQjL) + - : 一台 X 光机,由 SVG 蒙版创建。 +- [Realistic Water Simulation](https://www.shadertoy.com/view/Ms2SD1) + - : 如海浪的流水。 +- [Dungeon demo](http://www.haxor.xyz/demos/1.0/dungeon/) + - : 基于 Haxor 的地下城场景,拥有可行走的人物。 +- [Massive Assault tech demo](http://massiveassaultnetwork.com/html5/) + - : 渲染出的具有未来派的军用车辆的群岛。 +- [Flight Stream](https://callumprentice.github.io/apps/flight_stream/index.html) + - : 具有模拟航线的 3D 球体。 +- [WebGL filters](http://pixelscommander.com/polygon/htmlgl/demo/filters.html) + - : 用于向 HTML 元素添加效果的 WebGL 过滤器演示。 +- [SVG isometic tiles](http://codepen.io/AshKyd/pen/zxmgzV) + - : Generating isometric tiles with SVG matricies. +- [ThreeJS App Player](https://jsfiddle.net/jetienne/rkth90c9/) + - : 你可以在其中载入和运行 Three.js 的示例。 +- [WebGL + Three.js Demo](/en-US/demos/detail/escher-puzzle/launch) + - : 警告:可能造成眩晕。 diff --git a/files/zh-cn/games/index.md b/files/zh-cn/games/index.md index 8521cd5d06ebca..18637d4eafba41 100644 --- a/files/zh-cn/games/index.md +++ b/files/zh-cn/games/index.md @@ -12,72 +12,66 @@ tags: - Web translation_of: Games --- -
{{GamesSidebar}}
- -

游戏是在计算机上最风靡的活动之一。新技术不断发展已使开发出能在任何符合标准的浏览器上运行更好更炫的游戏成为可能。

- -
{{EmbedGHLiveSample("web-tech-games/index.html", '100%', 820)}}
- -

开发网页游戏

- -

欢迎来到 MDN 游戏开发中心!在网站的这个模块我们为想要开发游戏的 web 开发者提供了资源。你可以在主菜单的左边找到很多有用的教程和技术文档,放轻松去探索吧。

- -

我们同样包含了参考书库,因此你可以轻易的找到有关游戏开发所有常用的 API 以及有用的引擎和工具清单和游戏案例.

- -
-

备注: 在你开始尝试创建一个网页游戏之前你至少要掌握基础的核心 web 技术 —— 例如 HTML、CSS 和 Javascript。如果你是一个完全的初学者, 这里 将会是一个很好的学习领域。

-
- -

将本地游戏移植到 Web

- -

如果你是一个本地游戏开发者 (例如你用 C++开发游戏),并且你对如何将本地游戏移植到 Web 感兴趣,你应该更多的学习关于我们的Emscripten 工具—— 这是一个 LLVM JavaScript 编译器。它能获取 LLVM 字节码 (例如用 Clang 编译 C/C++或者其他语言生成的字节码)并且将它们编译成asm.js以在 Web 上运行。

- -

开始,查看以下:

- - - -

示例

- -

有关网页游戏示例的列表,请参阅我们的示例页。也可以查看 openwebgames.com 以获得更多有用的资源和示例!

- -

参见

- -
-
Build New Games
-
这是一个以大量开放式网页游戏开发教程为特色的协作网站。最近还不是很活跃,但还是拥有一些不错的资源。
-
Creative JS
-
一个令人印象深刻的 JavaScript 技术和实验的集合,并不全是游戏技术,但还是对开发有帮助。最近并不非常活跃,但仍然拥有一些不错的资源。
-
Game programming patterns
-
在线书籍,作者 Bob Nystrom,其中讨论了游戏开发环境中的编程模式,旨在帮助游戏开发人员生成更有效,更高效的代码。
-
Artillery blog
-
HTML5 游戏公司 Artillery 在他们的博客上发表的一些有用的文章。
-
Building games for Firefox OS
-
使用 HTML5 创建 2D 游戏的快速指南,针对在 Firefox OS 和其他移动平台上分发。
-
Gamedev.js Weekly
-
关于 HTML5 游戏开发的每周新闻,每星期五发送。包含最新的文章,教程,工具和资源。
-
HTML5 Game Devs Forum
-
开发者,架构师,发布者的论坛。提出问题,获得帮助,帮助他人。
-
- -
-
HTML5 游戏引擎
-
眼下最流行的 HTML5 游戏框架列表,包含评分,特色和案例。
-
JSBreakouts
-
比较在不同的框架中的 JavaScript Breakout clones,以帮助您作出正确的选择。
-
Tuts 与游戏开发
-
关于游戏开发的教程和案例。
-
#BBG IRC chat
-
实时在线与开发者直接对话。
-
HTML5 Gamedev Starter
-
Starter 针对游戏开发新手,在网络上提供一个策划列表链接到各种,有用的资源。
-
js13kGames
-
针对 HTML5 游戏开发人员的 JavaScript 编码竞赛,文件大小限制设置为 13 千字节。所有提交的游戏都以可读的形式在 GitHub 上提供。
-
Mozilla Hacks blog
-
在 Mozilla Hacks 博客包含关于游戏类别的有趣的游戏开发的相关文章。
-
Visual-js game engine
-
2d / 3d / webSocket 定向游戏引擎。只有 window 下的工具。托管在 bitbucket 项目网站。
-
+{{GamesSidebar}} + +游戏是在计算机上最风靡的活动之一。新技术不断发展已使开发出能在任何符合标准的浏览器上运行更好更炫的游戏成为可能。 + +{{EmbedGHLiveSample("web-tech-games/index.html", '100%', 820)}} + +## 开发网页游戏 + +欢迎来到 MDN 游戏开发中心!在网站的这个模块我们为想要开发游戏的 web 开发者提供了资源。你可以在主菜单的左边找到很多有用的教程和技术文档,放轻松去探索吧。 + +我们同样包含了参考书库,因此你可以轻易的找到有关游戏开发所有常用的 API 以及有用的[引擎和工具](/zh-CN/docs/Games/Tools/Engines_and_tools)清单和[游戏案例](/zh-CN/docs/Games/Examples). + +> **备注:** 在你开始尝试创建一个网页游戏之前你至少要掌握基础的核心 web 技术 —— 例如 HTML、CSS 和 Javascript。如果你是一个完全的初学者, [这里](/zh-CN/docs/Learn) 将会是一个很好的学习领域。 + +## 将本地游戏移植到 Web + +如果你是一个本地游戏开发者 (例如你用 C++开发游戏),并且你对如何将本地游戏移植到 Web 感兴趣,你应该更多的学习关于我们的[Emscripten](http://kripken.github.io/emscripten-site/index.html) 工具—— 这是一个 LLVM JavaScript 编译器。它能获取 LLVM 字节码 (例如用 Clang 编译 C/C++或者其他语言生成的字节码)并且将它们编译成[asm.js](/en-US/docs/Games/Tools/asm.js)以在 Web 上运行。 + +开始,查看以下: + +- [关于 Emscripten](https://kripken.github.io/emscripten-site/docs/introducing_emscripten/about_emscripten.html)——简介和高级特性。 +- [下载和安装](https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html)——安装工具链。 +- [Emscripten 教程](https://kripken.github.io/emscripten-site/docs/getting_started/Tutorial.html)——指导你如何开始。 + +## 示例 + +有关网页游戏示例的列表,请参阅我们的[示例页](/zh-CN/docs/Games/Examples)。也可以查看 [openwebgames.com](http://www.openwebgames.com/) 以获得更多有用的资源和示例! + +## 参见 + +- [Build New Games](http://buildnewgames.com/) + - : 这是一个以大量开放式网页游戏开发教程为特色的协作网站。最近还不是很活跃,但还是拥有一些不错的资源。 +- [Creative JS](http://creativejs.com/) + - : 一个令人印象深刻的 JavaScript 技术和实验的集合,并不全是游戏技术,但还是对开发有帮助。最近并不非常活跃,但仍然拥有一些不错的资源。 +- [Game programming patterns](http://gameprogrammingpatterns.com/) + - : 在线书籍,作者 Bob Nystrom,其中讨论了游戏开发环境中的编程模式,旨在帮助游戏开发人员生成更有效,更高效的代码。 +- [Artillery blog](http://blog.artillery.com/) + - : HTML5 游戏公司 Artillery 在他们的博客上发表的一些有用的文章。 +- [Building games for Firefox OS](https://leanpub.com/buildinggamesforfirefoxos/) + - : 使用 HTML5 创建 2D 游戏的快速指南,针对在 Firefox OS 和其他移动平台上分发。 +- [Gamedev.js Weekly](http://gamedevjsweekly.com/) + - : 关于 HTML5 游戏开发的每周新闻,每星期五发送。包含最新的文章,教程,工具和资源。 +- [HTML5 Game Devs Forum](http://www.html5gamedevs.com/) + - : 开发者,架构师,发布者的论坛。提出问题,获得帮助,帮助他人。 + + + +- [HTML5 游戏引擎](http://html5gameengine.com/) + - : 眼下最流行的 HTML5 游戏框架列表,包含评分,特色和案例。 +- [JSBreakouts](http://www.jsbreakouts.org/) + - : 比较在不同的框架中的 JavaScript Breakout clones,以帮助您作出正确的选择。 +- [Tuts 与游戏开发](http://gamedevelopment.tutsplus.com/) + - : 关于游戏开发的教程和案例。 +- [#BBG IRC chat](http://webchat.freenode.net/?channels=bbg) + - : 实时在线与开发者直接对话。 +- [HTML5 Gamedev Starter](http://html5devstarter.enclavegames.com/) + - : Starter 针对游戏开发新手,在网络上提供一个策划列表链接到各种,有用的资源。 +- [js13kGames](http://js13kgames.com/) + - : 针对 HTML5 游戏开发人员的 JavaScript 编码竞赛,文件大小限制设置为 13 千字节。所有提交的游戏都以可读的形式在 GitHub 上提供。 +- [Mozilla Hacks blog](https://hacks.mozilla.org/category/games/) + - : 在 Mozilla Hacks 博客包含关于游戏类别的有趣的游戏开发的相关文章。 +- [Visual-js game engine](Games/Visual-js_game_engine) + - : 2d / 3d / webSocket 定向游戏引擎。只有 window 下的工具。托管在 bitbucket 项目网站。 diff --git a/files/zh-cn/games/introduction/index.md b/files/zh-cn/games/introduction/index.md index b51cb0cebe8ff6..9d88f9e2aae325 100644 --- a/files/zh-cn/games/introduction/index.md +++ b/files/zh-cn/games/introduction/index.md @@ -8,108 +8,69 @@ tags: translation_of: Games/Introduction original_slug: Games/简介 --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

现代的 web 已经高速发展成为一个可行可靠的平台,它不仅能够用来创建高质量的酷炫游戏,同时也能够用来发布和传播这些游戏。

+现代的 web 已经高速发展成为一个可行可靠的平台,它不仅能够用来创建高质量的酷炫游戏,同时也能够用来发布和传播这些游戏。 -

采用现代网页技术和较新的浏览器,完全有可能做出令人印象深刻的顶级页面游戏。它能够制作的游戏种类可以和桌面端以及原生系统相当。我们这里所说的,并不是很久之前就采用 Flash®制作出的简单卡牌游戏或者多人社交游戏。而是牛逼的 3D 动作射击游戏,RPG 游戏等等。得益于 JavaScript 实时编译技术性能的大幅提升,以及新开放的 API。在制作运行在浏览器(或者是基于类似 Firefox OSHTML5技术支持的设备)上的游戏时,我们不用妥协。

+采用现代网页技术和较新的浏览器,完全有可能做出令人印象深刻的顶级页面游戏。它能够制作的游戏种类可以和桌面端以及原生系统相当。我们这里所说的,并不是很久之前就采用 Flash® 制作出的简单卡牌游戏或者多人社交游戏。而是牛逼的 3D 动作射击游戏,RPG 游戏等等。得益于 [JavaScript](/zh-CN/docs/JavaScript) 实时编译技术性能的大幅提升,以及新开放的 API。在制作运行在浏览器(或者是基于类似 [Firefox OS](/zh-CN/docs/Mozilla/Firefox_OS) 的 [HTML5](/zh-CN/docs/HTML/HTML5)技术支持的设备)上的游戏时,我们不用妥协。 +## HTML5 游戏平台 +你可以真正地为你的游戏考虑下 Web 来作为更好的目标平台。我们总是喜欢说,"the Web is the platform." 让我们浏览下 Web 平台的核心部分: -

HTML5 游戏平台

+| 功能 | 技术 | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **音频** | [Web Audio API](/zh-CN/docs/Web/API/Web_Audio_API) | +| **图形** | [WebGL](/zh-CN/docs/WebGL) ([OpenGL ES](http://www.khronos.org/opengles/) 2.0) | +| **输入** | [Touch events](/zh-CN/docs/DOM/Touch_events), [Gamepad API](/zh-CN/docs/Web/API/Gamepad_API/Using_the_Gamepad_API), 设备传感器,[WebRTC](/zh-CN/docs/WebRTC), [Full Screen API](/zh-CN/docs/Web/API/Fullscreen_API), [Pointer Lock API](/zh-CN/docs/API/Pointer_Lock_API) | +| **语言** | [JavaScript](/zh-CN/docs/JavaScript) (或是 C/C++ 使用 [Emscripten](https://github.com/kripken/emscripten/wiki) 来编译成 JavaScript) | +| **网络** | [WebRTC](/zh-CN/docs/WebRTC) 和/或 [WebSockets](/zh-CN/docs/Web/API/WebSockets_API) | +| **存储** | [IndexedDB](/zh-CN/docs/IndexedDB) 或是 "云 (存储)" | +| **Web** | [HTML](/zh-CN/docs/HTML), [CSS](/zh-CN/docs/CSS), [SVG](/zh-CN/docs/SVG), [Social API](/zh-CN/docs/Mozilla/Projects/Social_API) (还有其他很多很多东西!) | -

你可以真正地为你的游戏考虑下 Web 来作为更好的目标平台。我们总是喜欢说,"the Web is the platform." 让我们浏览下 Web 平台的核心部分:

+## 商业案例 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
功能技术
音频Web Audio API
图形WebGL (OpenGL ES 2.0)
输入Touch events, Gamepad API, 设备传感器,WebRTC, Full Screen API, Pointer Lock API
语言JavaScript (或是 C/C++ 使用 Emscripten 来编译成 JavaScript)
网络WebRTC 和/或 WebSockets
存储IndexedDB 或是 "云 (存储)"
WebHTML, CSS, SVG, Social API (还有其他很多很多东西!)
+作为一名游戏开发者,无论你是独立的个人还是大型游戏工作室,你想知道你的下一个游戏项目瞄准 Web 是有意义的 。让我们看看 Web 是如何帮到你的。 -

商业案例

+1. Web 触手可及;它无处不在。如今可以看到,用 HTML5 构建的游戏运行在智能手机,平板,个人电脑和智能电视。 +2. 提高营销和曝光度。你不限于在某商店推广你的游戏。相反,你可以像其他媒体一样在 Web 宣传和推广你的游戏,利用网络的固有性和共享性接触新客户。 +3. 你可以掌握最重要的事项:支付。你不必交付超过收入的 30% 给他人,仅仅就因为你的游戏在他们的生态系统。相反,你可以管理任何你想要的和使用任何你喜欢的付款处理服务。 +4. 拥有更多控制权的是,只要你愿意,你可以随时更新游戏。 不必着急等待审核通过,仅当其他公司的某某人决定你的关键 bug 修复是否会在今天或明天交付。 +5. 掌握你的数据分析!不必依靠别人作出所有决定,你需要什么分析,你可以收集自己的 -- 或选择你最喜欢的第三方平台,来收集有关你的销售和游戏产生的信息。 +6. 你可以用你的方式更密切地管理你的客户关系。 再也不用苦苦等待只能通过应用商店有限的机制来过滤客户的反馈。用你想要的方式与客户交流, 没有中间人。 +7. 你的玩家可以随时随地玩你的游戏。因为 Web 是无处不在的,你的顾客可以在手机,平板,家庭手提,个人电脑或其他设备上关注游戏动态。 -

作为一名游戏开发者,无论你是独立的个人还是大型游戏工作室,你想知道你的下一个游戏项目瞄准 Web 是有意义的 。让我们看看 Web 是如何帮到你的。

+## 针对游戏开发者的 Web 技术 -
    -
  1. -
    Web 触手可及;它无处不在。如今可以看到,用 HTML5 构建的游戏运行在智能手机,平板,个人电脑和智能电视。
    -
  2. -
  3. 提高营销和曝光度。你不限于在某商店推广你的游戏。相反,你可以像其他媒体一样在 Web 宣传和推广你的游戏,利用网络的固有性和共享性接触新客户。
  4. -
  5. 你可以掌握最重要的事项:支付。你不必交付超过收入的 30% 给他人,仅仅就因为你的游戏在他们的生态系统。相反,你可以管理任何你想要的和使用任何你喜欢的付款处理服务。
  6. -
  7. 拥有更多控制权的是,只要你愿意,你可以随时更新游戏。 不必着急等待审核通过,仅当其他公司的某某人决定你的关键 bug 修复是否会在今天或明天交付。
  8. -
  9. 掌握你的数据分析!不必依靠别人作出所有决定,你需要什么分析,你可以收集自己的 -- 或选择你最喜欢的第三方平台,来收集有关你的销售和游戏产生的信息。
  10. -
  11. 你可以用你的方式更密切地管理你的客户关系。 再也不用苦苦等待只能通过应用商店有限的机制来过滤客户的反馈。用你想要的方式与客户交流, 没有中间人。
  12. -
  13. 你的玩家可以随时随地玩你的游戏。因为 Web 是无处不在的,你的顾客可以在手机,平板,家庭手提,个人电脑或其他设备上关注游戏动态。
  14. -
+技术同行们,让我们发掘出所有关于 Web 的 APIs,将它们呈现给所有的游戏开发者们。下面是一个比较完整的列表,可以一窥 Web 究竟能够做些什么: -

针对游戏开发者的 Web 技术

- -

技术同行们,让我们发掘出所有关于 Web 的 APIs,将它们呈现给所有的游戏开发者们。下面是一个比较完整的列表,可以一窥 Web 究竟能够做些什么:

- -
-
-
Full Screen API
-
这个简单的 API 能够让你的游戏占据整个屏幕,从而使玩家沉浸在动作中
-
Gamepad API
-
如果你想你的用户能够使用游戏手柄或其他游戏控制器来控制游戏,你需要这个 API
-
HTML and CSS
-
二者合璧,可以构建,设计并对你的游戏界面布局,HTML 有一个提供 2D 图形的元素,即{{HTMLElement("canvas")}}
-
HTML audio
-
{{HTMLElement("audio")}} 元素可以用来播放一些简单的音效和音乐。如果你想要更多的参与,可以学习Web Audio API 来深入了解音频处理的力量!
-
IndexedDB
-
一个强大的数据存储 API,用来在电脑或者设备上保存用户自己的数据。一个很好的方法用来保存游戏的状态和其它最近的信息,这样在需要的时候不用每次重新下载。也可以用来让你的游戏即使用户没有链接到网络也能继续玩 (例如在飞机上的数小时)。
-
JavaScript
-
JavaScript 是网络上使用的编程语言,在现代浏览器中正在快速发展,而且一直在快速发展。使用它的力量为您的游戏编写代码,或者使用EmscriptenAsm.js等技术轻松移植您现有的游戏。
-
Pointer Lock API
-
指针锁定 API 允许您在游戏界面中锁定鼠标或其他指针设备,以便您不用绝对定位光标就可以获得坐标变化值,从而准确地判断用户正在做什么,并且还可以防止用户意外地进入另一块屏幕或别的什么地方,从而导致误操作。
-
SVG (可缩放矢量图形)
-
无论用户显示器的大小或分辨率如何,都可以构建平滑缩放的矢量图形。
-
Typed Arrays
-
JavaScript 中的类型数组可以让您访问原始二进制数据;这使您可以操纵 GL 纹理,游戏数据或其他任何东西,即使它不是原生 JavaScript 数据格式。
-
Web Audio API
-
这个 API 用于控制 JavaScript 代码中的音频的回放,合成和处理,使您可以创建出色的音效,以及实时播放和操作音乐。
-
WebGL
-
允许您从 Web 内容创建高性能,硬件加速的 3D(和 2D)图形。这是一个 Web 支持的OpenGL ES 2.0 实现。
-
WebRTC
-
WebRTC(实时通信)API 使您能够控制音频和视频数据,包括远程会议以及两个用户之间来回传输其他应用程序数据。希望你的玩家能够在殴打怪物的同时互相交流?这是你的 API,快使用它吧。
-
WebSockets
-
WebSocket API 使您可以将您的应用程序或站点连接到服务器,实时传输数据。构建完美的多人游戏动作,聊天服务等必备。
-
Web Workers
-
Workers API 能够让您生成运行 JavaScript 代码的后台线程,以充分利用现代的多核 CPU。
-
XMLHttpRequestFile API
-
XMLHttpRequest 和 File API 的组合使您可以从 Web 服务器发送和接收任何类型的数据。比如下载新的游戏关卡,文件,以及传递非实时游戏状态信息等。
-
-
+- [Full Screen API](/zh-CN/docs/Web/API/Fullscreen_API) + - : 这个简单的 API 能够让你的游戏占据整个屏幕,从而使玩家沉浸在动作中 +- [Gamepad API](/zh-CN/docs/Web/API/Gamepad_API/Using_the_Gamepad_API) + - : 如果你想你的用户能够使用游戏手柄或其他游戏控制器来控制游戏,你需要这个 API +- [HTML](/zh-CN/docs/HTML) and [CSS](/zh-CN/docs/CSS) + - : 二者合璧,可以构建,设计并对你的游戏界面布局,HTML 有一个提供 2D 图形的元素,即{{HTMLElement("canvas")}} +- [HTML audio](/zh-CN/docs/HTML/Element/audio) + - : {{HTMLElement("audio")}} 元素可以用来播放一些简单的音效和音乐。如果你想要更多的参与,可以学习[Web Audio API](/zh-CN/docs/Web/API/Web_Audio_API) 来深入了解音频处理的力量! +- [IndexedDB](/zh-CN/docs/IndexedDB) + - : 一个强大的数据存储 API,用来在电脑或者设备上保存用户自己的数据。一个很好的方法用来保存游戏的状态和其它最近的信息,这样在需要的时候不用每次重新下载。也可以用来让你的游戏即使用户没有链接到网络也能继续玩 (例如在飞机上的数小时)。 +- [JavaScript](/zh-CN/docs/JavaScript) + - : JavaScript 是网络上使用的编程语言,在现代浏览器中正在快速发展,而且一直在快速发展。使用它的力量为您的游戏编写代码,或者使用[Emscripten](https://github.com/kripken/emscripten/wiki)或[Asm.js](http://asmjs.org/spec/latest/)等技术轻松移植您现有的游戏。 +- [Pointer Lock API](/zh-CN/docs/API/Pointer_Lock_API) + - : 指针锁定 API 允许您在游戏界面中锁定鼠标或其他指针设备,以便您不用绝对定位光标就可以获得坐标变化值,从而准确地判断用户正在做什么,并且还可以防止用户意外地进入另一块屏幕或别的什么地方,从而导致误操作。 +- [SVG](/zh-CN/docs/SVG) (可缩放矢量图形) + - : 无论用户显示器的大小或分辨率如何,都可以构建平滑缩放的矢量图形。 +- [Typed Arrays](/zh-CN/docs/JavaScript/Typed_arrays) + - : JavaScript 中的类型数组可以让您访问原始二进制数据;这使您可以操纵 GL 纹理,游戏数据或其他任何东西,即使它不是原生 JavaScript 数据格式。 +- [Web Audio API](/zh-CN/docs/Web/API/Web_Audio_API) + - : 这个 API 用于控制 JavaScript 代码中的音频的回放,合成和处理,使您可以创建出色的音效,以及实时播放和操作音乐。 +- [WebGL](/zh-CN/docs/WebGL) + - : 允许您从 Web 内容创建高性能,硬件加速的 3D(和 2D)图形。这是一个 Web 支持的[OpenGL ES](https://www.khronos.org/opengles/) 2.0 实现。 +- [WebRTC](/zh-CN/docs/WebRTC) + - : WebRTC(实时通信)API 使您能够控制音频和视频数据,包括远程会议以及两个用户之间来回传输其他应用程序数据。希望你的玩家能够在殴打怪物的同时互相交流?这是你的 API,快使用它吧。 +- [WebSockets](/zh-CN/docs/Web/API/WebSockets_API) + - : WebSocket API 使您可以将您的应用程序或站点连接到服务器,实时传输数据。构建完美的多人游戏动作,聊天服务等必备。 +- [Web Workers](/zh-CN/docs/DOM/Using_web_workers) + - : Workers API 能够让您生成运行 JavaScript 代码的后台线程,以充分利用现代的多核 CPU。 +- [XMLHttpRequest](/zh-CN/docs/DOM/XMLHttpRequest) 和 [File API](/zh-CN/docs/Web/API/File_and_Directory_Entries_API) + - : XMLHttpRequest 和 File API 的组合使您可以从 Web 服务器发送和接收任何类型的数据。比如下载新的游戏关卡,文件,以及传递非实时游戏状态信息等。 diff --git a/files/zh-cn/games/introduction_to_html5_game_development/index.md b/files/zh-cn/games/introduction_to_html5_game_development/index.md index 37fb345dc179c9..660449b9067025 100644 --- a/files/zh-cn/games/introduction_to_html5_game_development/index.md +++ b/files/zh-cn/games/introduction_to_html5_game_development/index.md @@ -7,93 +7,60 @@ tags: translation_of: Games/Introduction_to_HTML5_Game_Development_(summary) original_slug: Games/Introduction_to_HTML5_Game_Gevelopment_(summary) --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

优点

+## 优点 -
    -
  1. 使用 HTML5 构建的游戏可以在智能手机,平板电脑,个人电脑和智能电视上工作。
  2. -
  3. 通过网络以及其他媒体广告宣传您的游戏。
  4. -
  5. 付款。收取你想要的,并使用任何你喜欢的付款处理服务。
  6. -
  7. 随时更新游戏。
  8. -
  9. 收集您自己的分析!
  10. -
  11. 更密切地与客户联系。
  12. -
  13. 玩家可随时随地玩游戏。
  14. -
+1. 使用 HTML5 构建的游戏可以在智能手机,平板电脑,个人电脑和智能电视上工作。 +2. 通过网络以及其他媒体广告宣传您的游戏。 +3. 付款。收取你想要的,并使用任何你喜欢的付款处理服务。 +4. 随时更新游戏。 +5. 收集您自己的分析! +6. 更密切地与客户联系。 +7. 玩家可随时随地玩游戏。 -

网络技术

+## 网络技术 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FunctionTechnology
AudioWeb Audio API
GraphicsWebGL (OpenGL ES 2.0)
InputTouch events, Gamepad API, device sensors, WebRTC, Full Screen API, Pointer Lock API
LanguageJavaScript (or C/C++ using Emscripten to compile to JavaScript)
NetworkingWebRTC and/or WebSockets
StorageIndexedDB or the "cloud"
WebHTML, CSS, SVG, Social API (and much more!)
+| **Function** | **Technology** | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Audio** | [Web Audio API](/en-US/docs/Web_Audio_API) | +| **Graphics** | [WebGL](/en-US/docs/WebGL) ([OpenGL ES](http://www.khronos.org/opengles/) 2.0) | +| **Input** | [Touch events](/en-US/docs/DOM/Touch_events), [Gamepad API](/en-US/docs/API/Gamepad/Using_Gamepad_API), device sensors, [WebRTC](/en-US/docs/WebRTC), [Full Screen API](/en-US/docs/DOM/Using_fullscreen_mode), [Pointer Lock API](/en-US/docs/WebAPI/Pointer_Lock) | +| **Language** | [JavaScript](/en-US/docs/JavaScript) (or C/C++ using [Emscripten](https://github.com/kripken/emscripten/wiki) to compile to JavaScript) | +| **Networking** | [WebRTC](/en-US/docs/WebRTC) and/or [WebSockets](/en-US/docs/WebSockets) | +| **Storage** | [IndexedDB](/en-US/docs/IndexedDB) or the "cloud" | +| **Web** | [HTML](/en-US/docs/HTML), [CSS](/en-US/docs/CSS), [SVG](/en-US/docs/SVG), [Social API](/en-US/docs/Social_API) (and much more!) | -
-
Full Screen API
-
全屏游戏。
-
Gamepad API
-
使用游戏手柄或其他游戏控制器。
-
HTML and CSS
-
构建,样式和布局游戏的用户界面。
-
HTML audio
-
轻松播放简单的音效和音乐。
-
IndexedDB
-
将用户数据存储在他们自己的计算机或设备上。
-
JavaScript
-
快速的网页编程语言为您的游戏编写代码。轻松移植您现有的游戏 EmscriptenAsm.js
-
Pointer Lock API
-
在游戏界面中锁定鼠标或其他指针设备。
-
SVG (Scalable Vector Graphics)
-
构建能够顺利扩展的矢量图形,无论用户显示器的大小或分辨率如何。
-
Typed Arrays
-
从 JavaScript 中访问原始二进制数据; 操纵 GL 纹理,游戏数据或其他任何东西。
-
+- [Full Screen API](/en-US/docs/DOM/Using_fullscreen_mode) + - : 全屏游戏。 +- [Gamepad API](/en-US/docs/API/Gamepad/Using_Gamepad_API) + - : 使用游戏手柄或其他游戏控制器。 +- [HTML](/en-US/docs/HTML) and [CSS](/en-US/docs/CSS) + - : 构建,样式和布局游戏的用户界面。 +- [HTML audio](/en-US/docs/HTML/Element/audio) + - : 轻松播放简单的音效和音乐。 +- [IndexedDB](/en-US/docs/IndexedDB) + - : 将用户数据存储在他们自己的计算机或设备上。 +- [JavaScript](/en-US/docs/JavaScript) + - : 快速的网页编程语言为您的游戏编写代码。轻松移植您现有的游戏 [Emscripten](https://github.com/kripken/emscripten/wiki) 或 [Asm.js](http://asmjs.org/spec/latest/) +- [Pointer Lock API](/en-US/docs/WebAPI/Pointer_Lock) + - : 在游戏界面中锁定鼠标或其他指针设备。 +- [SVG](/en-US/docs/SVG) (Scalable Vector Graphics) + - : 构建能够顺利扩展的矢量图形,无论用户显示器的大小或分辨率如何。 +- [Typed Arrays](/en-US/docs/JavaScript/Typed_arrays) + - : 从 JavaScript 中访问原始二进制数据; 操纵 GL 纹理,游戏数据或其他任何东西。 -
-
Web Audio API
-
实时控制音频的播放,合成和操纵。
-
WebGL
-
创建高性能,硬件加速的 3D(和 2D)图形。OpenGL ES 2.0.
-
WebRTC
-
实时通讯控制音频和视频数据,包括电话会议,并在两个用户之间来回传送其他应用数据,如聊天。
-
WebSockets
-
将您的应用程序或站点连接到一个服务器以实时传输数据。适合多人游戏动作,聊天服务等。
-
Web Workers
-
生成后台线程为多核处理器运行自己的 JavaScript 代码。
-
XMLHttpRequest and File API
-
从一个 Web 服务器发送和接收任何您想要的数据,如下载新的游戏级别和艺术品,以便来回传送非实时游戏状态信息。
-
+ + +- [Web Audio API](/en-US/docs/Web_Audio_API) + - : 实时控制音频的播放,合成和操纵。 +- [WebGL](/en-US/docs/WebGL) + - : 创建高性能,硬件加速的 3D(和 2D)图形。[OpenGL ES](http://www.khronos.org/opengles/) 2.0. +- [WebRTC](/en-US/docs/WebRTC) + - : 实时通讯控制音频和视频数据,包括电话会议,并在两个用户之间来回传送其他应用数据,如聊天。 +- [WebSockets](/en-US/docs/WebSockets) + - : 将您的应用程序或站点连接到一个服务器以实时传输数据。适合多人游戏动作,聊天服务等。 +- [Web Workers](/en-US/docs/DOM/Using_web_workers) + - : 生成后台线程为多核处理器运行自己的 JavaScript 代码。 +- [XMLHttpRequest](/en-US/docs/DOM/XMLHttpRequest) and [File API](/en-US/docs/DOM/File_API) + - : 从一个 Web 服务器发送和接收任何您想要的数据,如下载新的游戏级别和艺术品,以便来回传送非实时游戏状态信息。 diff --git a/files/zh-cn/games/publishing_games/game_distribution/index.md b/files/zh-cn/games/publishing_games/game_distribution/index.md index 9319cc665d9fe2..9cdd2e0446ed8e 100644 --- a/files/zh-cn/games/publishing_games/game_distribution/index.md +++ b/files/zh-cn/games/publishing_games/game_distribution/index.md @@ -3,125 +3,113 @@ title: Game distribution slug: Games/Publishing_games/Game_distribution translation_of: Games/Publishing_games/Game_distribution --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

你已经跟着一两个教程做了一个 HTML5 游戏了——真棒 ! 这篇文章介绍了一些可以让你投放你的游戏的方式。 包括自己建立网站,在公开的应用市场上线,或是发布到 Google Play 或 IOS 的 App Store。

+你已经跟着一两个[教程](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript)做了一个 HTML5 游戏了——真棒 ! 这篇文章介绍了一些可以让你投放你的游戏的方式。 包括自己建立网站,在公开的应用市场上线,或是发布到 Google Play 或 IOS 的 App Store。 -

HTML5 相较于传统的好处

+## HTML5 相较于传统的好处 -

用 HTML5 构筑游戏有许多好处,例如

+用 HTML5 构筑游戏有许多好处,例如 -

多平台兼容

+### 多平台兼容 -

HTML5 本身是多平台的,所以你只需要写一种代码就可以适配不同的平台。 从小型的智能手机和平板电脑,到笔记本电脑和台式电脑,再到智能电视,智能手表甚至是智能冰箱(如果它内置现代化浏览器的话)。

+HTML5 本身是多平台的,所以你只需要写一种代码就可以适配不同的平台。 从小型的智能手机和平板电脑,到笔记本电脑和台式电脑,再到智能电视,智能手表甚至是智能冰箱(如果它内置现代化浏览器的话)。 -

你并不需要数个开发小组去编写不同平台的代码,你们只需要维护这一种基础代码。 你可以花更多时间去推广游戏和促进游戏收益化

+你并不需要数个开发小组去编写不同平台的代码,你们只需要维护这一种基础代码。 你可以花更多时间去[推广游戏](/en-US/docs/Games/Techniques/Publishing_games/Game_promotion)和促进[游戏收益化](/en-US/docs/Games/Techniques/Publishing_games/Game_monetization)。 -

即时更新

+### 即时更新 -

你不需要花数日去上传你的游戏代码.。如果你发现了漏洞,你可以立即修复它,升级系统和在服务端上传代码以为你的用户更新游戏几乎都是即时的

+你不需要花数日去上传你的游戏代码.。如果你发现了漏洞,你可以立即修复它,升级系统和在服务端上传代码以为你的用户更新游戏几乎都是即时的 -

直连,直玩

+### 直连,直玩 -

若是 HTML5 游戏,你无需让大家去应用商店搜索,只需要给他们 URL 链接即可,他们点击链接就可以直接玩游戏,而不需要使用第三方平台或是下载一个很大的安装包来安装游戏。不过你仍需考虑你的游戏的大小是否可能会让用户花一点时间来加载资源,以及你的游戏对网速的需求。总之,如果你把你的游戏按照你的设想构建,并且在开玩之前没有那么多弯弯绕绕,推广它还是很容易的

+若是 HTML5 游戏,你无需让大家去应用商店搜索,只需要给他们 URL 链接即可,他们点击链接就可以直接玩游戏,而不需要使用第三方平台或是下载一个很大的安装包来安装游戏。不过你仍需考虑你的游戏的大小是否可能会让用户花一点时间来加载资源,以及你的游戏对网速的需求。总之,如果你把你的游戏按照你的设想构建,并且在开玩之前没有那么多弯弯绕绕,推广它还是很容易的 -

电脑还是手机?

+## 电脑还是手机? -

我们感兴趣的绝大部分流量——HTML5 游戏玩家——都来自移动设备,所以如果你真的想要成功,你就必须专注于这一点。手机端是 HTML5 真正发光发热的地方,那里没有 Flash,HTML5 便是全部。

+我们感兴趣的绝大部分流量——HTML5 游戏玩家——都来自移动设备,所以如果你真的想要成功,你就必须专注于这一点。手机端是 HTML5 真正发光发热的地方,那里没有 Flash,HTML5 便是全部。 -

要与 PC 端游直接竞争是很困难的,当然你也可以在 PC 端发布你的游戏(见下文的电脑平台)你也应该这么做,因为这可以让你的游戏支持的平台变得多样化,但谨记,电脑游戏的开发者拥有多年的经验,优秀的工具和稳定的发行渠道。许多 HTML5 游戏会与传统电脑游戏面向不同的受众市场。例如,简单的的小游戏比大型的沉浸式游戏更有人气,这类游戏通常设计成用两根手指,甚至一根手指玩,所以你可以拿着设备玩游戏,还可以用第二只手做你目前需要的任何事情。

+要与 PC 端游直接竞争是很困难的,当然你也可以在 PC 端发布你的游戏(见下文的[电脑平台](#电脑平台))你也应该这么做,因为这可以让你的游戏支持的平台变得多样化,但谨记,电脑游戏的开发者拥有多年的经验,优秀的工具和稳定的发行渠道。许多 HTML5 游戏会与传统电脑游戏面向不同的受众市场。例如,简单的的小游戏比大型的沉浸式游戏更有人气,这类游戏通常设计成用两根手指,甚至一根手指玩,所以你可以拿着设备玩游戏,还可以用第二只手做你目前需要的任何事情。 -

话又说回来,电脑平台易于发行游戏,因为有许多好用的打包软件帮助你构造游戏的架构(见下文游戏打包),为你的游戏配置适应电脑端的控制器也是很不错的做法——即使你的游戏主要面向手机用户。用户可以在任何平台畅玩你的游戏,电脑端也应该是其中之一。此外,在电脑端先构建和测试游戏通常更为便捷,然后再到手机端测试 BUG

+话又说回来,电脑平台易于发行游戏,因为有许多好用的打包软件帮助你构造游戏的架构(见下文[游戏打包](#游戏打包)),为你的游戏配置适应电脑端的控制器也是很不错的做法——即使你的游戏主要面向手机用户。用户可以在任何平台畅玩你的游戏,电脑端也应该是其中之一。此外,在电脑端先构建和测试游戏通常更为便捷,然后再到手机端测试 BUG -

发布游戏

+## 发布游戏 -

当你要发行游戏时,通常有三种主要的方式可供选择

+当你要发行游戏时,通常有三种主要的方式可供选择 -
    -
  • 自运营
  • -
  • 发行商代理
  • -
  • 上架商店
  • -
+- 自运营 +- 发行商代理 +- 上架商店 -

记住你的游戏名应该要足够独特,这样可以在发布之后迅速地推广, 但也要同样朗朗上口,这样人们才不会忘记。

+记住你的游戏名应该要足够独特,这样可以在发布之后迅速地[推广](/en-US/docs/Games/Techniques/Publishing_games/Game_promotion), 但也要同样朗朗上口,这样人们才不会忘记。 -

自运营

+### 自运营 -

如果你是前端开发者,你应该已经知道要做什么了。一个 HTML5 游戏不过是又一个网站而已.。你可以将它上传到远程服务器,设置一个好记的域名,然后就可以自己开始运营游戏了。

+如果你是前端开发者,你应该已经知道要做什么了。一个 HTML5 游戏不过是又一个网站而已.。你可以将它上传到远程服务器,设置一个好记的域名,然后就可以自己开始运营游戏了。 -

如果你想从游戏开发中赚钱,你应该用多种方法保护你的源码,这样其他人不会轻易地取得你的源码并且拿去当成自己的去出售。你可以压缩和精简代码,让它变得更小,更难读,这样他人就不能轻易的复刻你的游戏。一个更好的方法是在网上发布测试版如果你打算打包你的项目并把它出售给 Steam 或者 iTunes。

+如果你想从游戏开发中赚钱,你应该用多种方法保护你的源码,这样其他人不会轻易地取得你的源码并且拿去当成自己的去出售。你可以压缩和精简代码,让它变得更小,更难读,这样他人就不能轻易的复刻你的游戏。一个更好的方法是在网上发布测试版如果你打算打包你的项目并把它出售给 Steam 或者 iTunes。 -

如果你只是为了娱乐性质的话,开放源码可以让那些想要从你的作品中学习的人收益。你甚至不需要担心主机提供商,因为你可以在 Github 上托管游戏. 你可以有一个免费的主机,可控制的版本,以及可能的贡献者——如果这个项目足够有趣的话。

+如果你只是为了娱乐性质的话,开放源码可以让那些想要从你的作品中学习的人收益。你甚至不需要担心主机提供商,因为你可以[在 Github 上托管游戏](http://dev.end3r.com/2014/02/host-your-html5-games-on-github-pages/). 你可以有一个免费的主机,可控制的版本,以及可能的贡献者——如果这个项目足够有趣的话。 -

发行商和门户网站

+### 发行商和门户网站 -

顾名思义,开发商可以帮助你发行游戏,是否交给开发商则取决于你的游戏开发计划:你想在全平台发行么?或你只向购买了游戏的用户开放游戏?这都取决于你,考虑各个选项,试验和结论。你可以在游戏收益化这篇文章中得到更详细的关于发行商的解释。

+顾名思义,开发商可以帮助你发行游戏,是否交给开发商则取决于你的游戏开发计划:你想在全平台发行么?或你只向[购买了游戏](/en-US/docs/Games/Publishing_games/Game_monetization)的用户开放游戏?这都取决于你,考虑各个选项,试验和结论。你可以在[游戏收益化](/en-US/docs/Games/Techniques/Publishing_games/Game_monetization/)这篇文章中得到更详细的关于发行商的解释。 -

这里还有许多独立的门户网站收集 HTML5 游戏,例如 HTML5Games.com, MarketJS.com, Clay.io, or Poki 你可以把你的游戏发布上去,它会得到一些自然的推广,因为这些网站吸引了大量的流量。一些网站会把你的文件放在他们的服务器上运营,而其他网站则只链接到你的网站或将你的游戏嵌入他们的网站,这样的曝光可能只是为你的游戏提供宣传,如果你的游戏旁边有广告 (或其他赚钱的选项),它也可能为你的游戏提供收益化。

+这里还有许多独立的门户网站收集 HTML5 游戏,例如 [HTML5Games.com](http://html5games.com/), [MarketJS.com](http://www.marketjs.com/), [Clay.io](http://clay.io/), or [Poki](https://developers.poki.com/) 你可以把你的游戏发布上去,它会得到一些自然的推广,因为这些网站吸引了大量的流量。一些网站会把你的文件放在他们的服务器上运营,而其他网站则只链接到你的网站或将你的游戏嵌入他们的网站,这样的曝光可能只是为你的游戏提供宣传,如果你的游戏旁边有广告 (或其他赚钱的选项),它也可能为你的游戏提供收益化。 -

网络和应用商店

+### 网络和应用商店 -

你也可以直接把游戏发布到不同的应用商店里,或者是应用市场,要做到这一点,你必须准备好并将其打包为针对您想要针对的每个应用程序生态系统的特定构建格式。见下文应用市场—多样化平台来获取更多关于应用市场的细节

+你也可以直接把游戏发布到不同的应用商店里,或者是应用市场,要做到这一点,你必须准备好并将其打包为针对您想要针对的每个应用程序生态系统的特定构建格式。见下文[应用市场—多样化平台](#应用市场—多样化平台)来获取更多关于应用市场的细节 -

应用市场—多样化平台

+## 应用市场—多样化平台 -

让我们看看针对不同平台和操作系统的市场/商店有哪些可用选项。

+让我们看看针对不同平台和操作系统的市场/商店有哪些可用选项。 -
-

备注: 这些是最流行的发行平台,但这并不是说这些是唯一的选择。你也可以尝试找到一个对口的平台,并直接向那些对你的游戏感兴趣的观众推广你的游戏。在这里,你的创造力至关重要。

-
+> **备注:** 这些是最流行的发行平台,但这并不是说这些是唯一的选择。你也可以尝试找到一个对口的平台,并直接向那些对你的游戏感兴趣的观众推广你的游戏。在这里,你的创造力至关重要。 -

网络商店

+### 网络商店 -

最适合 HTML5 的平台是基于 web 的商店。为它们准备一款游戏很容易,因为这样的操作几乎不需要修改游戏本身——通常在包含所有资源的压缩包中添加包含必要信息的清单文件就足够了。

+最适合 HTML5 的平台是基于 web 的商店。为它们[准备一款游戏](http://code.tutsplus.com/tutorials/preparing-for-firefox-os--mobile-18515)很容易,因为这样的操作几乎不需要修改游戏本身——通常在包含所有资源的压缩包中添加包含必要信息的清单文件就足够了。 -
    -
  • Firefox OS 是 HTML5 游戏的完美硬件平台,因为系统本身是用 JavaScript 编写的,而且是开源的。您可以快速访问控制硬件的核心应用程序,Firefox Marketplace 是推广你的游戏的好地方,你也可以更进一步,允许人们直接从网络上安装你的游戏。
  • -
  • The Chrome Web Store 也是一个吸引人的选择——同样,准备好一个清单文件,压缩你的游戏并填写在线提交表单就足够了。
  • -
  • Tizen 还高度重视支持用 JavaScript 编写的应用程序。他们的商店是另一个可用的选择。
  • -
+- [Firefox OS](/pl/docs/Mozilla/Firefox_OS) 是 HTML5 游戏的完美硬件平台,因为系统本身是用 JavaScript 编写的,而且是开源的。您可以快速访问控制硬件的核心应用程序,[Firefox Marketplace](https://marketplace.firefox.com/) 是推广你的游戏的好地方,你也可以更进一步,允许人们直接从网络上安装你的游戏。 +- [The Chrome Web Store](https://chrome.google.com/webstore/) 也是一个吸引人的选择——同样,准备好一个清单文件,压缩你的游戏并填写在线提交表单就足够了。 +- [Tizen](http://www.tizenstore.com/) 还高度重视支持用 JavaScript 编写的应用程序。他们的商店是另一个可用的选择。 -

手机应用商店

+### 手机应用商店 -

在移动市场上,iOS 版的苹果应用商店 (Apple App Store)、Android 版的谷歌 Play 以及其他竞争对手。原生商店中已经充斥着销售优秀游戏的成熟开发者,所以你必须具备足够的天赋和幸运才能获得关注。

+在移动市场上,iOS 版的苹果应用商店 (Apple App Store)、Android 版的谷歌 Play 以及其他竞争对手。原生商店中已经充斥着销售优秀游戏的成熟开发者,所以你必须具备足够的天赋和幸运才能获得关注。 -
    -
  • iOS App Store 很难进入,因为游戏必须满足严格的要求,你必须等待一到两周才能被接受。此外,它是最著名的移动商店,有成千上万的应用程序,所以很难从人群中脱颖而出。
  • -
  • Google Play's 的要求不那么严格,所以商店被低质量的游戏污染了。由于每天提交的应用程序数量庞大,因此很难被注意到。在这里赚钱也更加困难——大多数来自 iOS 的付费游戏都是在 Android 上作为免费游戏发布的,盈利来自于应用内购买 (IAPs) 或广告。
  • -
  • 其他面向 Windows Phone 或黑莓 (Blackberry) 等本土移动平台的商店也在努力分一杯羹,而且远远落后于竞争对手。在那里提交你的游戏是很好的,因为它会更容易被注意到。
  • -
+- iOS App Store 很难进入,因为游戏必须满足严格的要求,你必须等待一到两周才能被接受。此外,它是最著名的移动商店,有成千上万的应用程序,所以很难从人群中脱颖而出。 +- Google Play's 的要求不那么严格,所以商店被低质量的游戏污染了。由于每天提交的应用程序数量庞大,因此很难被注意到。在这里赚钱也更加困难——大多数来自 iOS 的付费游戏都是在 Android 上作为免费游戏发布的,盈利来自于应用内购买 (IAPs) 或广告。 +- 其他面向 Windows Phone 或黑莓 (Blackberry) 等本土移动平台的商店也在努力分一杯羹,而且远远落后于竞争对手。在那里提交你的游戏是很好的,因为它会更容易被注意到。 -

如果你想了解更多关于不同类型的应用程序商店的信息,你可以在维基百科上查看手机软件发布平台列表

+如果你想了解更多关于不同类型的应用程序商店的信息,你可以在维基百科上查看[手机软件发布平台列表](https://en.wikipedia.org/wiki/List_of_mobile_software_distribution_platforms)。 -

电脑平台

+### 电脑平台 -

为了扩大你的受众,你也可以使用 HTML5 游戏去占据电脑游戏市场——只要记住那些已经占据了大部分市场份额的 AAA 级游戏,并仔细考虑这是否适合你的策略。要正确的在电脑端运行,您应该支持所有三种操作系统:Windows、Mac OS 和 Linux。最大的电脑游戏商店无疑是Steam — 独立开发者可以通过 Greenlight 接触 steam. 请记住,您必须通过为不同的平台上传不同的版本来处理跨平台问题。

+为了扩大你的受众,你也可以使用 HTML5 游戏去占据电脑游戏市场——只要记住那些已经占据了大部分市场份额的 AAA 级游戏,并仔细考虑这是否适合你的策略。要正确的在电脑端运行,您应该支持所有三种操作系统:Windows、Mac OS 和 Linux。最大的电脑游戏商店无疑是[Steam](http://steamcommunity.com/) — 独立开发者可以通过 [Greenlight](https://steamcommunity.com/greenlight/) 接触 steam. 请记住,您必须通过为不同的平台上传不同的版本来处理跨平台问题。 -

在你入驻 Steam 之后,便会有许多类似于Humble Bundle等项目的讨论,这些项目可以把最受欢迎的独立游戏能够呈现给更多人。不过,这更像是一个绝佳的促销机会,而不是一种赚大钱的方式,因为捆绑游戏的价格通常相当低。

+在你入驻 Steam 之后,便会有许多类似于[Humble Bundle](http://www.humblebundle.com/)等项目的讨论,这些项目可以把最受欢迎的独立游戏能够呈现给更多人。不过,这更像是一个绝佳的促销机会,而不是一种赚大钱的方式,因为捆绑游戏的价格通常相当低。 -

打包游戏

+## 打包游戏 -

网页是 HTML5 游戏的首选也是最好的选择,但如果你想接触到更广泛的受众并在封闭的生态系统中发行你的游戏,你仍然可以通过打包它来做到这一点。好在你不需要几个独立的团队在不同的平台上致力于同一款游戏——你可以一次性构建它,并使用像 Phonegap CocoonIO 这样的工具为本地商店打包游戏。生成的包通常非常可靠,但是您仍然应该测试它们,并注意要修复的小问题或 bug。

+网页是 HTML5 游戏的首选也是最好的选择,但如果你想接触到更广泛的受众并在封闭的生态系统中发行你的游戏,你仍然可以通过打包它来做到这一点。好在你不需要几个独立的团队在不同的平台上致力于同一款游戏——你可以一次性构建它,并使用像 [Phonegap](/en-US/docs/) 或[ CocoonIO](/en-US/docs/) 这样的工具为本地商店打包游戏。生成的包通常非常可靠,但是您仍然应该测试它们,并注意要修复的小问题或 bug。 -

实用工具

+### 实用工具 -

根据您的技能、首选框架或目标平台,可以选择多种工具。关键是为你的特定任务选择最好的工具。

+根据您的技能、首选框架或目标平台,可以选择多种工具。关键是为你的特定任务选择最好的工具。 -
    -
  • Phonegap —基于 Cordova,这是为本地平台构建/打包 JavaScript 应用程序最流行的工具
  • -
  • CocoonIO — 为多个本地商店构建 HTML5 游戏的最流行的工具。它对画布上呈现的游戏有自己的性能优化,并支持许多游戏框架。
  • -
  • Ejecta — 一个专门用于为 iOS 打包使用the ImpactJS框架创建的游戏的工具,由 ImpactJS 作者构建。它提供了与 ImpactJS 的无缝集成,但只支持一个框架和应用程序商店。
  • -
  • NW.js — 这款游戏的前身是 Node-Webkit,它是开发适用于 Windows、Mac 和 Linux 的桌面游戏的首选。这些发行版与 WebKit 引擎打包在一起,可以在任何平台上提供呈现。
  • -
+- [Phonegap](http://phonegap.com/) —基于 Cordova,这是为本地平台构建/打包 JavaScript 应用程序最流行的工具 +- [CocoonIO](http://cocoon.io/) — 为多个本地商店构建 HTML5 游戏的最流行的工具。它对画布上呈现的游戏有自己的性能优化,并支持许多游戏框架。 +- [Ejecta](http://impactjs.com/ejecta) — 一个专门用于为 iOS 打包使用[the ImpactJS](http://impactjs.com/)框架创建的游戏的工具,由 ImpactJS 作者构建。它提供了与 ImpactJS 的无缝集成,但只支持一个框架和应用程序商店。 +- [NW.js](http://nwjs.io/) — 这款游戏的前身是 Node-Webkit,它是开发适用于 Windows、Mac 和 Linux 的桌面游戏的首选。这些发行版与 WebKit 引擎打包在一起,可以在任何平台上提供呈现。 -

其他替代工具包括:

+其他替代工具包括: -
    -
  • Intel XDK — 一个很棒的的替代品,类似 CocoonIO。
  • -
  • Electron — 或者叫 Atom Shell,是 GitHub 的一个开源跨平台工具。.
  • -
  • Manifold.js — 微软团队的这个工具可以从 iOS、Android 和 Windows 创建 HTML5 游戏的本地发行版。
  • -
+- [Intel XDK](https://software.intel.com/en-us/intel-xdk) — 一个很棒的的替代品,类似 CocoonIO。 +- [Electron](http://electron.atom.io/) — 或者叫 Atom Shell,是 GitHub 的一个开源跨平台工具。. +- [Manifold.js](http://manifoldjs.com/) — 微软团队的这个工具可以从 iOS、Android 和 Windows 创建 HTML5 游戏的本地发行版。 -

总结

+## 总结 -

发行游戏是让你的世界为世界所知的方式,选择很多,但没有上上策。当你发行了游戏之后,便是专注于推广的时候了——让人们知道你的游戏的存在。没有推广,它们甚至都可能不知道有这个游戏,更别说玩了。

+发行游戏是让你的世界为世界所知的方式,选择很多,但没有上上策。当你发行了游戏之后,便是专注于[推广](/en-US/docs/Games/Techniques/Publishing_games/Game_promotion/)的时候了——让人们知道你的游戏的存在。没有推广,它们甚至都可能不知道有这个游戏,更别说玩了。 diff --git a/files/zh-cn/games/publishing_games/game_monetization/index.md b/files/zh-cn/games/publishing_games/game_monetization/index.md index ee34dfefd70387..d1fa7048c35158 100644 --- a/files/zh-cn/games/publishing_games/game_monetization/index.md +++ b/files/zh-cn/games/publishing_games/game_monetization/index.md @@ -9,88 +9,88 @@ tags: translation_of: Games/Publishing_games/Game_monetization original_slug: Games/Publishing_games/游戏货币化 --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

当你花时间创造一个游戏的时候,从发布促销中赚钱是你应该考虑的事。如果你正做出大量努力去成为一个能够以此为生的独立游戏开发者,接下去,看看你有哪些选择。技术手段已经足够成熟; 接下来只是选择正确的方法。

+当你花时间创造一个游戏的时候,从[发布](/en-US/docs/Games/Techniques/Publishing_games/Game_distribution)和[促销](/en-US/docs/Games/Techniques/Publishing_games/Game_promotion)中赚钱是你应该考虑的事。如果你正做出大量努力去成为一个能够以此为生的独立游戏开发者,接下去,看看你有哪些选择。技术手段已经足够成熟; 接下来只是选择正确的方法。 -

付费游戏

+## 付费游戏 -

你可能想到的第一个,也是最明显的选择便是以面向 AAA 级游戏的方式销售游戏——即固定的预付款。即使数字市场是关键,你也不需要打印封面,也不需要将游戏放在实体店的盒子里,但要想以固定的价格销售游戏赚取可观的利润,你必须将时间和金钱投入到市场营销中去。只有最好的游戏才能做到收支平衡,或者赚得比制作成本还要多,你仍然需要很多的运气。

+你可能想到的第一个,也是最明显的选择便是以面向 AAA 级游戏的方式销售游戏——即固定的预付款。即使数字市场是关键,你也不需要打印封面,也不需要将游戏放在实体店的盒子里,但要想以固定的价格销售游戏赚取可观的利润,你必须将时间和金钱投入到市场营销中去。只有最好的游戏才能做到收支平衡,或者赚得比制作成本还要多,你仍然需要很多的运气。 -

你为你的游戏收取多少费用取决于市场,游戏的质量和许多其他小因素。一款街机 iOS 游戏售价为 0.99 美元,但一款更长的 rpg 风格的 Steam 桌面游戏售价为 20 美元;两个价格都可以。你必须跟随市场,做自己的研究——迅速从错误中吸取教训是很重要的。

+你为你的游戏收取多少费用取决于市场,游戏的质量和许多其他小因素。一款街机 iOS 游戏售价为 0.99 美元,但一款更长的 rpg 风格的 Steam 桌面游戏售价为 20 美元;两个价格都可以。你必须跟随市场,做自己的研究——迅速从错误中吸取教训是很重要的。 -

应用内购买内容

+## 应用内购买内容 -

你可以提供一款带有应用内购买功能(IAP)的免费游戏,而不是让人们预先为你的游戏付费。在这种情况下,玩家不需要花一分钱就可以获得游戏——将游戏交给玩家,但要提供游戏内的货币、奖金或福利。具体的例子可以包括奖金水平,更好的武器或咒语,或补充所需的能量发挥。设计一个好的 IAP 系统本身就是一门艺术。

+你可以提供一款带有应用内购买功能(IAP)的免费游戏,而不是让人们预先为你的游戏付费。在这种情况下,玩家不需要花一分钱就可以获得游戏——将游戏交给玩家,但要提供游戏内的货币、奖金或福利。具体的例子可以包括奖金水平,更好的武器或咒语,或补充所需的能量发挥。设计一个好的 IAP 系统本身就是一门艺术。 -

记住,你需要下载数千次游戏才能使 IAPs 有效——只有一小部分玩家会真正为 IAPs 付费。多小?情况各不相同,但大约每千人中就有一个人处于平均水平。玩你的游戏的人越多,别人就越有可能付钱,所以你的收入很大程度取决于你的推广方式。

+记住,你需要下载数千次游戏才能使 IAPs 有效——只有一小部分玩家会真正为 IAPs 付费。多小?情况各不相同,但大约每千人中就有一个人处于平均水平。玩你的游戏的人越多,别人就越有可能付钱,所以你的收入很大程度取决于你的[推广](/en-US/docs/Games/Techniques/Publishing_games/Game_promotion)方式。 -

免费增值模式

+### 免费增值模式 -

带有 IAPs 功能的游戏通常被称为免费增值游戏——免费增值游戏可以免费取得与游玩,但你可以为额外的 (高级) 功能、虚拟物品或其他好处付费。在大公司专注于创造游戏后,这个词本身就带有负面含义,其主要目的是为了从玩家那里获得尽可能多的钱,而不是提供一种有趣的体验。最糟糕的情况是,你可以用真金实银来获得相对于其他玩家的优势,或限制玩家进入游戏的下一阶段,除非玩家付费。“为赢付费”这个术语是被创造出来的,并且这种方法不受许多玩家和开发者的欢迎。如果你想要实现 IAPs,那就试着用玩家喜欢的东西来为游戏增加价值,而不是把它拿出来然后收费。

+带有 IAPs 功能的游戏通常被称为免费增值游戏——免费增值游戏可以免费取得与游玩,但你可以为额外的 (高级) 功能、虚拟物品或其他好处付费。在大公司专注于创造游戏后,这个词本身就带有负面含义,其主要目的是为了从玩家那里获得尽可能多的钱,而不是提供一种有趣的体验。最糟糕的情况是,你可以用真金实银来获得相对于其他玩家的优势,或限制玩家进入游戏的下一阶段,除非玩家付费。“为赢付费”这个术语是被创造出来的,并且这种方法不受许多玩家和开发者的欢迎。如果你想要实现 IAPs,那就试着用玩家喜欢的东西来为游戏增加价值,而不是把它拿出来然后收费。 -

扩展包 (Add-on) 和可下载内容 (DLC)

+### 扩展包 (Add-on) 和可下载内容 (DLC) -

扩展包和可下载内容是为已经发行的游戏提供额外价值的好方法,但请记住,您必须提供体面的、有趣的内容来吸引人们购买它。一套全新的带有新角色、武器和故事的关卡对于 DLC 来说是一个很好的素材,但要想获得足够的销量,游戏本身必须是受欢迎的,否则就不会有玩家愿意将他们辛苦赚来的钱花在这上面。

+扩展包和可下载内容是为已经发行的游戏提供额外价值的好方法,但请记住,您必须提供体面的、有趣的内容来吸引人们购买它。一套全新的带有新角色、武器和故事的关卡对于 DLC 来说是一个很好的素材,但要想获得足够的销量,游戏本身必须是受欢迎的,否则就不会有玩家愿意将他们辛苦赚来的钱花在这上面。 -

推广

+## 推广 -

除了积极销售游戏以外,你也可以尝试被动销售 — 投放广告和开展相关活动或许有益于推广你的游戏,但你的游戏必须让人上瘾,这并不像听起来那么容易。你仍然需要计划好,在某种程度上,你也需要一些运气。如果你的游戏像病毒一样传播开来,人们开始分享它,你就能从广告中获得大量的下载和收益。

+除了积极销售游戏以外,你也可以尝试被动销售 — 投放广告和开展相关活动或许有益于[推广](/en-US/docs/Games/Techniques/Publishing_games/Game_promotion)你的游戏,但你的游戏必须让人上瘾,这并不像听起来那么容易。你仍然需要计划好,在某种程度上,你也需要一些运气。如果你的游戏像病毒一样传播开来,人们开始分享它,你就能从广告中获得大量的下载和收益。 -

有许多公司提供广告系统——你注册后,允许他们展示广告,以换取一定比例的利润。谷歌 AdSense 被认为是最有效的一个,但它不是为游戏而设计的,使用它来达到这个目的是一个非常糟糕的做法。不要冒着让你的账户被封禁,资产被冻结的风险,游戏开发者们更青睐门户网站,如LeadBolt。他们提供了易于实现的系统,以在您的游戏显示广告并与您分享收益。

+有许多公司提供广告系统——你注册后,允许他们展示广告,以换取一定比例的利润。谷歌 AdSense 被认为是最有效的一个,但它不是为游戏而设计的,使用它来达到这个目的是一个非常糟糕的做法。不要冒着让你的账户被封禁,资产被冻结的风险,游戏开发者们更青睐门户网站,如[LeadBolt](https://www.leadbolt.com/)。他们提供了易于实现的系统,以在您的游戏显示广告并与您分享收益。 -

视频广告正变得越来越受欢迎,特别是以预播放的形式——它们会在游戏开始时显示,而此时游戏还在加载中。至于在游戏中放置广告的位置,这完全取决于你自己。它应该尽可能的微妙,以避免过多地惹恼玩家,但又足够的可见性让玩家点击它或至少注意到它。通过屏幕在游戏会话之间添加广告是一种流行的方法。

+视频广告正变得越来越受欢迎,特别是以预播放的形式——它们会在游戏开始时显示,而此时游戏还在加载中。至于在游戏中放置广告的位置,这完全取决于你自己。它应该尽可能的微妙,以避免过多地惹恼玩家,但又足够的可见性让玩家点击它或至少注意到它。通过屏幕在游戏会话之间添加广告是一种流行的方法。 -

授权证书

+## 授权证书 -

有一种方法可以作为自己的盈利模式,即出售游戏发行许可。越来越多的门户网站有兴趣在他们的网站上展示你的游戏。他们遵循各种策略来通过你的游戏赚钱,但你不必担心所有这些,因为出售许可通常是一次性的交易。你得到了钱,他们就可以创造性地使用你的游戏来赚钱。

+有一种方法可以作为自己的盈利模式,即出售游戏发行许可。越来越多的门户网站有兴趣在他们的网站上展示你的游戏。他们遵循各种策略来通过你的游戏赚钱,但你不必担心所有这些,因为出售许可通常是一次性的交易。你得到了钱,他们就可以创造性地使用你的游戏来赚钱。 -

一开始寻找发行商是件困难的事情 — 你可以在HTML5 Gamedevs forums联络他们.。如果你很有名,他们可能会联系你。大多数交易都是通过电子邮件与出版商一方的专业人士进行沟通的。一些出版商的网站很容易获得这些信息,而另一些则很难找到。当接触出版商的时候,尽量友好而直接——他们都是很忙的人。

+一开始寻找发行商是件困难的事情 — 你可以在[HTML5 Gamedevs forums](http://www.html5gamedevs.com/)联络他们.。如果你很有名,他们可能会联系你。大多数交易都是通过电子邮件与出版商一方的专业人士进行沟通的。一些出版商的网站很容易获得这些信息,而另一些则很难找到。当接触出版商的时候,尽量友好而直接——他们都是很忙的人。 -

独家许可

+### 独家许可 -

独家性许可是针对一个发行商的一种许可类型——你创造了一款游戏,并将其所有权利出售给了一个实体,同时还拥有重新发行该游戏的权利 — Softgames就是这样一家发行商。 在出版商拥有版权的情况下,你不能再以任何形式出售它——这就是独家交易价值不菲的原因。到底是多少?这取决于游戏的质量,游戏类型,发行商,以及其他许多因素,但通常价格在 2000 到 5000 美元之间。一旦你卖出了独家授权,你就不用再参与推广这款游戏了,因为你赚不到更多钱,所以只有在你确信这款游戏足够盈利的情况下,你才会参与这样的交易。

+独家性许可是针对一个发行商的一种许可类型——你创造了一款游戏,并将其所有权利出售给了一个实体,同时还拥有重新发行该游戏的权利 — [Softgames](http://www.softgames.de/)就是这样一家发行商。 在出版商拥有版权的情况下,你不能再以任何形式出售它——这就是独家交易价值不菲的原因。到底是多少?这取决于游戏的质量,游戏类型,发行商,以及其他许多因素,但通常价格在 2000 到 5000 美元之间。一旦你卖出了独家授权,你就不用再参与推广这款游戏了,因为你赚不到更多钱,所以只有在你确信这款游戏足够盈利的情况下,你才会参与这样的交易。 -

独家许可

+### 独家许可 -

这种方法不那么严格——您可以将许可证出售给多个发布者。这是最受欢迎的方法,因为对于每一个新的发行商 (总会有的),你都可以以非独家的条款出售你的游戏。请记住,有了这个许可,发行商就不能再对其进行重新发行了——这通常被称为站点锁定交易,因为他们购买了在自己的门户网站上发布游戏的权利。非独家许可的通常成本约为 500 美元。

+这种方法不那么严格——您可以将许可证出售给多个发布者。这是最受欢迎的方法,因为对于每一个新的发行商 (总会有的),你都可以以非独家的条款出售你的游戏。请记住,有了这个许可,发行商就不能再对其进行重新发行了——这通常被称为站点锁定交易,因为他们购买了在自己的门户网站上发布游戏的权利。非独家许可的通常成本约为 500 美元。 -

定期付费

+### 定期付费 -

此外,用户还可以通过购买服务来月付你的游戏而不是一次性付款,每一款游戏每月都能为你提供一定的钱——大约 20-50 美元。你可以决定是一次性付清一段时间还是每月付一次。记住它可以被随时取消,所以它不是一个通解。

+此外,用户还可以通过购买服务来月付你的游戏而不是一次性付款,每一款游戏每月都能为你提供一定的钱——大约 20-50 美元。你可以决定是一次性付清一段时间还是每月付一次。记住它可以被随时取消,所以它不是一个通解。 -

推广收入

+### 推广收入 -

你可以在自己的游戏中发布广告,并试图找到流量来赚取一些钱,但你也可以与发行商达成收益分成协议。他们将负责吸引流量,并将分享收益——通常是每月 73 开或者五五开的交易。

+你可以在自己的游戏中发布广告,并试图找到流量来赚取一些钱,但你也可以与发行商达成收益分成协议。他们将负责吸引流量,并将分享收益——通常是每月 73 开或者五五开的交易。 -

请记住,许多新的、低质量的发行商会希望你的游戏获得广告收入而不是授权,因为这对他们来说更便宜,并且你可能只会在整个交易中获得每款游戏约 2 美元的收益。在与新出版商打交道时要小心——有时候,降低已知出版商的许可成本比冒着被未知出版商骗钱的风险要好。

+请记住,许多新的、低质量的发行商会希望你的游戏获得广告收入而不是授权,因为这对他们来说更便宜,并且你可能只会在整个交易中获得每款游戏约 2 美元的收益。在与新出版商打交道时要小心——有时候,降低已知出版商的许可成本比冒着被未知出版商骗钱的风险要好。 -

发行商从你的游戏中获取收益分成,以及/或许可可能需要实现他们自己的 API,这可能需要额外的工作,所以你也要考虑到这一点。

+发行商从你的游戏中获取收益分成,以及/或许可可能需要实现他们自己的 API,这可能需要额外的工作,所以你也要考虑到这一点。 -

品牌

+### 品牌 -

你可以出售你的游戏的品牌使用权,也可以用你自己的游戏来招揽其他人的品牌。在第一种情况下,它几乎类似于非独占许可,但是你的客户通常会购买代码的权限并构建自己的游戏。在第二种情况下,它就像一个自由的交易,但你将会在代码中加入客户的品牌图形,或有时会按照他们的指示实现需求。举个例子,如果你有一个游戏,玩家点击食物,你可以把食物换成客户的产品来给他们做广告。这个模型中的价格根据品牌、客户和工作量的不同而有很大的差异。

+你可以出售你的游戏的品牌使用权,也可以用你自己的游戏来招揽其他人的品牌。在第一种情况下,它几乎类似于非独占许可,但是你的客户通常会购买代码的权限并构建自己的游戏。在第二种情况下,它就像一个自由的交易,但你将会在代码中加入客户的品牌图形,或有时会按照他们的指示实现需求。举个例子,如果你有一个游戏,玩家点击食物,你可以把食物换成客户的产品来给他们做广告。这个模型中的价格根据品牌、客户和工作量的不同而有很大的差异。 -

其他不以游戏为主题的变现手段

+## 其他不以游戏为主题的变现手段 -

在开发 HTML5 游戏时,你还可以通过其他方式赚钱,而这甚至不需要与游戏相关。

+在开发 HTML5 游戏时,你还可以通过其他方式赚钱,而这甚至不需要与游戏相关。 -

销售资源

+### 销售资源 -

如果你是一名平面设计师,你可以出售你所创造的游戏的资产,或一些全新的专为这一目的的在线商店,如Envato Market. 虽然卖的钱并不多,但如果你是一个著名的设计师,它就是一个额外的被动收入流。

+如果你是一名平面设计师,你可以出售你所创造的游戏的资产,或一些全新的专为这一目的的在线商店,如[Envato Market](http://market.envato.com/). 虽然卖的钱并不多,但如果你是一个著名的设计师,它就是一个额外的被动收入流。 -

撰写文章和教程

+### 撰写文章和教程 -

你可以写一些关于你的游戏的文章,甚至可以从中获得报酬。可以同时取得游戏推广和收益化的双赢,如果你不滥用它与太多的广告,读者将享受阅读他们以及学习一两个东西。如果你专注于先分享知识,并将游戏作为例子来使用,这应该是可以的。浏览Tuts+ Game Development 或相似的网站来找寻协作机会

+你可以写一些关于你的游戏的文章,甚至可以从中获得报酬。可以同时取得游戏[推广](/en-US/docs/Games/Techniques/Publishing_games/Game_promotion)和收益化的双赢,如果你不滥用它与太多的广告,读者将享受阅读他们以及学习一两个东西。如果你专注于先分享知识,并将游戏作为例子来使用,这应该是可以的。浏览[Tuts+ Game Development](http://gamedevelopment.tutsplus.com/) 或相似的网站来找寻协作机会 -

周边商品

+### 周边商品 -

你可以售卖 T 恤,贴纸或其他周边 — 有些开发者从这些商品中赚的钱比从游戏本身中赚的钱还多,但它只适用于像愤怒的小鸟这样非常受欢迎且易于识别的游戏。不过,这也可能是另一种小的被动收入来源。你的收入越多样化,你的生意就越稳定。

+你可以售卖 T 恤,[贴纸](https://www.stickermule.com/user/1070634890/stickers)或其他周边 — 有些开发者从这些商品中赚的钱比从游戏本身中赚的钱还多,但它只适用于像愤怒的小鸟这样非常受欢迎且易于识别的游戏。不过,这也可能是另一种小的被动收入来源。你的收入越多样化,你的生意就越稳定。 -

捐助

+### 捐助 -

当其他方法都失败时,你可以尝试在你的游戏页面上放置一个捐赠按钮并寻求社区的支持。有时候它是有效的,但前提是玩家了解你并觉得它能够帮助你。这就是为什么小心管理你的社区是如此重要。这在js13kGames比赛中很管用 — 每个参与者都得到了一件免费的 t 恤,有些人甚至还退了一些钱,以帮助它在未来几年继续运行下去。

+当其他方法都失败时,你可以尝试在你的游戏页面上放置一个捐赠按钮并寻求社区的支持。有时候它是有效的,但前提是玩家了解你并觉得它能够帮助你。这就是为什么小心管理你的社区是如此重要。这在[js13kGames](http://js13kgames.com/)比赛中很管用 — 每个参与者都得到了一件免费的 t 恤,有些人甚至还退了一些钱,以帮助它在未来几年继续运行下去。 -

小结

+## 小结 -

赚钱的方法有很多种——所有适用于“普通”AAA 级游戏世界的东西,或多或少都可以应用于休闲 HTML5 游戏。然而,你也可以专注于销售许可证,做品牌,或者从广告中获得收入分成。你要走哪条路完全取决于你自己。

+赚钱的方法有很多种——所有适用于“普通”AAA 级游戏世界的东西,或多或少都可以应用于休闲 HTML5 游戏。然而,你也可以专注于销售许可证,做品牌,或者从广告中获得收入分成。你要走哪条路完全取决于你自己。 diff --git a/files/zh-cn/games/publishing_games/game_promotion/index.md b/files/zh-cn/games/publishing_games/game_promotion/index.md index 6f0985c800330a..a894a1209c9be3 100644 --- a/files/zh-cn/games/publishing_games/game_promotion/index.md +++ b/files/zh-cn/games/publishing_games/game_promotion/index.md @@ -3,77 +3,77 @@ title: Game promotion slug: Games/Publishing_games/Game_promotion translation_of: Games/Publishing_games/Game_promotion --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

开发与发行你的游戏并不是全部.。你应该让大家知道你有个大家会喜欢玩的游戏。这儿有很多方法去推广你的游戏——大部分方法是免费的,所以即使即使你正努力以一名零预算的独立开发者的身份谋生,你也可以让人们知道你的新游戏.。推广游戏也对之后的游戏收益化大有裨益,所以正确地推广游戏是很重要的。

+开发与发行你的游戏并不是全部.。你应该让大家知道你有个大家会喜欢玩的游戏。这儿有很多方法去推广你的游戏——大部分方法是免费的,所以即使即使你正努力以一名零预算的独立开发者的身份谋生,你也可以让人们知道你的新游戏.。推广游戏也对之后的[游戏收益化](/en-US/docs/Games/Techniques/Publishing_games/Game_monetization)大有裨益,所以正确地推广游戏是很重要的。 -

竞赛

+## 竞赛 -

参加竞赛不仅将提升您的游戏开发技能,让你认识新朋友、学习开发,它还将让你参与到社区之中。如果你在比赛中做了一个好的游戏并赢得了一些奖品,你的游戏就会自然而然地被组织者和其他参与者推广开来。你会变得富有和出名,至少他们是这么说的。
- 许多优秀的游戏都是从一个游戏制作比赛上的 demo 开始的。如果你的想法和执行力都足够好,你就会成功。另外,比赛通常要求游戏有一个固定的主题,所以如果你一筹莫展,你也可以围绕这个主题进行创作。

+参加竞赛不仅将提升您的游戏开发技能,让你认识新朋友、学习开发,它还将让你参与到社区之中。如果你在比赛中做了一个好的游戏并赢得了一些奖品,你的游戏就会自然而然地被组织者和其他参与者推广开来。你会变得富有和出名,至少他们是这么说的。 +许多优秀的游戏都是从一个游戏制作比赛上的 demo 开始的。如果你的想法和执行力都足够好,你就会成功。另外,比赛通常要求游戏有一个固定的主题,所以如果你一筹莫展,你也可以围绕这个主题进行创作。 -

网站与博客

+## 网站与博客 -

你应该创建自己的网站,包含所有关于游戏的信息,这样人们就可以看到你在做什么。你能包含的信息越多越好 — 包括截图,简报,预告,宣传资料,需求,可用的平台,赞助以及其他。让你的用户在网上直接玩你的游戏——或者说测试版可以让你得到许多电子。同时,为了让你的用户能够更好的玩游戏,你应该做些网站优化(SEO)

+你应该创建自己的网站,包含所有关于游戏的信息,这样人们就可以看到你在做什么。你能包含的信息越多越好 — 包括截图,简报,预告,宣传资料,需求,可用的平台,赞助以及其他。让你的用户在网上直接玩你的游戏——或者说测试版可以让你得到许多电子。同时,为了让你的用户能够更好的玩游戏,你应该做些网站优化(SEO) -

你也应该在博客公布所有与你游戏开发有关的动作,写下你的开发历程,严重的 bug,有趣的事情,经验教训,以及作为游戏开发者的起起伏伏。坚持发布信息有助于他人从中学习,提高你在社区中的声誉,改进你的网站优化。另一种选择是发布每月报告——总结你所有进展的报告——它能够帮助你看到你在整个月都完成了什么,还有什么需要去做,并不断提醒人们你的游戏即将发行——创造口碑总是好的。

+你也应该在博客公布所有与你游戏开发有关的动作,写下你的开发历程,严重的 bug,有趣的事情,经验教训,以及作为游戏开发者的起起伏伏。坚持发布信息有助于他人从中学习,提高你在社区中的声誉,改进你的网站优化。另一种选择是发布[每月报告](http://dev.end3r.com/?s=monthly+report)——总结你所有进展的报告——它能够帮助你看到你在整个月都完成了什么,还有什么需要去做,并不断提醒人们你的游戏即将发行——创造口碑总是好的。 -

社交媒体

+## 社交媒体 -

你的社交媒体的风格很重要 — 选择正确的标签,交朋结友,参与交流,帮助其他开发者。保持真诚,这是你与人结交的关键,因为没有人喜欢无聊的新闻发布或者硬广告.。一旦游戏完成,你的社区会帮助你宣传你的小宝贝游戏的

+你的社交媒体的风格很重要 — 选择正确的[标签](https://twitter.com/hashtag/gamedev),交朋结友,参与交流,帮助其他开发者。保持真诚,这是你与人结交的关键,因为没有人喜欢无聊的新闻发布或者硬广告.。一旦游戏完成,你的社区会帮助你宣传你的小宝贝游戏的 -

你应该至少使用推特(Twitter)和脸书(Facebook)之中的一个,并且入驻一个合适的论坛,最出名的就是 HTML5GameDevs.com. 分享你的游戏开发信息,回答别人的问题,这样人们会在心里衡量你所做的一切并且知道你做的很好.。记住也别逢人就说你的游戏——你可不是行走的广告

+你应该至少使用推特(Twitter)和脸书(Facebook)之中的一个,并且入驻一个合适的论坛,最出名的就是 [HTML5GameDevs.com](http://www.html5gamedevs.com/). 分享你的游戏开发信息,回答别人的问题,这样人们会在心里衡量你所做的一切并且知道你做的很好.。记住也别逢人就说你的游戏——你可不是行走的广告 -

发展你的粉丝,你可以与他们交流,分享一些小贴士,提供一些福利,在比赛中分发奖品,或者只是抱怨天气或者浏览器的问题,举止冷静,慷慨大方,做你自己,去帮助别人,你就会得到尊重。

+发展你的粉丝,你可以与他们交流,分享一些小贴士,提供一些福利,在比赛中分发奖品,或者只是抱怨天气或者浏览器的问题,举止冷静,慷慨大方,做你自己,去帮助别人,你就会得到尊重。 -

游戏门户网站

+## 游戏门户网站 -

设立门户网站主要与收益化挂钩, 但是如果你不打算售卖许可来让人们可以购买你的游戏而是打算发布广告 , 在免费的门户网站上推广游戏会更有效。你可以在公共门户网站,比如HTML5Games.com发布游戏,比起传统的游戏发行平台,它更像一个宣传平台。

+设立门户网站主要与[收益化](/en-US/docs/Games/Techniques/Publishing_games/Game_monetization)挂钩, 但是如果你不打算[售卖许可](/en-US/docs/Games/Techniques/Publishing_games/Game_monetization#Licensing)来让人们可以购买你的游戏而是打算[发布广告](/en-US/docs/Games/Techniques/Publishing_games/Game_monetization#Advertisements) , 在免费的门户网站上推广游戏会更有效。你可以在公共门户网站,比如[HTML5Games.com](http://html5games.com/)发布游戏,比起传统的游戏发行平台,它更像一个宣传平台。 -

免费的门户网站带来了流量,但是,只有最好的广告才足够受欢迎,能够从发布的广告中获得一些业绩。另一方面,如果你没有预算和有限的时间,门户网站也是一个完美的工具,它可以让更多人看到你的游戏

+免费的门户网站带来了流量,但是,只有最好的广告才足够受欢迎,能够从发布的广告中获得一些业绩。另一方面,如果你没有预算和有限的时间,门户网站也是一个完美的工具,它可以让更多人看到你的游戏 -

媒体宣传

+## 媒体宣传 -

你可以试着联系媒体去宣传你的游戏,不过要记住,他们每天都在处理成吨的请求,所以如果它们没有及时回复你,请保持耐心,在于他们交流时保持礼貌。一定要先检查他们是否只接纳特定类型的游戏或平台,这样你才不会发送与之无关的内容。如果你方式恰当并且你的游戏很好,那么你就有更多的成功机会

+你可以试着联系媒体去宣传你的游戏,不过要记住,他们每天都在处理成吨的请求,所以如果它们没有及时回复你,请保持耐心,在于他们交流时保持礼貌。一定要先检查他们是否只接纳特定类型的游戏或平台,这样你才不会发送与之无关的内容。如果你方式恰当并且你的游戏很好,那么你就有更多的成功机会 -

如果你想了解更多关于联系媒体的礼仪,你可以阅读 How To Contact Press - 由 Pixel Prospector 编写的一篇很棒的指南,还有Video Game Journaliser,他们创建的一个记录媒体联络名单的网站。

+如果你想了解更多关于联系媒体的礼仪,你可以阅读 [How To Contact Press](http://www.pixelprospector.com/how-to-contact-press/) - 由 Pixel Prospector 编写的一篇很棒的指南,还有[Video Game Journaliser](http://videogamejournaliser.com/),他们创建的一个记录媒体联络名单的网站。 -

教程

+## 教程 -

与其他开发者互通有无是很好的 — 毕竟你可能也曾在网上的一两篇文章上学到了些东西,所以你要花时间把这些知识传递出去。谈论或写一些你取得的成就或克服的问题是人们会感兴趣的事情。你可以拿你自己的游戏做例子,特别是当你展示你已经实现的事情. 这样每个人都会受益——人们学习新的技能,你的游戏会得到推广,如果你足够幸运,你甚至可以因为编写教程而获得报酬

+与其他开发者互通有无是很好的 — 毕竟你可能也曾在网上的一两篇文章上学到了些东西,所以你要花时间把这些知识传递出去。谈论或写一些你取得的成就或克服的问题是人们会感兴趣的事情。你可以拿你自己的游戏做例子,特别是当你[展示你已经实现的事情](/en-US/docs/Games/Techniques/Controls_Gamepad_API). 这样每个人都会受益——人们学习新的技能,你的游戏会得到推广,如果你足够幸运,你甚至可以因为编写教程而获得报酬 -

像是Tuts+ Game Development 这样的网站可能会更让人开心——他们为文章付稿费。 但并不是所有的主旨都会被接受。当你在写教程的时候,记住要把重点放在给读者提供一些有价值的东西上。他们想要学习一些东西——提供你的专业知识并将你的游戏作为案例研究。专注于一个方面,并试图解释它的全部和细节。如果人们有任何问题,请记得在评论中跟进讨论。

+像是[Tuts+ Game Development](http://gamedevelopment.tutsplus.com/) 这样的网站可能会更让人开心——他们为文章付稿费。 但并不是所有的主旨都会被接受。当你在写教程的时候,记住要把重点放在给读者提供一些有价值的东西上。他们想要学习一些东西——提供你的专业知识并将你的游戏作为案例研究。专注于一个方面,并试图解释它的全部和细节。如果人们有任何问题,请记得在评论中跟进讨论。 -

如果您联系的门户网站因你未写过教程而未采纳你的教程,可以在自己的博客先发布教程,这是锻炼你的写作技巧的最简单的方式。

+如果您联系的门户网站因你未写过教程而未采纳你的教程,可以在[自己的博客](/en-US/docs/Games/Publishing_games/Game_promotion#Website_and_blog)先发布教程,这是锻炼你的写作技巧的最简单的方式。 -

YouTuber 视频主 (YouTubers)

+## YouTuber 视频主 (YouTubers) -

这是一种趋势 — 别低估了 YouTuber 视频主(YouTubers)们对游戏的影响力,与他们交流,让他们做游戏实况会极大的宣传你的游戏。不过,你也应该现实一点——不要认为仅仅这一点就会让你的下载量或访问量飙升,而且要准备好处理好不好的评论。

+这是一种趋势 — 别低估了 YouTuber 视频主(YouTubers)们对游戏的影响力,与他们交流,让他们做游戏实况会极大的宣传你的游戏。不过,你也应该现实一点——不要认为仅仅这一点就会让你的下载量或访问量飙升,而且要准备好处理好不好的评论。 -

有两种方法可以让 Youtubers 选择你的游戏:第一种方法是你直接联系他们,并通过电子邮件或私人信息向他们发送游戏链接。第二种方法更省时 - 如果你很有名,Youtubers 可能会向你索要游戏链接或游戏文件。这个YouTuber 的名单是个很好的开始。

+有两种方法可以让 Youtubers 选择你的游戏:第一种方法是你直接联系他们,并通过电子邮件或私人信息向他们发送游戏链接。第二种方法更省时 - 如果你很有名,Youtubers 可能会向你索要游戏链接或游戏文件。这个[YouTuber 的名单](http://videogamecaster.com/big-list-of-youtubers)是个很好的开始。 -

活动

+## 活动 -

如果你已经完成了上面列出的所有选项,你仍然可以找到新的、创造性的方式去推广你的游戏——活动便是另一个很好的例子。参加本地和全球的活动,让您能够面对面地与您的粉丝以及开发社区的其他成员见面。别辜负了他们专程花时间来看你的心思。.

+如果你已经完成了上面列出的所有选项,你仍然可以找到新的、创造性的方式去推广你的游戏——活动便是另一个很好的例子。参加本地和全球的活动,让您能够面对面地与您的粉丝以及开发社区的其他成员见面。别辜负了他们专程花时间来看你的心思。. -

会议

+### 会议 -

在许多会议上,您可以发表演讲,解释您克服的一些技术困难,或者如何实现特定的 API;其次,以你的游戏为例。专注于知识部分并降低市场营销是很重要的——开发者对这个问题很敏感,如果你只是想向他们推销一些东西,他们可能会对此不满。.

+在许多会议上,您可以发表演讲,解释您克服的一些技术困难,或者如何实现特定的 API;其次,以你的游戏为例。专注于知识部分并降低市场营销是很重要的——开发者对这个问题很敏感,如果你只是想向他们推销一些东西,他们可能会对此不满。. -

展会

+### 展会 -

另一个与活动相关的选项是展会 (或博览会)——在这样的活动中,您可以在其他开发者中获得一个摊位,并向所有经过的参与者推广您的游戏。如果你这样做了,那就试着做得独特而有创意,这样你就很容易从人群中脱颖而出。以正确的方式去做,每个人都会谈论你和你的游戏。有一个展台可以让你与你的粉丝直接互动——除了推广部分,你还可以在普通人身上测试你的游戏的新版本,并修复他们发现的任何 bug(或包含任何反馈)。你无法想象人们在玩你的游戏时可能会想到什么,以及你在花费数小时打磨游戏时错过了哪些明显的问题。

+另一个与活动相关的选项是展会 (或博览会)——在这样的活动中,您可以在其他开发者中获得一个摊位,并向所有经过的参与者推广您的游戏。如果你这样做了,那就试着做得独特而有创意,这样你就很容易从人群中脱颖而出。以正确的方式去做,每个人都会谈论你和你的游戏。有一个展台可以让你与你的粉丝直接互动——除了推广部分,你还可以在普通人身上测试你的游戏的新版本,并修复他们发现的任何 bug(或包含任何反馈)。你无法想象人们在玩你的游戏时可能会想到什么,以及你在花费数小时打磨游戏时错过了哪些明显的问题。 -

优惠码

+## 优惠码 -

如果你是在销售游戏,那么你应该发行优惠码让人们免费游玩你的游戏 (或至少是一个演示版或限时版),并把它们发送到各地——给媒体,Youtuber,作为比赛奖品等等。如果游戏符合某些人的胃口,就相当于为成千上万人打了一次免费广告。如果你幸运的话,它比任何其他东西都能提高人们对你的游戏的兴趣

+如果你是在销售游戏,那么你应该发行优惠码让人们免费游玩你的游戏 (或至少是一个演示版或限时版),并把它们发送到各地——给媒体,Youtuber,作为比赛奖品等等。如果游戏符合某些人的胃口,就相当于为成千上万人打了一次免费广告。如果你幸运的话,它比任何其他东西都能提高人们对你的游戏的兴趣 -

培养社区

+## 培养社区 -

你可以帮助社区成长,同时推广你自己和你的游戏。发布每周时事通讯,组织在线竞赛或者线下聚会,这些都能让别人知道你对自己的工作充满激情,他们可以依靠你。当你需要帮助的时候,他们会在你身边

+你可以帮助社区成长,同时推广你自己和你的游戏。发布[每周时事通讯](http://gamedevjsweekly.com/),组织[在线竞赛](http://js13kgames.com/)或者[线下聚会](http://gamedevjs.com/),这些都能让别人知道你对自己的工作充满激情,他们可以依靠你。当你需要帮助的时候,他们会在你身边 -

总结

+## 总结 -

任何推广你的游戏的方法都是好的。你有很多选择,其中大部分都是免费的,所以关键在于你的热情和可用时间。有时候你不得不花更多的时间去推广一款游戏,而不是真正去开发它。记住,如果没有人知道世界上最好的游戏的存在,那么拥有它是没有任何意义的。

+任何推广你的游戏的方法都是好的。你有很多选择,其中大部分都是免费的,所以关键在于你的热情和可用时间。有时候你不得不花更多的时间去推广一款游戏,而不是真正去开发它。记住,如果没有人知道世界上最好的游戏的存在,那么拥有它是没有任何意义的。 -

现在让我们进入游戏收益化部分,然后挣口饭吃吧。

+现在让我们进入[游戏收益化](/en-US/docs/Games/Techniques/Publishing_games/Game_monetization)部分,然后挣口饭吃吧。 diff --git a/files/zh-cn/games/publishing_games/index.md b/files/zh-cn/games/publishing_games/index.md index 373ca8236d3fa7..01eae27136723e 100644 --- a/files/zh-cn/games/publishing_games/index.md +++ b/files/zh-cn/games/publishing_games/index.md @@ -8,16 +8,18 @@ tags: - 获利 translation_of: Games/Publishing_games --- -
{{GamesSidebar}}

HTML5 游戏在发布和分发上具有极大的优势--你可以通过网络自由地发布,推广,获利,并且不受分发商的限制。你可以实现通过多种平台获利。这一系列的案例关注在当你想要发布,推广你的游戏,并当游戏变得有名时获取一些回报。

+{{GamesSidebar}} -

游戏发布

+HTML5 游戏在发布和分发上具有极大的优势--你可以通过网络自由地发布,推广,获利,并且不受分发商的限制。你可以实现通过多种平台获利。这一系列的案例关注在当你想要发布,推广你的游戏,并当游戏变得有名时获取一些回报。 -

你按照一个或两个教程(12)制作了一个 HTML5 游戏。Game distribution提供了你发布游戏时所需的一切知识。包括如何在线托管游戏,提交游戏到开放的游戏市场,或封闭的游戏市场,如 Google Play,iOS App Store.

+## 游戏发布 -

游戏推广

+你按照一个或两个教程([1](/zh-CN/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript),[2](/zh-CN/docs/Games/Workflows/2D_Breakout_game_Phaser))制作了一个 HTML5 游戏。[Game distribution](/zh-CN/docs/Games/Publishing_games/Game_distribution)提供了你发布游戏时所需的一切知识。包括如何在线托管游戏,提交游戏到开放的游戏市场,或封闭的游戏市场,如 Google Play,iOS App Store. -

开发完成游戏并不是结束。你必须让世界知道你制作了一些有趣的东西能使他们乐在其中。这些游戏推广技术— 有些是免费的 — 即使你作为一名 0 预算的独立开发者为生活奔波,你依旧可以让很多人知道你制作的这个新游戏。推广游戏或许能够使你获得收入。高效的推广非常重要。

+## 游戏推广 -

游戏获利

+开发完成游戏并不是结束。你必须让世界知道你制作了一些有趣的东西能使他们乐在其中。这些[游戏推广](/zh-CN/docs/Games/Publishing_games/Game_promotion)技术— 有些是免费的 — 即使你作为一名 0 预算的独立开发者为生活奔波,你依旧可以让很多人知道你制作的这个新游戏。推广游戏或许能够使你获得收入。高效的推广非常重要。 -

当你开发,发布并推广你的游戏后,你可以考虑通过游戏来获得收入。游戏获利对于考虑从业余转为全职并以此为生的开发者来说是必要的一个手段。现在来看看你的选择,技术已经足够成熟,现在只差一个合适的机会了。

+## 游戏获利 + +当你开发,发布并推广你的游戏后,你可以考虑通过游戏来获得收入。[游戏获利](/zh-CN/docs/Games/Publishing_games/Game_monetization)对于考虑从业余转为全职并以此为生的开发者来说是必要的一个手段。现在来看看你的选择,技术已经足够成熟,现在只差一个合适的机会了。 diff --git a/files/zh-cn/games/techniques/2d_collision_detection/index.md b/files/zh-cn/games/techniques/2d_collision_detection/index.md index b394ef4c07ef27..90812ca993ac69 100644 --- a/files/zh-cn/games/techniques/2d_collision_detection/index.md +++ b/files/zh-cn/games/techniques/2d_collision_detection/index.md @@ -3,80 +3,76 @@ title: 2D collision detection slug: Games/Techniques/2D_collision_detection translation_of: Games/Techniques/2D_collision_detection --- -
{{GamesSidebar}}
+{{GamesSidebar}} -
-

检测 2D 游戏中的碰撞算法,依赖于可碰撞物体的形状(例如:矩形与矩形,矩形与圆形,圆形与圆形)。通常情况下,你使用的的简单通用形状,会被称为“hitbox”的实体所覆盖,尽管发生的碰撞并不是像素完美契合的,它看起来也足够好,而且可跨多个实体执行碰撞。本文提供了一系列较为通用的 2D 游戏中碰撞侦测技术。

-
+检测 2D 游戏中的碰撞算法,依赖于可碰撞物体的形状(例如:矩形与矩形,矩形与圆形,圆形与圆形)。通常情况下,你使用的的简单通用形状,会被称为“hitbox”的实体所覆盖,尽管发生的碰撞并不是像素完美契合的,它看起来也足够好,而且可跨多个实体执行碰撞。本文提供了一系列较为通用的 2D 游戏中碰撞侦测技术。 -

Axis-Aligned Bounding Box

+## Axis-Aligned Bounding Box -

碰撞侦测其中一种简单的形式是,在两个轴对齐的矩形之间碰撞 — 这意味着没有旋转。这个算法是确定两个矩形任意 4 边之间不再有间隔,存在间隔代表没有发生碰撞。

+碰撞侦测其中一种简单的形式是,在两个轴对齐的矩形之间碰撞 — 这意味着没有旋转。这个算法是确定两个矩形任意 4 边之间不再有间隔,存在间隔代表没有发生碰撞。 -
var rect1 = {x: 5, y: 5, width: 50, height: 50}
+```js
+var rect1 = {x: 5, y: 5, width: 50, height: 50}
 var rect2 = {x: 20, y: 10, width: 10, height: 10}
 
-if (rect1.x < rect2.x + rect2.width &&
-   rect1.x + rect1.width > rect2.x &&
-   rect1.y < rect2.y + rect2.height &&
-   rect1.height + rect1.y > rect2.y) {
+if (rect1.x < rect2.x + rect2.width &&
+   rect1.x + rect1.width > rect2.x &&
+   rect1.y < rect2.y + rect2.height &&
+   rect1.height + rect1.y > rect2.y) {
     // collision detected!
 }
 
-// filling in the values =>
+// filling in the values =>
 
-if (5 < 30 &&
-    55 > 20 &&
-    5 < 20 &&
-    55 > 10) {
+if (5 < 30 &&
+    55 > 20 &&
+    5 < 20 &&
+    55 > 10) {
     // collision detected!
-}
+} +``` -
-

备注: You can see a live example of Axis-Aligned Bounding Box collision detection on jsFiddle, to illustrate how this code would work in practice. Here is another example without Canvas or external libraries.

-
+> **备注:** You can see a [live example of Axis-Aligned Bounding Box collision detection](http://jsfiddle.net/knam8/) on jsFiddle, to illustrate how this code would work in practice. [Here is another example without Canvas or external libraries](https://jsfiddle.net/jlr7245/217jrozd/3/). -

圆形碰撞

+## 圆形碰撞 -

碰撞测试的另一种形状是两个圆形间的碰撞,该算法是通过获取两个圆心点,并确定圆心距离小于两个圆形的半径和实现的。

+碰撞测试的另一种形状是两个圆形间的碰撞,该算法是通过获取两个圆心点,并确定圆心距离小于两个圆形的半径和实现的。 -
var circle1 = {radius: 20, x: 5, y: 5};
+```js
+var circle1 = {radius: 20, x: 5, y: 5};
 var circle2 = {radius: 12, x: 10, y: 5};
 
 var dx = circle1.x - circle2.x;
 var dy = circle1.y - circle2.y;
 var distance = Math.sqrt(dx * dx + dy * dy);
 
-if (distance < circle1.radius + circle2.radius) {
+if (distance < circle1.radius + circle2.radius) {
     // collision detected!
-}
+} +``` -
-

备注: You can see a live example of Circle collision detection on jsFiddle, to illustrate how this code would work in practice.

-
+> **备注:** You can see a [live example of Circle collision detection](http://jsfiddle.net/gQ3hD/2/) on jsFiddle, to illustrate how this code would work in practice. -

Separating Axis Theorem

+## Separating Axis Theorem -

This is a collision algorithm that can detect a collision between any two *convex* polygons. It's more complicated to implement than the above methods but is more powerful. The complexity of an algorithm like this means we will need to consider performance optimization, covered in the next section.

+This is a collision algorithm that can detect a collision between any two \*convex\* polygons. It's more complicated to implement than the above methods but is more powerful. The complexity of an algorithm like this means we will need to consider performance optimization, covered in the next section. -

Implementing SAT is out of scope for this page so see the recommended tutorials below:

+Implementing SAT is out of scope for this page so see the recommended tutorials below: -
    -
  1. Separating Axis Theorem (SAT) explanation
  2. -
  3. Collision detection and response
  4. -
  5. Collision detection Using the Separating Axis Theorem
  6. -
  7. SAT (Separating Axis Theorem)
  8. -
  9. Separation of Axis Theorem (SAT) for Collision Detection
  10. -
+1. [Separating Axis Theorem (SAT) explanation](http://www.sevenson.com.au/actionscript/sat/) +2. [Collision detection and response](http://www.metanetsoftware.com/technique/tutorialA.html) +3. [Collision detection Using the Separating Axis Theorem](http://gamedevelopment.tutsplus.com/tutorials/collision-detection-using-the-separating-axis-theorem--gamedev-169) +4. [SAT (Separating Axis Theorem)](http://www.codezealot.org/archives/55) +5. [Separation of Axis Theorem (SAT) for Collision Detection](http://rocketmandevelopment.com/blog/separation-of-axis-theorem-for-collision-detection/) -

Collision Performance

+## Collision Performance -

While some of these algorithms for collision detection are simple enough to calculate, it can be a waste of cycles to test *every* entity with every other entity. Usually games will split collision into two phases, broad and narrow.

+While some of these algorithms for collision detection are simple enough to calculate, it can be a waste of cycles to test \*every\* entity with every other entity. Usually games will split collision into two phases, broad and narrow. -

Broad Phase

+### Broad Phase -

Broad phase should give you a list of entities that *could* be colliding. This can be implemented with a spacial data structure that will give you a rough idea of where the entity exists and what exist around it. Some examples of spacial data structures are Quad Trees, R-Trees or a Spacial Hashmap.

+Broad phase should give you a list of entities that \*could\* be colliding. This can be implemented with a spacial data structure that will give you a rough idea of where the entity exists and what exist around it. Some examples of spacial data structures are Quad Trees, R-Trees or a Spacial Hashmap. -

Narrow Phase

+### Narrow Phase -

When you have a small list of entities to check you will want to use a narrow phase algorithm (like the ones listed above) to provide a certain answer as to whether there is a collision or not.

+When you have a small list of entities to check you will want to use a narrow phase algorithm (like the ones listed above) to provide a certain answer as to whether there is a collision or not. diff --git a/files/zh-cn/games/techniques/3d_collision_detection/index.md b/files/zh-cn/games/techniques/3d_collision_detection/index.md index a442e2f1f87727..b98476c2354ed5 100644 --- a/files/zh-cn/games/techniques/3d_collision_detection/index.md +++ b/files/zh-cn/games/techniques/3d_collision_detection/index.md @@ -3,118 +3,120 @@ title: 3D 碰撞检测 slug: Games/Techniques/3D_collision_detection translation_of: Games/Techniques/3D_collision_detection --- -
{{GamesSidebar}}

本文介绍了用于在 3D 环境中实现不同边界体积碰撞检测的技术。 后续文章将讨论特定 3D 库中的实现。

+{{GamesSidebar}} -

Axis-aligned bounding boxes(AABB 包围盒

+本文介绍了用于在 3D 环境中实现不同边界体积碰撞检测的技术。 后续文章将讨论特定 3D 库中的实现。 -

+## Axis-aligned bounding boxes(**AABB 包围盒**) -

在游戏中,为了简化物体之间的碰撞检测运算,通常会对物体创建一个规则的几何外形将其包围。其中,AABB(axis-aligned bounding box)包围盒被称为轴对齐包围盒。

+在游戏中,为了简化物体之间的碰撞检测运算,通常会对物体创建一个规则的几何外形将其包围。其中,AABB(axis-aligned bounding box)包围盒被称为轴对齐包围盒。 -

与 2D 碰撞检测一样,轴对齐包围盒是判断两个物体是否重叠的最快算法,物体被包裹在一个非旋转的(因此轴对齐的)盒中,并检查这些盒在三维坐标空间中的位置,以确定它们是否重叠。

+与 2D 碰撞检测一样,轴对齐包围盒是判断两个物体是否重叠的最快算法,物体被包裹在一个非旋转的(因此轴对齐的)盒中,并检查这些盒在三维坐标空间中的位置,以确定它们是否重叠。 -

+![](screen_shot_2015-10-16_at_15.11.21.png) -

由于性能原因,轴对齐是有一些约束的。两个非旋转的盒子之间是否重叠可以通过逻辑比较进行检查,而旋转的盒子则需要三角运算,这会导致性能下降。如果你有旋转的物体,可以通过修改边框的尺寸,这样盒子仍可以包裹物体,或者选择使用另一种边界几何类型,比如球体 (球体旋转,形状不会变)。下图是一个 AABB 物体旋转,动态调节盒大小适应物体的例子。

+由于性能原因,轴对齐是有一些约束的。两个非旋转的盒子之间是否重叠可以通过逻辑比较进行检查,而旋转的盒子则需要三角运算,这会导致性能下降。如果你有旋转的物体,可以通过修改边框的尺寸,这样盒子仍可以包裹物体,或者选择使用另一种边界几何类型,比如球体 (球体旋转,形状不会变)。下图是一个 AABB 物体旋转,动态调节盒大小适应物体的例子。 -

+![](rotating_knot.gif) -
-

备注: 参考这里,使用 Three.js 进行边界体积碰撞检测。

-
+> **备注:** 参考[这里](/en-US/docs/Games/Techniques/3D_collision_detection/Bounding_volume_collision_detection_with_THREE.js),使用 Three.js 进行边界体积碰撞检测。 -

点与 AABB

+### 点与 AABB -

如果检测到一个点是否在 AABB 内部就非常简单了 — 我们只需要检查这个点的坐标是否在 AABB 内; 分别考虑到每种坐标轴。如果假设 Px, Py Pz 是点的坐标, BminXBmaxX, BminYBmaxY, 和 BminZBmaxZ 是 AABB 的每一个坐标轴的范围,我们可以使用以下公式计算两者之间的碰撞是否发生:

+如果检测到一个点是否在 AABB 内部就非常简单了 — 我们只需要检查这个点的坐标是否在 AABB 内; 分别考虑到每种坐标轴。如果假设 _Px_, _Py 和_ _Pz_ 是点的坐标, _BminX_–_BmaxX_, _BminY_–_BmaxY_, 和 _BminZ_–_BmaxZ_ 是 AABB 的每一个坐标轴的范围,我们可以使用以下公式计算两者之间的碰撞是否发生: -

f(P,B)=(Px>=BminXPx<=BmaxX)(Py>=BminYPy<=BmaxY)(Pz>=BminZPz<=BmaxZ)f(P,B)= (P_x >= B_{minX} \wedge P_x <= B_{maxX}) \wedge (P_y >= B_{minY} \wedge P_y <= B_{maxY}) \wedge (P_z >= B_{minZ} \wedge P_z <= B_{maxZ})

+f(P,B)=(Px>=BminXPx<=BmaxX)(Py>=BminYPy<=BmaxY)(Pz>=BminZPz<=BmaxZ)f(P,B)= (P*x >= B*{minX} \wedge P*x <= B*{maxX}) \wedge (P*y >= B*{minY} \wedge P*y <= B*{maxY}) \wedge (P*z >= B*{minZ} \wedge P*z <= B*{maxZ}) -

或者用 JavaScript:

+或者用 JavaScript: -
function isPointInsideAABB(point, box) {
-  return (point.x >= box.minX && point.x <= box.maxX) &&
-         (point.y >= box.minY && point.y <= box.maxY) &&
-         (point.z >= box.minY && point.z <= box.maxZ);
-}
+```js +function isPointInsideAABB(point, box) { + return (point.x >= box.minX && point.x <= box.maxX) && + (point.y >= box.minY && point.y <= box.maxY) && + (point.z >= box.minY && point.z <= box.maxZ); +} +``` -

AABB 与 AABB

+### AABB 与 AABB -

检查一个 AABB 是否和另一个 AABB 相交类似于检测两个点一样。我们只需要基于每一条坐标轴并利用盒子的边缘去检测。下图显示了我们基于 X 轴的检测 — 当然, AminXAmaxXBminXBmaxX 会不会重叠?

+检查一个 AABB 是否和另一个 AABB 相交类似于检测两个点一样。我们只需要基于每一条坐标轴并利用盒子的边缘去检测。下图显示了我们基于 X 轴的检测 — 当然, _AminX_–_AmaxX_ 和 _BminX_–_BmaxX_ 会不会重叠? -

updated version

+![updated version](aabb_test.png) -

在数学上的表示就像这样:

+在数学上的表示就像这样: -

f(A,B)=(AminX<=BmaxXAmaxX>=BminX)(AminY<=BmaxYAmaxY>=BminY)(AminZ<=BmaxZAmaxZ>=BminZ)f(A,B) =

+f(A,B)=(AminX<=BmaxXAmaxX>=BminX)(AminY<=BmaxYAmaxY>=BminY)(AminZ<=BmaxZAmaxZ>=BminZ)f(A,B) = -

在 JavaScript 我们可以这样:

+在 JavaScript 我们可以这样: -
function intersect(a, b) {
-  return (a.minX <= b.maxX && a.maxX >= b.minX) &&
-         (a.minY <= b.maxY && a.maxY >= b.minY) &&
-         (a.minZ <= b.maxZ && a.maxZ >= b.minZ);
+```js
+function intersect(a, b) {
+  return (a.minX <= b.maxX && a.maxX >= b.minX) &&
+         (a.minY <= b.maxY && a.maxY >= b.minY) &&
+         (a.minZ <= b.maxZ && a.maxZ >= b.minZ);
 }
-
+``` -

球体碰撞

+## 球体碰撞 -

球体碰撞边缘检测比 AABB 盒子稍微复杂一点,但他的检测仍相当容易的。球体的主要优势是他们不变的旋转,如果包装实体旋转,边界领域仍将是相同的。他们的主要缺点是,除非他们包装的实体实际上是球形,包装的实体通常不是一个完美的球形 (比如用这样的球形包装一个人将导致一些错误,而 AABB 盒子将更合适)。

+球体碰撞边缘检测比 AABB 盒子稍微复杂一点,但他的检测仍相当容易的。球体的主要优势是他们不变的旋转,如果包装实体旋转,边界领域仍将是相同的。他们的主要缺点是,除非他们包装的实体实际上是球形,包装的实体通常不是一个完美的球形 (比如用这样的球形包装一个人将导致一些错误,而 AABB 盒子将更合适)。 -

点与球

+### 点与球 -

检查是否一个球体包含一个点,我们需要计算点和球体的中心之间的距离。如果这个距离小于或等于球的半径,这个点就在里面。

+检查是否一个球体包含一个点,我们需要计算点和球体的中心之间的距离。如果这个距离小于或等于球的半径,这个点就在里面。 -

+![](point_vs_sphere.png) -

两个点 A 和 B 之间的欧氏距离是
- (Ax-Bx)2)+(Ay-By)2+(Az-Bz)\sqrt{(A_x - B_x) ^ 2) + (A_y - B_y)^2 + (A_z - B_z)} ,我们的公式指出,球体碰撞检测是:

+两个点 A 和 B 之间的欧氏距离是 (Ax-Bx)2)+(Ay-By)2+(Az-Bz)\sqrt{(A_x - B_x) ^ 2) + (A_y - B_y)^2 + (A_z - B_z)} ,我们的公式指出,球体碰撞检测是: -

f(P,S)=Sradius>=(Px-Sx)2+(Py-Sy)2+(Pz-Sz)2f(P,S) = S_{radius} >= \sqrt{(P_x - S_x)^2 + (P_y - S_y)^2 + (P_z - S_z)^2}

+f(P,S)=Sradius>=(Px-Sx)2+(Py-Sy)2+(Pz-Sz)2f(P,S) = S\_{radius} >= \sqrt{(P_x - S_x)^2 + (P_y - S_y)^2 + (P_z - S_z)^2} -

或者用 JavaScript:

+或者用 JavaScript: -
function isPointInsideSphere(point, sphere) {
+```js
+function isPointInsideSphere(point, sphere) {
   // we are using multiplications because is faster than calling Math.pow
   var distance = Math.sqrt((point.x - sphere.x) * (point.x - sphere.x) +
                            (point.y - sphere.y) * (point.y - sphere.y) +
                            (point.z - sphere.z) * (point.z - sphere.z));
-  return distance < sphere.radius;
+  return distance < sphere.radius;
 }
-
+``` -
-

备注: 上面的代码有一个平方根,是一个开销昂贵的计算。一个简单的优化,以避免它由半径平方,所以优化方程不涉及distance < sphere.radius * sphere.radius.

-
+> **备注:** 上面的代码有一个平方根,是一个开销昂贵的计算。一个简单的优化,以避免它由半径平方,所以优化方程不涉及`distance < sphere.radius * sphere.radius`. -

球体与球体

+### 球体与球体 -

球体与球体的距离类似于点和球体。我们需要测试是球体的中心之间的距离小于或等于半径的总和。

+球体与球体的距离类似于点和球体。我们需要测试是球体的中心之间的距离小于或等于半径的总和。 -

+![](sphere_vs_sphere.png) -

在数学上,像这样:

+在数学上,像这样: -

f(A,B)=(Ax-Bx)2+(Ay-By)2+(Az-Bz)2<=Aradius+Bradiusf(A,B) = \sqrt{(A_x - B_x)^2 + (A_y - B_y)^2 + (A_z - B_z)^2} <= A_{radius} + B_{radius}

+f(A,B)=(Ax-Bx)2+(Ay-By)2+(Az-Bz)2<=Aradius+Bradiusf(A,B) = \sqrt{(A*x - B_x)^2 + (A_y - B_y)^2 + (A_z - B_z)^2} <= A*{radius} + B\_{radius} -

或者 JavaScript:

+或者 JavaScript: -
function intersect(sphere, other) {
+```js
+function intersect(sphere, other) {
   // we are using multiplications because it's faster than calling Math.pow
   var distance = Math.sqrt((sphere.x - other.x) * (sphere.x - other.x) +
                            (sphere.y - other.y) * (sphere.y - other.y) +
                            (sphere.z - other.z) * (sphere.z - other.z));
-  return distance < (sphere.radius + other.radius); }
-}
+ return distance < (sphere.radius + other.radius); } +} +``` -

球体与 AABB

+### 球体与 AABB -

测试一个球和一个 AABB 的碰撞是稍微复杂,但过程仍然简单和快速。一个合乎逻辑的方法是,检查 AABB 每个顶点,计算每一个点与球的距离。然而这是大材小用了,测试所有的顶点都是不必要的,因为我们可以侥幸计算 AABB 最近的点 (不一定是一个顶点) 和球体的中心之间的距离,看看它是小于或等于球体的半径。我们可以通过逼近球体的中心和 AABB 的距离得到这个值。

+测试一个球和一个 AABB 的碰撞是稍微复杂,但过程仍然简单和快速。一个合乎逻辑的方法是,检查 AABB 每个顶点,计算每一个点与球的距离。然而这是大材小用了,测试所有的顶点都是不必要的,因为我们可以侥幸计算 AABB 最近的点 (不一定是一个顶点) 和球体的中心之间的距离,看看它是小于或等于球体的半径。我们可以通过逼近球体的中心和 AABB 的距离得到这个值。 -

+![](sphere_vs_aabb.png) -

在 JavaScript, 我们可以像这样子做:

+在 JavaScript, 我们可以像这样子做: -
function intersect(sphere, box) {
+```js
+function intersect(sphere, box) {
   // get box closest point to sphere center by clamping
   var x = Math.max(box.minX, Math.min(sphere.x, box.maxX));
   var y = Math.max(box.minY, Math.min(sphere.y, box.maxY));
@@ -125,29 +127,24 @@ translation_of: Games/Techniques/3D_collision_detection
                            (y - sphere.y) * (y - sphere.y) +
                            (z - sphere.z) * (z - sphere.z));
 
-  return distance < sphere.radius;
+  return distance < sphere.radius;
 }
+```
 
-
- -

使用一个物理引擎

+## 使用一个物理引擎 -

3D physics engines provide collision detection algorithms, most of them based on bounding volumes as well. The way a physics engine works is by creating a physical body, usually attached to a visual representation of it. This body has properties such as velocity, position, rotation, torque, etc., and also a physical shape. This shape is the one that is considered in the collision detection calculations.

+**3D physics engines** provide collision detection algorithms, most of them based on bounding volumes as well. The way a physics engine works is by creating a **physical body**, usually attached to a visual representation of it. This body has properties such as velocity, position, rotation, torque, etc., and also a **physical shape**. This shape is the one that is considered in the collision detection calculations. -

We have prepared a live collision detection demo (with source code) that you can take a look at to see such techniques in action — this uses the open-source 3D physics engine cannon.js.

+We have prepared a [live collision detection demo](http://mozdevs.github.io/gamedev-js-3d-aabb/physics.html) (with [source code](https://github.com/mozdevs/gamedev-js-3d-aabb)) that you can take a look at to see such techniques in action — this uses the open-source 3D physics engine [cannon.js](https://github.com/schteppe/cannon.js). -

See also

+## See also -

Related articles on MDN:

+Related articles on MDN: - +- [Bounding volumes collision detection with Three.js](/en-US/docs/Games/Techniques/3D_collision_detection/Bounding_volume_collision_detection_with_THREE.js) +- [2D collision detection](/en-US/docs/Games/Techniques/2D_collision_detection) -

External resources:

+External resources: - +- [Simple intersection tests for games](http://www.gamasutra.com/view/feature/3383/simple_intersection_tests_for_games.php) on Gamasutra +- [Bounding volume](https://en.wikipedia.org/wiki/Bounding_volume) on Wikipedia diff --git a/files/zh-cn/games/techniques/3d_on_the_web/basic_theory/index.md b/files/zh-cn/games/techniques/3d_on_the_web/basic_theory/index.md index 25c985dc81b44d..9761a9eb11e991 100644 --- a/files/zh-cn/games/techniques/3d_on_the_web/basic_theory/index.md +++ b/files/zh-cn/games/techniques/3d_on_the_web/basic_theory/index.md @@ -8,115 +8,107 @@ tags: - 顶点 translation_of: Games/Techniques/3D_on_the_web/Basic_theory --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

这篇文章解释了当你开始使用 3D 工作的时候需要的所有有用的基本理论

+这篇文章解释了当你开始使用 3D 工作的时候需要的所有有用的基本理论 -

坐标系统

+## 坐标系统 -

3D 指的是有关在 3D 空间中所有形状的表示,并且可以使用坐标系统来计算其位置。

+3D 指的是有关在 3D 空间中所有形状的表示,并且可以使用坐标系统来计算其位置。 -

Coordinate system

+![Coordinate system](mdn-games-3d-coordinate-system.png) -

WebGL 使用右手坐标系统 — x 轴向右,y 轴向上 z 轴指向屏幕外,在上图可以看到。

+WebGL 使用右手坐标系统 — `x` 轴向右,`y` 轴向上 `z` 轴指向屏幕外,在上图可以看到。 -

物体

+## 物体 -

使用顶点建立不同类型的物体。 一个顶点是在 3D 坐标系中拥有坐标位置的一个点以及一些额外可以定义它的信息。 每个点都包含这些属性:

+使用顶点建立不同类型的物体。 **一个顶点**是在 3D 坐标系中拥有坐标位置的一个点以及一些额外可以定义它的信息。 每个点都包含这些属性: -
    -
  • 位置: 在 3D 空间用来辨认 (x, y, z).
  • -
  • 颜色: 包含 RGBA (R, G 和 B 分别是红,绿,蓝和 alpha 通道,alpha 通道控制透明度 — 所有通道值的范围都是 0.01.0).
  • -
  • 法线: 描述顶点朝向。
  • -
  • 纹理: 顶点用来装饰模型表面的一张 2D 图片,它是代替简单颜色的选择之一。
  • -
+- **位置**: 在 3D 空间用来辨认 (`x`, `y`, `z`). +- **颜色**: 包含 RGBA (R, G 和 B 分别是红,绿,蓝和 alpha 通道,alpha 通道控制透明度 — 所有通道值的范围都是 `0.0` 到 `1.0`). +- **法线:** 描述顶点朝向。 +- **纹理**: 顶点用来装饰模型表面的一张 2D 图片,它是代替简单颜色的选择之一。 -

你可以使用这些信息建立几何体 — 这是一个立方体的例子:

+你可以使用这些信息建立几何体 — 这是一个立方体的例子: -

Cube

+![Cube](mdn-games-3d-cube.png) -

给定形状的一个面是顶点之间的一个平面。例如,一个立方体有 8 个不同的顶点和 6 个不同的面 每个面由 4 个顶点构成。一条法线定义面的朝向。同时,连接这些点可以创建立方体的边。这个几何体通过点和面构成,材质使用的是一张纹理贴图,这里使用一个纯蓝色或一张图片。该物体的几何形状 (geometry) 由顶点和面构成,而材质 (material) 则是由纹理构成。如果我们将几何体和材质连接起来会得到一个网格 (mesh).

+给定形状的一个面是顶点之间的一个平面。例如,一个立方体有 8 个不同的顶点和 6 个不同的面 每个面由 4 个顶点构成。一条法线定义面的朝向。同时,连接这些点可以创建立方体的边。这个几何体通过点和面构成,材质使用的是一张纹理贴图,这里使用一个纯蓝色或一张图片。该物体的几何形状 (geometry) 由顶点和面构成,而材质 (material) 则是由纹理构成。如果我们将几何体和材质连接起来会得到一个网格 (mesh). -

渲染流程

+## 渲染流程 -

渲染流程是个将之前准备好的模型输出到屏幕的过程。3D 渲染流程会接受使用顶点描述 3D 物体的原始数据作为输入用于处理,并计算其片段 (fragment), 然后渲染为像素 (pixels) 输出到屏幕。

+渲染流程是个将之前准备好的模型输出到屏幕的过程。3D 渲染流程会接受使用顶点描述 3D 物体的原始数据作为输入用于处理,并计算其片段 (fragment), 然后渲染为像素 (pixels) 输出到屏幕。 -

Rendering pipeline

+![Rendering pipeline](mdn-games-3d-rendering-pipeline.png) -

上图中用到了如下术语:

+上图中用到了如下术语: -
    -
  • 原始数据: 渲染流程中的输入 — 用顶点生成,它可能是三角形,点或线。
  • -
  • 片段: 一个像素的 3D 投射,有着和像素一样的属性。
  • -
  • 像素: 屏幕上的 2D 网格中的点布置的点,包含 RGBA.
  • -
+- **原始数据**: 渲染流程中的输入 — 用顶点生成,它可能是三角形,点或线。 +- **片段**: 一个像素的 3D 投射,有着和像素一样的属性。 +- **像素**: 屏幕上的 2D 网格中的点布置的点,包含 RGBA. -

顶点和片段处理是可编程的 — 你可以编写自己的着色器 来控制输出。

+顶点和片段处理是可编程的 — 你可以[编写自己的着色器](/zh-CN/docs/Games/Techniques/3D_on_the_web/GLSL_Shaders) 来控制输出。 -

顶点处理

+## 顶点处理 -

顶点处理是将独立的顶点信息组合成原始数据并设置其在 3D 空间中的坐标,方便显示器识别。就像是对你准备的场景进行拍照 — 你必须先放置物品,设置相机参数,然后开拍。

+顶点处理是将独立的顶点信息组合成原始数据并设置其在 3D 空间中的坐标,方便显示器识别。就像是对你准备的场景进行拍照 — 你必须先放置物品,设置相机参数,然后开拍。 -

Vertex processing

+![Vertex processing](mdn-games-3d-vertex-processing.png) -

这个过程分为四步:第一步是筹备世界坐标中的物体,也被称为模型转换 (model transformation). 然后是视图转换 (view transformation) , 这一步只关心位置和 3D 空间中摄像机的朝向设置。摄像机有三个参数 (位置,方向和朝向), 在新创建的场景中必须定义这三个参数。

+这个过程分为四步:第一步是筹备世界坐标中的物体,也被称为**模型转换 (model transformation)**. 然后是**视图转换 (view transformation)** , 这一步只关心位置和 3D 空间中摄像机的朝向设置。摄像机有三个参数 (位置,方向和朝向), 在新创建的场景中必须定义这三个参数。 -

Camera

+![Camera](mdn-games-3d-camera.png) -

投射转换(projection transformation), 也被称作透视转换 (perspective transformation), 这一步定义摄像机设置,在此过程会设置哪些在摄像机中可见,配置包含视野 (field of view), 宽高比例 (aspect ratio) 和可选的近裁剪和远裁剪参数。阅读 Three.js 文章摄像机了解更多。

+**投射转换**(projection transformation), 也被称作透视转换 (perspective transformation), 这一步定义摄像机设置,在此过程会设置哪些在摄像机中可见,配置包含视野 (field of view), 宽高比例 (aspect ratio) 和可选的近裁剪和远裁剪参数。阅读 Three.js 文章[摄像机](/en-US/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_Three.js#Camera)了解更多。 -

Camera settings

+![Camera settings](mdn-games-3d-camera-settings.png) -

最后一步是视图窗口转换(viewport transformation), 这一步会将一切都输出给渲染流程中的下一步。

+最后一步是**视图窗口转换**(viewport transformation), 这一步会将一切都输出给渲染流程中的下一步。 -

栅格化

+## 栅格化 -

栅格化将原始数据 (从顶点信息转换过来的) 转换为一系列的片段。

+栅格化将原始数据 (从顶点信息转换过来的) 转换为一系列的片段。 -

Rasterization

+![Rasterization](mdn-games-3d-rasterization.png) -

那些片段 (2D 像素的 3D 投射) 是对应到像素网格的,所以在渲染合成阶段最后他们会被 2D 的屏幕直接打印到像素点上。

+那些片段 (2D 像素的 3D 投射) 是对应到像素网格的,所以在渲染合成阶段最后他们会被 2D 的屏幕直接打印到像素点上。 -

片段合成

+## 片段合成 -

片段合成关注关注的是纹理和光照 — 它会基于给定参数计算最终的颜色。

+片段合成关注关注的是纹理和光照 — 它会基于给定参数计算最终的颜色。 -

Fragment processing

+![Fragment processing](mdn-games-3d-fragment-processing.png) -

纹理

+### 纹理 -

纹理是在 3D 空间中用了是模型看起来更加真实的 2D 图片。纹理是由称为纹素的单个纹理元素组合,和像素组合的原理一样。如果必要的话,在渲染流程中的片段处理阶段添加纹理到模型上允许我们使用包装 (wrapping) 和过滤 (filtering) 进行适配。

+纹理是在 3D 空间中用了是模型看起来更加真实的 2D 图片。纹理是由称为纹素的单个纹理元素组合,和像素组合的原理一样。如果必要的话,在渲染流程中的片段处理阶段添加纹理到模型上允许我们使用包装 (wrapping) 和过滤 (filtering) 进行适配。 -

纹理包装允许你在 3D 模型上重复使用 2D 图片。纹理过滤是纹理贴图的原始分辨率和将要呈现的片段的分辨率不同的时候,会根据情况对纹理进行缩放。

+纹理包装允许你在 3D 模型上重复使用 2D 图片。纹理过滤是纹理贴图的原始分辨率和将要呈现的片段的分辨率不同的时候,会根据情况对纹理进行缩放。 -

光照

+### 光照 -

我们在屏幕上看到的颜色是光照和模型颜色,材质进行交互之后的最终结果。灯光会被吸收和反射,在 WebGL 中实现的标准Phong 光照模型 有一下四种光照参数:

+我们在屏幕上看到的颜色是光照和模型颜色,材质进行交互之后的最终结果。灯光会被吸收和反射,在 WebGL 中实现的标准**Phong 光照模型** 有一下四种光照参数: -
    -
  • 漫反射: 遥远的直接光照,就像太阳。
  • -
  • 高光: 点光源,就像房间的白炽灯或闪光灯。
  • -
  • 环境色: 常量灯光,可影响场景中的所有模型。
  • -
  • 自发光: 模型自身发出的光。
  • -
+- **漫反射**: 遥远的直接光照,就像太阳。 +- **高光**: 点光源,就像房间的白炽灯或闪光灯。 +- **环境色**: 常量灯光,可影响场景中的所有模型。 +- **自发光**: 模型自身发出的光。 -

输出合成

+## 输出合成 -

在输出操作阶段所有来自 3D 空间的原始数据的片段会被转换到 2D 像素网格中,然后打印到屏幕像素上。

+在输出操作阶段所有来自 3D 空间的原始数据的片段会被转换到 2D 像素网格中,然后打印到屏幕像素上。 -

Output merging

+![Output merging](mdn-games-3d-output-merging.png) -

在输出合成阶段同样可以忽略不必要的信息,例如在屏幕外的模型参数或者被其他模型遮挡的模型,因为是不可见的所以不会被计算。

+在输出合成阶段同样可以忽略不必要的信息,例如在屏幕外的模型参数或者被其他模型遮挡的模型,因为是不可见的所以不会被计算。 -

总结

+## 总结 -

现在你知道了 3D 操作背后的基本原理。如果你想去练习或者看学习 demo, 看看下面的教程:

+现在你知道了 3D 操作背后的基本原理。如果你想去练习或者看学习 demo, 看看下面的教程: - +- [用 Three.js 创建基本 demo](/en-US/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_Three.js) +- [用 Babylon.js 创建基本 demo](/en-US/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_Babylon.js) +- [用 PlayCanvas 创建基本 demo](/en-US/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_PlayCanvas) +- [用 A-Frame 创建基本 demo](/en-US/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_A-Frame) -

继续,去创建一些炫酷 3D 实验吧!

+继续,去创建一些炫酷 3D 实验吧! diff --git a/files/zh-cn/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_three.js/index.md b/files/zh-cn/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_three.js/index.md index 5e2d847f1a3c26..32716d1ba99a43 100644 --- a/files/zh-cn/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_three.js/index.md +++ b/files/zh-cn/games/techniques/3d_on_the_web/building_up_a_basic_demo_with_three.js/index.md @@ -3,256 +3,268 @@ title: Building up a basic demo with Three.js slug: Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_Three.js translation_of: Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_Three.js --- -
{{GamesSidebar}}

游戏中一个典型的 3D 场景 (最简单的那种) 包含标准的物品比如在坐标轴中的形状,一个实际可看到他们的摄像机,灯光和材质让其看起来不错,动画使其生动等等。 Three.js, 和其他 3D 库一样,提供内置的 helper 函数来帮助你尽可能快地实现通用的 3D 功能 . 在这篇文章我们会带你了解使用 Three 的基本知识,包含设置开发者环境,必要的 HTML 结构,Three.js 对象基础,以及如何创建一个基本的 demo.

+{{GamesSidebar}} -
-

备注: 我们选择 Three.js 因为它是最流行的WebGL 库之一,并且很容易上手。我们不会介绍任何其他更好的 WebGL 库,你可以自由选择其他库做尝试,比如 CopperLicht, GLGE, OSG.js, O3D, 或者其他你喜欢的库。

-
+游戏中一个典型的 3D 场景 (最简单的那种) 包含标准的物品比如在坐标轴中的形状,一个实际可看到他们的摄像机,灯光和材质让其看起来不错,动画使其生动等等。 **Three.js**, 和其他 3D 库一样,提供内置的 helper 函数来帮助你尽可能快地实现通用的 3D 功能 . 在这篇文章我们会带你了解使用 Three 的基本知识,包含设置开发者环境,必要的 HTML 结构,Three.js 对象基础,以及如何创建一个基本的 demo. -

环境设置

+> **备注:** 我们选择 Three.js 因为它是最流行的[WebGL](/en-US/docs/Web/API/WebGL_API) 库之一,并且很容易上手。我们不会介绍任何其他更好的 WebGL 库,你可以自由选择其他库做尝试,比如 [CopperLicht](http://www.ambiera.com/copperlicht/index.html), [GLGE](http://www.glge.org/), [OSG.js](http://osgjs.org/), [O3D](https://code.google.com/p/o3d/), 或者其他你喜欢的库。 -

开始用 Three.js, 你不需要准备太多,只需:

+## 环境设置 -
    -
  • 确保使用的支持 WebGL 的现代浏览器,例如最新版的 Firefox 或 Chrome.
  • -
  • 创建一个目录保存例子。
  • -
  • 复制最新的压缩版 Three.js 到你的目录。
  • -
  • 用单独的浏览器 tab 打开 Three.js 文档 — 对应参考很有用。
  • -
+开始用 Three.js, 你不需要准备太多,只需: -

HTML 结构

+- 确保使用的支持 [WebGL](/en-US/docs/Web/API/WebGL_API) 的现代浏览器,例如最新版的 Firefox 或 Chrome. +- 创建一个目录保存例子。 +- 复制最新的压缩版[ Three.js](http://threejs.org/build/three.min.js) 到你的目录。 +- 用单独的浏览器 tab 打开 [Three.js ](http://threejs.org/docs/)文档 — 对应参考很有用。 -

这是将用到的 HTML 结构。

+## HTML 结构 -
<!DOCTYPE html>
-<html>
-<head>
-	<meta charset="utf-8">
-	<title>MDN Games: Three.js demo</title>
-	<style>
+这是将用到的 HTML 结构。
+
+```html
+
+
+
+	
+	MDN Games: Three.js demo
+	
+
+
+
+
+
+
+```
 
-

It contains some basic information like the document {{htmlelement("title")}}, and some CSS to set the width and height of the {{htmlelement("canvas")}} element that Three.js will insert on the page to 100% so that it will fill the entire available viewport space. The first {{htmlelement("script")}} element includes the Three.js library in the page, and we will write our example code into the second one. There are two helper variables already included, which store the window's width and height.

+It contains some basic information like the document {{htmlelement("title")}}, and some CSS to set the `width` and `height` of the {{htmlelement("canvas")}} element that Three.js will insert on the page to 100% so that it will fill the entire available viewport space. The first {{htmlelement("script")}} element includes the Three.js library in the page, and we will write our example code into the second one. There are two helper variables already included, which store the window's `width` and `height`. -

Before reading on, copy this code to a new text file, and save it in your working directory as index.html.

+Before reading on, copy this code to a new text file, and save it in your working directory as `index.html`. -

渲染器

+## 渲染器 -

A renderer is a tool that displays scenes right in your browser. There are a few different renderers: WebGL is the default one, and the others you can use are Canvas, SVG, CSS and DOM. They differ in a way everything is rendered, so the WebGL implementation will work differently than the CSS one, but the idea is to have it look exactly the same for the end user. Thanks to this approach, a fallback can be used if the primary technology is not supported by the browser.

+A renderer is a tool that displays scenes right in your browser. There are a few different renderers: WebGL is the default one, and the others you can use are Canvas, SVG, CSS and DOM. They differ in a way everything is rendered, so the WebGL implementation will work differently than the CSS one, but the idea is to have it look exactly the same for the end user. Thanks to this approach, a fallback can be used if the primary technology is not supported by the browser. -
var renderer = new THREE.WebGLRenderer({antialias:true});
+```js
+var renderer = new THREE.WebGLRenderer({antialias:true});
 renderer.setSize(WIDTH, HEIGHT);
 renderer.setClearColor(0xDDDDDD, 1);
 document.body.appendChild(renderer.domElement);
-
+``` -

We are creating a new WebGL renderer, setting it's size to fit the whole available space on the screen and appending the DOM structure to the page. You probably noticed the antialias parameter in the first line — this enables the edges of the shapes to be rendered a little more smoothly. The setClearColor() method sets our background to a light gray colour instead of the default black one.

+We are creating a new WebGL renderer, setting it's size to fit the whole available space on the screen and appending the DOM structure to the page. You probably noticed the `antialias` parameter in the first line — this enables the edges of the shapes to be rendered a little more smoothly. The `setClearColor()` method sets our background to a light gray colour instead of the default black one. -

Add this code into the second {{htmlelement("script")}} element, just below the JavaScript comment.

+Add this code into the second {{htmlelement("script")}} element, just below the JavaScript comment. -

场景

+## 场景 -

A scene is the place where everything happens. When creating new objects in the demo, we will be adding them all to the scene to make them visible on the screen. In three.js, the scene is reperesented by a Scene object. Let's create it, by adding the following line below our previous lines:

+A scene is the place where everything happens. When creating new objects in the demo, we will be adding them all to the scene to make them visible on the screen. In three.js, the scene is reperesented by a `Scene` object. Let's create it, by adding the following line below our previous lines: -
var scene = new THREE.Scene();
-
+```js +var scene = new THREE.Scene(); +``` -

Later on we will be using the .add() method to add objects to the scene.

+Later on we will be using the `.add()` method to add objects to the scene. -

摄像机

+## 摄像机 -

我们有渲染场景,但是我们仍然需要一个摄像机来观察场景 - 想象没有摄像机的电影场景。下面的代码将摄像机放在三维坐标系中,并将其指向我们的场景,这样人们就能看到一些东西:

+我们有渲染场景,但是我们仍然需要一个摄像机来观察场景 - 想象没有摄像机的电影场景。下面的代码将摄像机放在三维坐标系中,并将其指向我们的场景,这样人们就能看到一些东西: -
var camera = new THREE.PerspectiveCamera(70, WIDTH/HEIGHT);
+```js
+var camera = new THREE.PerspectiveCamera(70, WIDTH/HEIGHT);
 camera.position.z = 50;
 scene.add(camera);
-
+``` -

Add these lines to your code, below the prevous ones.

+Add these lines to your code, below the prevous ones. -

There are other types of camera available (Cube, Orthographic), but the simplest is the Perspective one. To initialize it we have to set its field of view and aspect ratio — the first one is used to set how much is seen, and a proper aspect ratio is important for the objects on the screen to have the right proportions when rendered and not look stretched. Let's explain the values we are setting in the code above:

+There are other types of camera available (Cube, Orthographic), but the simplest is the Perspective one. To initialize it we have to set its field of view and aspect ratio — the first one is used to set how much is seen, and a proper aspect ratio is important for the objects on the screen to have the right proportions when rendered and not look stretched. Let's explain the values we are setting in the code above: -
    -
  • The value we set for the field of view, 70, is something we can experiment with — the higher the value, the greater the amount of scene the camera will show. Imagine a normal camera view, versus a fish eye effect, which allows a lot more to be seen. The default value is 50.
  • -
  • The aspect ratio is set to the current width and height of the window so it will be dynamically adjusted. We could set a fixed ratio — for example 16 ⁄ 9, which is the aspect ratio of a widescreen TV. The default value is 1.
  • -
  • The z position with the value of 50 units is the distance between the camera and the center of the scene on the z axis — here we're moving the camera back so the objects on the scene can be viewed. 50 feels ok as it's not too near and not too far and the sizes of the objects allow them to stay on the scene within the given field of view. The x and y values, if not specified, will default to 0.
  • -
+- The value we set for the field of view, 70, is something we can experiment with — the higher the value, the greater the amount of scene the camera will show. Imagine a normal camera view, versus a fish eye effect, which allows a lot more to be seen. The default value is 50. +- The aspect ratio is set to the current width and height of the window so it will be dynamically adjusted. We could set a fixed ratio — for example 16 ⁄ 9, which is the aspect ratio of a widescreen TV. The default value is 1. +- The `z` position with the value of 50 units is the distance between the camera and the center of the scene on the `z` axis — here we're moving the camera back so the objects on the scene can be viewed. 50 feels ok as it's not too near and not too far and the sizes of the objects allow them to stay on the scene within the given field of view. The `x` and `y` values, if not specified, will default to 0. -

You should experiment with these values and see how they change what you see in the scene.

+You should experiment with these values and see how they change what you see in the scene. -
-

备注: The distance values (e.g. for the camera z position) are unitless, and can basically be anything you deem suitable for your scene — milimeters, meters, feet, or miles — it's up to you.

-
+> **备注:** The distance values (e.g. for the camera z position) are unitless, and can basically be anything you deem suitable for your scene — milimeters, meters, feet, or miles — it's up to you. -

Rendering the scene

+## Rendering the scene -

Everything is ready, but we still can't see anything. Although we set the renderer up, we still have to actually render everything. Our render() function will do this job, with a little help from requestAnimationFrame(), which causes the scene to be re-rendered constantly on every frame:

+Everything is ready, but we still can't see anything. Although we set the renderer up, we still have to actually render everything. Our `render()` function will do this job, with a little help from [`requestAnimationFrame()`](/en-US/docs/Web/API/window/requestAnimationFrame), which causes the scene to be re-rendered constantly on every frame: -
function render() {
+```js
+function render() {
 	requestAnimationFrame(render);
 	renderer.render(scene, camera);
 }
 render();
-
+``` -

On every new frame the render function is invoked and the renderer renders the scene and the camera. Right after the function declaration we're invoking it for the first time to start the loop, after which it will be used indefinitely.

+On every new frame the `render` function is invoked and the `renderer` renders the `scene` and the `camera`. Right after the function declaration we're invoking it for the first time to start the loop, after which it will be used indefinitely. -

Again add the new code below your previous additions, then try saving the file and loading it in your browser. You should now see a gray window. Congratulations!

+Again add the new code below your previous additions, then try saving the file and loading it in your browser. You should now see a gray window. Congratulations! -

Geometry

+## Geometry -

Now the scene is properly rendering we can start adding 3D shapes to it. To speed up development Three.js provides a bunch of predefined primitives that you can to create shapes instantly in a single line of code. There's cubes, spheres, cylinders and more complicated shapes available. Drawing the needed vertices and faces for given shape is taken care of by the framework, so we can focus on the high level coding. Let's start by defining the geometry for a cube shape — add the following just above the render() function:

+Now the scene is properly rendering we can start adding 3D shapes to it. To speed up development Three.js provides a bunch of predefined primitives that you can to create shapes instantly in a single line of code. There's cubes, spheres, cylinders and more complicated shapes available. Drawing the needed vertices and faces for given shape is taken care of by the framework, so we can focus on the high level coding. Let's start by defining the geometry for a cube shape — add the following just above the `render()` function: -
var boxGeometry = new THREE.BoxGeometry(10, 10, 10);
-
+```js +var boxGeometry = new THREE.BoxGeometry(10, 10, 10); +``` -

In this case we define a simple cube that is 10 x 10 x 10 units. The geometry itself is not enough though — we also need a material that will be used for our shape.

+In this case we define a simple cube that is 10 x 10 x 10 units. The geometry itself is not enough though — we also need a material that will be used for our shape. -

Material

+## Material -

Material is that thing covering the object — the colors or texture on its surface. In our case we will use a simple blue color to paint our box. There are predefined materials that can be used: Basic, Phong, Lambert. We will play with the last two later on, but for now the Basic one should be enough:

+Material is that thing covering the object — the colors or texture on its surface. In our case we will use a simple blue color to paint our box. There are predefined materials that can be used: Basic, Phong, Lambert. We will play with the last two later on, but for now the Basic one should be enough: -
var basicMaterial = new THREE.MeshBasicMaterial({color: 0x0095DD});
-
+```js +var basicMaterial = new THREE.MeshBasicMaterial({color: 0x0095DD}); +``` -

Add this line below the previous one.

+Add this line below the previous one. -

Our material is ready, but what to do next?

+Our material is ready, but what to do next? -

Mesh

+## Mesh -

To apply the material to a geometry a mesh is used. It takes a shape and adds the specified material to every face:

+To apply the material to a geometry a mesh is used. It takes a shape and adds the specified material to every face: -
var cube = new THREE.Mesh(boxGeometry, basicMaterial);
-
+```js +var cube = new THREE.Mesh(boxGeometry, basicMaterial); +``` -

Again, add this line below the previous one.

+Again, add this line below the previous one. -

Adding the cube to the scene

+## Adding the cube to the scene -

We've now created the actual cube using the geometry and material defined earlier. The last thing to do is to actually add the cube to our scene — add this line below the previous one:

+We've now created the actual cube using the geometry and material defined earlier. The last thing to do is to actually add the cube to our scene — add this line below the previous one: -
scene.add(cube);
-
+```js +scene.add(cube); +``` -

If you save and refresh now, your object will look like a square, because it's facing the camera. The good thing about objects is that we can move them on the scene however we want, for example rotating and scaling as we like. Let's apply a little bit of rotation to the cube, so we can see more than one face — again, add below the previous one:

+If you save and refresh now, your object will look like a square, because it's facing the camera. The good thing about objects is that we can move them on the scene however we want, for example rotating and scaling as we like. Let's apply a little bit of rotation to the cube, so we can see more than one face — again, add below the previous one: -
cube.rotation.set(0.4, 0.2, 0);
-
+```js +cube.rotation.set(0.4, 0.2, 0); +``` -

Congratulations, you've created your first object in a 3D environment! It was easier than you thought, right? Here's how it should look:

+Congratulations, you've created your first object in a 3D environment! It was easier than you thought, right? Here's how it should look: -

Blue cube on a gray background rendered with Three.js.

+![Blue cube on a gray background rendered with Three.js.](cube.png) -

And here's the code we have created so far:

+And here's the code we have created so far: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/bwup75fa/","","350")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/bwup75fa/","","350")}} -

You can also check it out on GitHub.

+You can also [check it out on GitHub](https://github.com/end3r/MDN-Games-3D/blob/gh-pages/Three.js/cube.html). -

More shapes and materials

+## More shapes and materials -

Now we will add more shapes to the scene and explore other shapes, materials, lighting, and more. Let's move the cube to the left to make space for some friends — add the following line just below the previous one:

+Now we will add more shapes to the scene and explore other shapes, materials, lighting, and more. Let's move the cube to the left to make space for some friends — add the following line just below the previous one: -
cube.position.x = -25;
-
+```js +cube.position.x = -25; +``` -

Now onto the shapes and materials: what would you say for a torus using the Phong material? Try adding the following lines just below the lines that define the cube.

+Now onto the shapes and materials: what would you say for a torus using the Phong material? Try adding the following lines just below the lines that define the cube. -
var torusGeometry = new THREE.TorusGeometry(7, 1, 6, 12);
+```js
+var torusGeometry = new THREE.TorusGeometry(7, 1, 6, 12);
 var phongMaterial = new THREE.MeshPhongMaterial({color: 0xFF9500});
 var torus = new THREE.Mesh(torusGeometry, phongMaterial);
 scene.add(torus);
-
+``` -

Thee lines will add a torus geometry; the TorusGeometry() method's parameters define and the parameters are radius, tube diameter, radial segment count and tubular segment count. The Phong material should look more glossy than the simple color of the box that was using the Basic material, although at the moment it will just look black.

+Thee lines will add a torus geometry; the `TorusGeometry()` method's parameters define and the parameters are `radius`, `tube diameter`, `radial segment count` and `tubular segment count`. The Phong material should look more glossy than the simple color of the box that was using the Basic material, although at the moment it will just look black. -

We can have even crazier predefined shapes; let's play some more — add the following lines below the ones that defined the torus:

+We can have even crazier predefined shapes; let's play some more — add the following lines below the ones that defined the torus: -
var dodecahedronGeometry = new THREE.DodecahedronGeometry(7);
+```js
+var dodecahedronGeometry = new THREE.DodecahedronGeometry(7);
 var lambertMaterial = new THREE.MeshLambertMaterial({color: 0xEAEFF2});
 var dodecahedron = new THREE.Mesh(dodecahedronGeometry, lambertMaterial);
 dodecahedron.position.x = 25;
 scene.add(dodecahedron);
-
+``` -

This time we are creating a dodecahedron, which is a shape containing twelve flat faces. The parameter DodecahedronGeometry() takes is the size of the object. We're using a Lambert material here, which is similar to Phong, but should be less glossy (again, black for now.) We're moving the object to the right, so it's not in the same place as the box or torus.

+This time we are creating a dodecahedron, which is a shape containing twelve flat faces. The parameter `DodecahedronGeometry()` takes is the size of the object. We're using a Lambert material here, which is similar to Phong, but should be less glossy (again, black for now.) We're moving the object to the right, so it's not in the same place as the box or torus. -

As mentioned above, the new objects currently just look black. To have both the Phong and Lambert materials properly visible we need a source of light.

+As mentioned above, the new objects currently just look black. To have both the Phong and Lambert materials properly visible we need a source of light. -

Lights

+## Lights -

There are various types of light sources available in Three.js; the most basic one is the PointLight, which works like a flashlight — shinig a spotlight in a given direction. Add the following below your shapre definitions:

+There are various types of light sources available in Three.js; the most basic one is the `PointLight`, which works like a flashlight — shinig a spotlight in a given direction. Add the following below your shapre definitions: -
var light = new THREE.PointLight(0xFFFFFF);
+```js
+var light = new THREE.PointLight(0xFFFFFF);
 light.position.set(-10, 15, 50);
 scene.add(light);
-
+``` -

We define a white point of light, set it's position a bit away from the center of the scene so it can light up some parts of the shapes, and add it to the scene. Now everything works as it should — all three shapes are visible. You should check the documentation for other types of light like Ambient, Directional, Hemisphere or Spot, and experiment with placing them on the scene to see the effects.

+We define a white point of light, set it's position a bit away from the center of the scene so it can light up some parts of the shapes, and add it to the scene. Now everything works as it should — all three shapes are visible. You should check the documentation for other types of light like Ambient, Directional, Hemisphere or Spot, and experiment with placing them on the scene to see the effects. -

Shapes: blue cube, dark yellow torus and dark gray dodecahedron on a gray background rendered with Three.js.

+![Shapes: blue cube, dark yellow torus and dark gray dodecahedron on a gray background rendered with Three.js.](shapes.png) -

This looks a little bit boring though. In a game something is usually happening — we can see animations and such — so let's try to breathe a little life into those shapes by animating them.

+This looks a little bit boring though. In a game something is usually happening — we can see animations and such — so let's try to breathe a little life into those shapes by animating them. -

Animation

+## Animation -

We already used rotation to adjust the position of the cube; we could also scale the shapes, or change thier positions. To show actual animation, we need to make changes to these values inside the render loop so, they are updated on every frame.

+We already used rotation to adjust the position of the cube; we could also scale the shapes, or change thier positions. To show actual animation, we need to make changes to these values inside the render loop so, they are updated on every frame. -

Rotation

+### Rotation -

Rotating is quite easy — all you need to do is to add a defined value to the given direction of the rotation on each frame. Add this line of code right after the requestAnimationFrame() invocation in the render function:

+Rotating is quite easy — all you need to do is to add a defined value to the given direction of the rotation on each frame. Add this line of code right after the `requestAnimationFrame()` invocation in the `render` function: -
cube.rotation.y += 0.01;
-
+```js +cube.rotation.y += 0.01; +``` -

It will rotate the cube on every frame by a tiny bit, so it will look like a smooth animation.

+It will rotate the cube on every frame by a tiny bit, so it will look like a smooth animation. -

Scaling

+### Scaling -

We can also scale a given object. By applying a constant value we could make it grow or shrink once, but let's make it more interesting. First, we will need a helper variable called t for counting the elapsed time. Add it right before the render() function:

+We can also scale a given object. By applying a constant value we could make it grow or shrink once, but let's make it more interesting. First, we will need a helper variable called `t` for counting the elapsed time. Add it right before the `render()` function: -
var t = 0;
-
+```js +var t = 0; +``` -

Now let's increase the value by a given constant value on each frame of the animation; add the following lines just below the requestAnimationFrame() invocation:

+Now let's increase the value by a given constant value on each frame of the animation; add the following lines just below the `requestAnimationFrame()` invocation: -
t += 0.01;
+```js
+t += 0.01;
 torus.scale.y = Math.abs(Math.sin(t));
-
+``` -

This way we'll be able to use Math.sin and end up with quite an interesting result: this will scale the torus and repeat the whole process, as sin is a periodic function. We're wrapping the scale value in Math.abs to pass the absolute values (greater or equal to 0), because sin is between -1 and 0, and for negative values the torus might render unexpectedly (in this case it looks black half the time.)

+This way we'll be able to use `Math.sin` and end up with quite an interesting result: this will scale the torus and repeat the whole process, as `sin` is a periodic function. We're wrapping the scale value in `Math.abs` to pass the absolute values (greater or equal to 0), because sin is between -1 and 0, and for negative values the torus might render unexpectedly (in this case it looks black half the time.) -

Now onto the movement part.

+Now onto the movement part. -

Moving

+### Moving -

Beside rotation and scaling we can also move objects around the scene. Add the following, again just below the requestAnimationFrame() invocation:

+Beside rotation and scaling we can also move objects around the scene. Add the following, again just below the `requestAnimationFrame()` invocation: -
dodecahedron.position.y = -7*Math.sin(t*2);
-
+```js +dodecahedron.position.y = -7*Math.sin(t*2); +``` -

This will move the dodecahedron up and down by applying the sin() value to the y axis on each frame, with a little bit of adjustment to make it look cooler. Try changing the values to see how it affects the animations.

+This will move the dodecahedron up and down by applying the `sin()` value to the y axis on each frame, with a little bit of adjustment to make it look cooler. Try changing the values to see how it affects the animations. -

Conclusion

+## Conclusion -

Here's the final piece of the code:

+Here's the final piece of the code: -

{{JSFiddleEmbed("https://jsfiddle.net/rybr720u/","","350")}}

+{{JSFiddleEmbed("https://jsfiddle.net/rybr720u/","","350")}} -

You can also see it on GitHub and fork the repository if you want to play with it yourself locally. Now you know the basics of Three.js, you can get back to the parent page about 3D on the Web.

+You can also [see it on GitHub](https://github.com/end3r/MDN-Games-3D/blob/gh-pages/Three.js/shapes.html) and [fork the repository](https://github.com/end3r/MDN-Games-3D/) if you want to play with it yourself locally. Now you know the basics of Three.js, you can get back to the parent page about [3D on the Web](/en-US/docs/Games/Techniques/3D_on_the_web). -

You should also try learning raw WebGL, so you can get a better understanding of what's going on. See our WebGL documentation.

+You should also try learning raw WebGL, so you can get a better understanding of what's going on. See our [WebGL documentation](/en-US/docs/Web/API/WebGL_API). diff --git a/files/zh-cn/games/techniques/3d_on_the_web/glsl_shaders/index.md b/files/zh-cn/games/techniques/3d_on_the_web/glsl_shaders/index.md index 9ef41dd573c6f6..83c5d77811761c 100644 --- a/files/zh-cn/games/techniques/3d_on_the_web/glsl_shaders/index.md +++ b/files/zh-cn/games/techniques/3d_on_the_web/glsl_shaders/index.md @@ -8,173 +8,174 @@ tags: - 顶点着色器 translation_of: Games/Techniques/3D_on_the_web/GLSL_Shaders --- -
{{GamesSidebar}}

使用 GLSL 的着色器 (shader), GLSL 是一门特殊的有着类似于 C 语言的语法,在图形管道 (graphic pipeline) 中直接可执行的 OpenGL 着色语言。着色器有两种类型 -- 顶点着色器 (Vertex Shader) 和片段着色器 (Fragment Shader). 前者是将形状转换到真实的 3D 绘制坐标中,后者是计算最终渲染的颜色和其他属性用的。

+{{GamesSidebar}} -

GLSL 不同于 JavaScript, 它是强类型语言,并且内置很多数学公式用于计算向量和矩阵。快速编写着色器非常复杂,但创建一个简单的着色器并不难。在这篇文章我们将介绍使用着色器的基础知识,并且构建一个使用 Three.js 的例子来加速代码编写。

+使用 GLSL 的着色器 (shader), GLSL 是一门特殊的有着类似于 C 语言的语法,在图形管道 (graphic pipeline) 中直接可执行的 OpenGL 着色语言。着色器有两种类型 -- 顶点着色器 (Vertex Shader) 和片段着色器 (Fragment Shader). 前者是将形状转换到真实的 3D 绘制坐标中,后者是计算最终渲染的颜色和其他属性用的。 -

你可能记得基本原理那篇文章,一个顶点 (vertex) 是在空间中有自己 3D 坐标的点,并且通常包含些被定义的其他信息。空间本身会被坐标系统定义。在那个 3D 空间中一切都是关于形状的呈现。

+GLSL 不同于 JavaScript, 它是强类型语言,并且内置很多数学公式用于计算向量和矩阵。快速编写着色器非常复杂,但创建一个简单的着色器并不难。在这篇文章我们将介绍使用着色器的基础知识,并且构建一个使用 Three.js 的例子来加速代码编写。 -

着色器类型

+你可能记得[基本原理](/en-US/docs/Games/Techniques/3D_on_the_web/Basic_theory)那篇文章,一个顶点 (vertex) 是在空间中有自己 3D 坐标的点,并且通常包含些被定义的其他信息。空间本身会被坐标系统定义。在那个 3D 空间中一切都是关于形状的呈现。 -

一个着色器实际上就是一个绘制东西到屏幕上的函数。着色器运行在 GPU 中,它对这些操作进行了很多的优化,这样你就可以卸载很多不必要的 CPU, 然后集中处理能力去执行你自己的代码。

+## 着色器类型 -

顶点着色器

+一个着色器实际上就是一个绘制东西到屏幕上的函数。着色器运行在 GPU 中,它对这些操作进行了很多的优化,这样你就可以卸载很多不必要的 CPU, 然后集中处理能力去执行你自己的代码。 -

顶点着色器操作 3D 空间的坐标并且每个顶点都会调用一次这个函数。其目的是设置 gl_Position 变量 -- 这是一个特殊的全局内置变量,它是用来存储当前顶点的位置:

+### 顶点着色器 -
void main() {
+顶点着色器操作 3D 空间的坐标并且每个顶点都会调用一次这个函数。其目的是设置 `gl_Position` 变量 -- 这是一个特殊的全局内置变量,它是用来存储当前顶点的位置:
+
+```glsl
+void main() {
 	gl_Position = makeCalculationsToHaveCoordinates;
 }
-
+``` -

这个 void main() 函数是定义全局gl_Position 变量的标准方式。所有在这个函数里面的代码都会被着色器执行。 如果将 3D 空间中的位置投射到 2D 屏幕上这些信息都会保存在计算结果的变量中。

+这个 `void main()` 函数是定义全局`gl_Position` 变量的标准方式。所有在这个函数里面的代码都会被着色器执行。 如果将 3D 空间中的位置投射到 2D 屏幕上这些信息都会保存在计算结果的变量中。 -

片段着色器

+### 片段着色器 -

片段 (或者纹理) 着色器 在计算时定义了每像素的 RGBA 颜色 — 每个像素只调用一次片段着色器。这个着色器的作用是设置 gl_FragColor 变量,也是一个 GLSL 内置变量:

+片段 (或者纹理) 着色器 在计算时定义了每像素的 RGBA 颜色 — 每个像素只调用一次片段着色器。这个着色器的作用是设置 `gl_FragColor` 变量,也是一个 GLSL 内置变量: -
void main() {
+```glsl
+void main() {
 	gl_FragColor = makeCalculationsToHaveColor;
 }
-
+``` -

计算结果包含 RGBA 颜色信息。

+计算结果包含 RGBA 颜色信息。 -

例子

+## 例子 -

让我们构建一个简单的例子来解释这些着色器的动作。假设你已经看过Three.js 教程并掌握了场景,物体和材质的基本概念。

+让我们构建一个简单的例子来解释这些着色器的动作。假设你已经看过[Three.js 教程](/en-US/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_Three.js)并掌握了场景,物体和材质的基本概念。 -
-

备注: 记住你没必要使用 Three.js 或者其他库来编写着色器 -- 纯WebGL 完全够了。我们这里使用 Three.js 来制作背景代码更简单和易理解。所以你只需关注着色器代码。Three.js 和其他 3D 库给你抽象了很多东西出来 -- 如果你想要用纯 WebGL 创建这个例子,你得写很多其他的代码才能运行。

-
+> **备注:** 记住你没必要使用 Three.js 或者其他库来编写着色器 -- 纯[WebGL](/en-US/docs/Web/API/WebGL_API) 完全够了。我们这里使用 Three.js 来制作背景代码更简单和易理解。所以你只需关注着色器代码。Three.js 和其他 3D 库给你抽象了很多东西出来 -- 如果你想要用纯 WebGL 创建这个例子,你得写很多其他的代码才能运行。 -

环境设置

+### 环境设置 -

要开始编写 WebGL 着色器你不需要做太多,只需:

+要开始编写 WebGL 着色器你不需要做太多,只需: -
    -
  • 确保你在使用对 WebGL 有良好支持的现代浏览器,比如最新版的 Firefox 或 Chrome.
  • -
  • 创建一个目录保存你的实验。
  • -
  • 拷贝一份的 压缩版的 Three.js 库 到你的目录。
  • -
+- 确保你在使用对 [WebGL](/en-US/docs/Web/API/WebGL_API) 有良好支持的现代浏览器,比如最新版的 Firefox 或 Chrome. +- 创建一个目录保存你的实验。 +- 拷贝一份的 [压缩版的 Three.js 库](http://threejs.org/build/three.min.js) 到你的目录。 -

HTML 结构

+### HTML 结构 -

这是将用到的 HTML 结构。

+这是将用到的 HTML 结构。 -
<!DOCTYPE html>
-<html>
-<head>
-	<meta charset="utf-8">
-	<title>MDN Games: Shaders demo</title>
-	<style>
+```html
+
+
+
+	
+	MDN Games: Shaders demo
+	
+	
+
+
+  
+  
+  
+
+
+```
 
-

他包含了一些基本信息比如 文档的 {{htmlelement("title")}}, 并且设置了{{htmlelement("canvas")}}元素 css 样式的宽高,Three.js 会插入到页面中占满整个可视区域。 {{htmlelement("script")}}元素在包含 Three.js 库的{{htmlelement("head")}}中。我们的代码将卸载{{htmlelement("body")}}标签中的 script 标签中:

+他包含了一些基本信息比如 文档的 {{htmlelement("title")}}, 并且设置了{{htmlelement("canvas")}}元素 css 样式的宽高,Three.js 会插入到页面中占满整个可视区域。 {{htmlelement("script")}}元素在包含 Three.js 库的{{htmlelement("head")}}中。我们的代码将卸载{{htmlelement("body")}}标签中的 script 标签中: -
    -
  1. 首先将包含顶点着色器。
  2. -
  3. 然后包含片段着色器。
  4. -
  5. 最后会包含一些生成实际场景的 JavaScript 代码。
  6. -
+1. 首先将包含顶点着色器。 +2. 然后包含片段着色器。 +3. 最后会包含一些生成实际场景的 JavaScript 代码。 -

阅读之前,复制这些代码到一个新的文本文件中,保存到你的工作目录作为 index.html. 我们将在这个文件中创建一个简单的立方体来解释着色器是如何工作的。

+阅读之前,复制这些代码到一个新的文本文件中,保存到你的工作目录作为 `index.html`. 我们将在这个文件中创建一个简单的立方体来解释着色器是如何工作的。 -

立方体源代码

+### 立方体源代码 -

我们可以复用Building up a basic demo with Three.js 中立方体的源代码,大多数元素例如渲染器,摄像机和灯光都没有发生改变,但是基本的材质会用到自己写的着色器。

+我们可以复用[Building up a basic demo with Three.js](/en-US/docs/Games/Techniques/3D_on_the_web/Building_up_a_basic_demo_with_Three.js) 中立方体的源代码,大多数元素例如渲染器,摄像机和灯光都没有发生改变,但是基本的材质会用到自己写的着色器。 -

cube.html file on GitHub中,复制第二个{{htmlelement("script")}}元素中所有的 JavaScript 代码,粘贴到当前例子中的第三个<script> 标签中。保存并运行 index.html — 然后你会看到一个蓝色立方体

+去[cube.html file on GitHub](https://github.com/end3r/MDN-Games-3D/blob/gh-pages/Three.js/cube.html)中,复制第二个{{htmlelement("script")}}元素中所有的 JavaScript 代码,粘贴到当前例子中的第三个` +``` -

或者,通过脚本来做同样的事情:

+或者,通过脚本来做同样的事情: -
var script = document.createElement('script');
+```js
+var script = document.createElement('script');
 script.src = "file.js";
-document.body.appendChild(script);
+document.body.appendChild(script); +``` -

(从脚本中创建的脚本默认为异步。) 默认的 HTML shell Emscripten 生成后者。

+(从脚本中创建的脚本默认为异步。) 默认的 HTML shell Emscripten 生成后者。 -

什么时候用 async 或者不用?

+## 什么时候用 async 或者不用? -

两种常见的情况下是脚本是异步的(由HTML 规范定义)

+两种常见的情况下是脚本是**非**异步的(由[HTML 规范](https://www.w3.org/TR/html5/scripting-1.html)定义) -
<script async>code</script>
+```js + +``` -

以及

+以及 -
var script = document.createElement('script');
+```js
+var script = document.createElement('script');
 script.innerHTML = "code";
-document.body.appendChild(script);
+document.body.appendChild(script); +``` -

两者都被视为“内联”脚本,阻塞其余所有任务,进行编译,编译完成后立即执行。

+两者都被视为“内联”脚本,阻塞其余所有任务,进行编译,编译完成后立即执行。 -

如果你的代码是一个 JS 字符串呢?而不是使用 eval 或 innerHTML,这两者都会触发同步编译,您应该使用 Blob 和 URL 对象:

+如果你的代码是一个 JS 字符串呢?而不是使用 eval 或 innerHTML,这两者都会触发同步编译,您应该使用 Blob 和 URL 对象: -
var blob = new Blob([codeString]);
+```js
+var blob = new Blob([codeString]);
 var script = document.createElement('script');
 var url = URL.createObjectURL(blob);
 script.onload = script.onerror = function() { URL.revokeObjectURL(url); };
 script.src = url;
-document.body.appendChild(script);
+document.body.appendChild(script); +``` -

使用src而不是innerHTML,则该脚本是异步的。

+使用`src`而不是`innerHTML,则该`脚本是异步的。 diff --git a/files/zh-cn/games/techniques/control_mechanisms/index.md b/files/zh-cn/games/techniques/control_mechanisms/index.md index 74a38b61d97e3e..ba0ea283a64ee8 100644 --- a/files/zh-cn/games/techniques/control_mechanisms/index.md +++ b/files/zh-cn/games/techniques/control_mechanisms/index.md @@ -16,63 +16,65 @@ tags: - touch translation_of: Games/Techniques/Control_mechanisms --- -
{{GamesSidebar}}

One of HTML5's main advantages as a game development platform is the ability to run on various platforms and devices. Streamlining cross device differences creates multiple challenges, not least when providing appropriate controls for different contexts. In this series of articles we will show you how you can approach building a game that can be played using touchscreen smartphones, mouse and keyboard, and also less common mechanisms such as gamepads.

+{{GamesSidebar}} -

Case study

+One of HTML5's main advantages as a game development platform is the ability to run on various platforms and devices. Streamlining cross device differences creates multiple challenges, not least when providing appropriate controls for different contexts. In this series of articles we will show you how you can approach building a game that can be played using touchscreen smartphones, mouse and keyboard, and also less common mechanisms such as gamepads. -

We'll be using the Captain Rogers: Battle at Andromeda demo as an example.

+## Case study -

Captain Rogers: Battle at Andromeda - cover of the game containing Enclave Games and Blackmoon Design logos, Roger's space ship and title of the game.

+We'll be using the [Captain Rogers: Battle at Andromeda demo](http://rogers2.enclavegames.com/demo/) as an example. -

Captain Rogers was created using the Phaser framework, the most popular tool for simple 2D game development in JavaScript right now, but it should be fairly easy to reuse the knowledge contained within these articles when building games in pure JavaScript or any other framework. If you're looking for a good introduction to Phaser, then check the 2D breakout game using Phaser tutorial.

+![Captain Rogers: Battle at Andromeda - cover of the game containing Enclave Games and Blackmoon Design logos, Roger's space ship and title of the game.](captainrogers2-cover.png) -

In the following articles we will show how to implement various different control mechanisms for Captain Rogers to support different platforms — from touch on mobile, through keyboard/mouse/gamepad on desktop, to more unconventional ones like TV remote, shouting to or waving your hand in front of the laptop, or squeezing bananas.

+Captain Rogers was created using the [Phaser](http://phaser.io/) framework, the most popular tool for simple 2D game development in JavaScript right now, but it should be fairly easy to reuse the knowledge contained within these articles when building games in pure JavaScript or any other framework. If you're looking for a good introduction to Phaser, then check the [2D breakout game using Phaser](/en-US/docs/Games/Tutorials/2D_breakout_game_Phaser) tutorial. -

Setting up the environment

+In the following articles we will show how to implement various different control mechanisms for Captain Rogers to support different platforms — from touch on mobile, through keyboard/mouse/gamepad on desktop, to more unconventional ones like TV remote, shouting to or waving your hand in front of the laptop, or squeezing bananas. -

Let's start with a quick overview of the game's folder structure, JavaScript files and in-game states, so we know what's happening where. The game's folders look like this:

+## Setting up the environment -

Captain Rogers: Battle at Andromeda - folder structure of the games' project containing JavaScript sources, images and fonts.

+Let's start with a quick overview of the game's folder structure, JavaScript files and in-game states, so we know what's happening where. The game's folders look like this: -

As you can see there are folders for images, JavaScript files, fonts and sound effects. The src folder contains the JavaScript files split as a separate states — Boot.js, Preloader.js, MainMenu.js and Game.js — these are loaded into the index file in this exact order. The first one initializes Phaser, the second preloads all the assets, the third one controls the main menu welcoming the player, and the fourth controls the actual gameplay.

+![Captain Rogers: Battle at Andromeda - folder structure of the games' project containing JavaScript sources, images and fonts.](captainrogers2-folderstructure.png) -

Every state has its own default methods: preload(), create(), and update(). The first one is needed for preloading required assets, create() is executed once the state had started, and update() is executed on every frame.

+As you can see there are folders for images, JavaScript files, fonts and sound effects. The `src` folder contains the JavaScript files split as a separate states — `Boot.js`, `Preloader.js`, `MainMenu.js` and `Game.js` — these are loaded into the index file in this exact order. The first one initializes Phaser, the second preloads all the assets, the third one controls the main menu welcoming the player, and the fourth controls the actual gameplay. -

For example, you can define a button in the create() function:

+Every state has its own default methods: `preload()`, `create()`, and `update()`. The first one is needed for preloading required assets, `create()` is executed once the state had started, and `update()` is executed on every frame. -
create: function() {
+For example, you can define a button in the `create()` function:
+
+```js
+create: function() {
 	// ...
 	var buttonEnclave = this.add.button(10, 10, 'logo-enclave', this.clickEnclave, this);
 	// ...
 }
-
+``` -

It will be created once at the start of the game, and will execute this.clickEnclave() action assigned to it when clicked, but you can also use the mouse's pointer value in the update() function to make an action:

+It will be created once at the start of the game, and will execute `this.clickEnclave()` action assigned to it when clicked, but you can also use the mouse's pointer value in the `update()` function to make an action: -
update: function() {
+```js
+update: function() {
 	// ...
 	if(this.game.input.mousePointer.isDown) {
 	    // do something
 	}
 	// ...
 }
-
+``` -

This will be executed whenever the mouse button is pressed, and it will be checked against the input's isDown boolean variable on every frame of the game.

+This will be executed whenever the mouse button is pressed, and it will be checked against the input's `isDown` boolean variable on every frame of the game. -

That should give you some understanding of the project structure. We'll be playing mostly with the MainMenu.js and Game.js files, and we'll explain the code inside the create() and update() methods in much more detail in later articles.

+That should give you some understanding of the project structure. We'll be playing mostly with the `MainMenu.js` and `Game.js` files, and we'll explain the code inside the `create()` and `update()` methods in much more detail in later articles. -

Pure JavaScript demo

+## Pure JavaScript demo -

There's also a small online demo with full source code available on GitHub where the basic support for the control mechanisms described in the articles is implemented in pure JavaScript. It will be explained in the given articles themselves below, but you can play with it already, and use the code however you want for learning purposes.

+There's also a [small online demo](https://end3r.github.io/JavaScript-Game-Controls/) with full source code [available on GitHub](https://github.com/end3r/JavaScript-Game-Controls/) where the basic support for the control mechanisms described in the articles is implemented in pure JavaScript. It will be explained in the given articles themselves below, but you can play with it already, and use the code however you want for learning purposes. -

The articles

+## The articles -

JavaScript is the perfect choice for mobile gaming because of HTML5 being truly multiplatform; all of the following articles focus on the APIs provided for interfacing with different control mechanisms:

+JavaScript is the perfect choice for mobile gaming because of HTML5 being truly multiplatform; all of the following articles focus on the APIs provided for interfacing with different control mechanisms: -
    -
  1. Mobile touch controls — The first article will kick off with touch, as the mobile first approach is very popular.
  2. -
  3. Desktop mouse and keyboard controls — When playing on a desktop/laptop computer, providing keyboard and mouse controls is essential to provide an acceptable level of accessibility for the game.
  4. -
  5. Desktop gamepad controls — The Gamepad API rather usefully allows gamepads to be used for controlling web apps on desktop/laptop, for that console feel.
  6. -
  7. Unconventional controls — The final article showcases some unconventional control mechanisms, from the experimental to the slightly crazy, which you might not believe could be used to play the game.
  8. -
+1. [Mobile touch controls](/en-US/docs/Games/Techniques/Control_mechanisms/Mobile_touch) — The first article will kick off with touch, as the mobile first approach is very popular. +2. [Desktop mouse and keyboard controls](/en-US/docs/Games/Techniques/Control_mechanisms/Desktop_with_mouse_and_keyboard) — When playing on a desktop/laptop computer, providing keyboard and mouse controls is essential to provide an acceptable level of accessibility for the game. +3. [Desktop gamepad controls](/en-US/docs/Games/Techniques/Control_mechanisms/Desktop_with_gamepad) — The Gamepad API rather usefully allows gamepads to be used for controlling web apps on desktop/laptop, for that console feel. +4. [Unconventional controls](/en-US/docs/Games/Techniques/Control_mechanisms/Other) — The final article showcases some unconventional control mechanisms, from the experimental to the slightly crazy, which you might not believe could be used to play the game. diff --git a/files/zh-cn/games/techniques/control_mechanisms/mobile_touch/index.md b/files/zh-cn/games/techniques/control_mechanisms/mobile_touch/index.md index afd7fe49b5bca6..53f81a4fd42fae 100644 --- a/files/zh-cn/games/techniques/control_mechanisms/mobile_touch/index.md +++ b/files/zh-cn/games/techniques/control_mechanisms/mobile_touch/index.md @@ -4,120 +4,131 @@ slug: Games/Techniques/Control_mechanisms/Mobile_touch translation_of: Games/Techniques/Control_mechanisms/Mobile_touch original_slug: Games/Techniques/Control_mechanisms/移动端触摸控制 --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{NextMenu("Games/Techniques/Control_mechanisms/Desktop_with_mouse_and_keyboard", "Games/Techniques/Control_mechanisms")}}

+{{NextMenu("Games/Techniques/Control_mechanisms/Desktop_with_mouse_and_keyboard", "Games/Techniques/Control_mechanisms")}} -

未来手游一定是 Web 的天下,许多开发在游戏开发过程中首先选择手游 — 既然如此,触摸控制是不可少的。我们将在本教程中了解怎样简单地在移动端 H5 游戏中实现触摸控制 ,只要移动端支持触摸,你就可以尽情的玩。

+未来手游一定是 Web 的天下,许多开发在游戏开发过程中首先选择手游 — 既然如此,触摸控制是不可少的。我们将在本教程中了解怎样简单地在移动端 H5 游戏中实现触摸控制 ,只要移动端支持触摸,你就可以尽情的玩。 -

说明:游戏 Captain Rogers: Battle at Andromeda 是基于Phaser 和 Phaser-based 管理控制,但它也可以用纯 JavaScript 实现。使用 Phaser 的好处它提供了辅助变量和方法可以直接调用,有助于快速的开发游戏,这需要根据项目实际情况选择。

+**说明**:游戏 [Captain Rogers: Battle at Andromeda](http://rogers2.enclavegames.com/demo/) 是基于[Phaser](http://phaser.io/) 和 Phaser-based 管理控制,但它也可以用纯 JavaScript 实现。使用 Phaser 的好处它提供了辅助变量和方法可以直接调用,有助于快速的开发游戏,这需要根据项目实际情况选择。 -

纯 JavaScript 方式实现

+## 纯 JavaScript 方式实现 -

我们可以实现自己的触摸事件 — 给 document 添加事件监听,并传入自定义功能的方法,非常简单:

+我们可以实现自己的触摸事件 — 给 document 添加事件监听,并传入自定义功能的方法,非常简单: -
var el = document.getElementsByTagName("canvas")[0];
+```js
+var el = document.getElementsByTagName("canvas")[0];
 el.addEventListener("touchstart", handleStart);
 el.addEventListener("touchmove", handleMove);
 el.addEventListener("touchend", handleEnd);
-el.addEventListener("touchcancel", handleCancel);
+el.addEventListener("touchcancel", handleCancel); +``` -

这样,在移动设备上屏幕上触摸游戏的 {{htmlelement("canvas")}} 将触发这些事件,因为我们就可以随意操控游戏(如:移动太空船)。 事件如下所示:

+这样,在移动设备上屏幕上触摸游戏的 {{htmlelement("canvas")}} 将触发这些事件,因为我们就可以随意操控游戏(如:移动太空船)。 事件如下所示: -
    -
  • touchstart 当用户手指放在屏幕上触发。
  • -
  • touchmove 当他们在屏幕上移动手指时触发。
  • -
  • touchend 当用户在屏幕上停止移动时触发。
  • -
  • touchcancel 触摸被取消是触发,例如当用户将他们的手指移动到屏幕之外时。
  • -
+- [touchstart](/en-US/docs/Web/API/GlobalEventHandlers/ontouchstart) 当用户手指放在屏幕上触发。 +- [touchmove](/en-US/docs/Web/API/GlobalEventHandlers/ontouchmove) 当他们在屏幕上移动手指时触发。 +- [touchend](/en-US/docs/Web/API/GlobalEventHandlers/ontouchend) 当用户在屏幕上停止移动时触发。 +- [touchcancel](/en-US/docs/Web/API/GlobalEventHandlers/ontouchcancel) 触摸被取消是触发,例如当用户将他们的手指移动到屏幕之外时。 -
-

备注: 这篇 touch events 参考文章提供了更多的实例和介绍。

-
+> **备注:** 这篇 [touch events](/en-US/docs/Web/API/Touch_events) 参考文章提供了更多的实例和介绍。 -

纯 JavaScript 示例

+### 纯 JavaScript 示例 -

这个实现了移动端触摸的little demo代码已经放到了 GibHub 上,我们下载这个示例就可以实现在移动端屏幕上移动飞船。

+这个实现了移动端触摸的[little demo](https://github.com/end3r/JavaScript-Game-Controls/)代码已经放到了 GibHub 上,我们下载这个示例就可以实现在移动端屏幕上移动飞船。 -

我们将两种事件:touchstart touchmove 放到一个方法里处理。为什么呢? touchHandler 方法定义的飞船位置变量适合下面两种情况下:当玩家触摸时,但不移动它(touchstart)和当手指在屏幕上开始移动(touchmove):

+我们将两种事件:`touchstart `和`touchmove` 放到一个方法里处理。为什么呢? `touchHandler` 方法定义的飞船位置变量适合下面两种情况下:当玩家触摸时,但不移动它(`touchstart`)和当手指在屏幕上开始移动(`touchmove`): -
document.addEventListener("touchstart", touchHandler);
-document.addEventListener("touchmove", touchHandler);
+```js +document.addEventListener("touchstart", touchHandler); +document.addEventListener("touchmove", touchHandler); +``` -

touchHandler 方法的代码如下:

+`touchHandler` 方法的代码如下: -
function touchHandler(e) {
+```js
+function touchHandler(e) {
     if(e.touches) {
         playerX = e.touches[0].pageX - canvas.offsetLeft - playerWidth / 2;
         playerY = e.touches[0].pageY - canvas.offsetTop - playerHeight / 2;
         output.innerHTML = "Touch: "+ " x: " + playerX + ", y: " + playerY;
         e.preventDefault();
     }
-}
+} +``` -

If the touch occurs (touches object is not empty), then we will have all the info we need in that object. We can get the first touch (e.touches[0], our example is not multitouch-enabled), extract the pageX and pageY variables and set the player's ship position on the screen by subtracting the Canvas offset (distance from the Canvas and the edge of the screen) and half the player's width and height.

+If the touch occurs (`touches` object is not empty), then we will have all the info we need in that object. We can get the first touch (`e.touches[0]`, our example is not multitouch-enabled), extract the `pageX` and `pageY` variables and set the player's ship position on the screen by subtracting the Canvas offset (distance from the Canvas and the edge of the screen) and half the player's width and height. -

Touch controls for the player's ship, with visible output of the x and y position.

+![Touch controls for the player's ship, with visible output of the x and y position.](controls-touch.png) -

To see if it's working correctly we can output the x and y positions using the output element. The preventDefault() function is needed to prevent the browser from moving — without it you'd have the default behaviour, and the Canvas would be dragged around the page, which would show the browser scroll bars and look messy.

+To see if it's working correctly we can output the `x` and `y` positions using the `output` element. The `preventDefault()` function is needed to prevent the browser from moving — without it you'd have the default behaviour, and the Canvas would be dragged around the page, which would show the browser scroll bars and look messy. -

Touch events in Phaser

+## Touch events in Phaser -

We don't have to do this on our own; frameworks like Phaser offer systems for managing touch events for us — see managing the touch events.

+We don't have to do this on our own; frameworks like Phaser offer systems for managing touch events for us — see [managing the touch events](http://phaser.io/docs/2.6.1/Phaser.Touch.html). -

Pointer theory

+### Pointer theory -

A pointer represents a single finger on the touch screen. Phaser starts two pointers by default, so two fingers can perform an action at once. Captain Rogers is a simple game — it can be controlled by two fingers, the left one moving the ship and the right one controlling the ship's gun. There's no multitouch or gestures — everything is handled by single pointer inputs.

+A [pointer](http://phaser.io/docs/2.6.1/Phaser.Pointer.html) represents a single finger on the touch screen. Phaser starts two pointers by default, so two fingers can perform an action at once. Captain Rogers is a simple game — it can be controlled by two fingers, the left one moving the ship and the right one controlling the ship's gun. There's no multitouch or gestures — everything is handled by single pointer inputs. -

You can add more pointers to the game by using; this.game.input.addPointer up to ten pointers can be managed simultaneously. The most recently used pointer is available in the this.game.input.activePointer object — the most recent finger active on the screen.

+You can add more pointers to the game by using; `this.game.input.addPointer` up to ten pointers can be managed simultaneously. The most recently used pointer is available in the `this.game.input.activePointer` object — the most recent finger active on the screen. -

If you need to access a specific pointer, they are all available at, this.game.input.pointer1this.game.input.pointer2, etc. They are assigned dynamically, so if you put three fingers on the screen, then, pointer1pointer2, and pointer3 will be active. Removing the second finger, for example, won't affect the other two, and setting it back again will use the first available property, so pointer2 will be used again.

+If you need to access a specific pointer, they are all available at, ` this.game.input.pointer1``this.game.input.pointer2 `, etc. They are assigned dynamically, so if you put three fingers on the screen, then, ` pointer1``pointer2 `, and `pointer3` will be active. Removing the second finger, for example, won't affect the other two, and setting it back again will use the first available property, so `pointer2` will be used again. -

You can quickly get the coordinates of the most recently active pointer via the this.game.input.x and this.game.input.y variables.

+You can quickly get the coordinates of the most recently active pointer via the `this.game.input.x` and `this.game.input.y` variables. -

Input events

+### Input events -

Instead of using the pointers directly it is also possible to listen for this.game.input events, like onDown, onUp, onTap and onHold:

+Instead of using the pointers directly it is also possible to listen for `this.game.input` events, like `onDown`, `onUp`, `onTap` and `onHold`: -
this.game.input.onDown.add(itemTouched, this);
+```js
+this.game.input.onDown.add(itemTouched, this);
 
 function itemTouched(pointer) {
     // do something
-}
+} +``` -

The itemTouched() function will be executed when the onDown event is dispatched by touching the screen. The pointer variable will contain the information about the pointer that activated the event.

+The `itemTouched()` function will be executed when the `onDown` event is dispatched by touching the screen. The `pointer` variable will contain the information about the pointer that activated the event. -

This approach uses the generally available this.game.input object, but you can also detect the actions on any game objects like sprites or buttons by using onInputOver, onInputOut, onInputDown, onInputUp, onDragStart, or onDragStop:

+This approach uses the generally available `this.game.input` object, but you can also detect the actions on any game objects like sprites or buttons by using `onInputOver`, `onInputOut`, `onInputDown`, `onInputUp`, `onDragStart`, or `onDragStop`: -
this.button.events.onInputOver.add(itemTouched, this);
+```js
+this.button.events.onInputOver.add(itemTouched, this);
 
 function itemTouched(button, pointer) {
     // do something
-}
+} +``` -

That way you'll be able to attach an event to any object in the game, like the player's ship, and react to the actions performed by the user.

+That way you'll be able to attach an event to any object in the game, like the player's ship, and react to the actions performed by the user. -

An additional advantage of using Phaser is that the buttons you create will take any type of input, whether it's a touch on mobile or a click on desktop — the framework sorts this out in the background for you.

+An additional advantage of using Phaser is that the buttons you create will take any type of input, whether it's a touch on mobile or a click on desktop — the framework sorts this out in the background for you. -

Implementation

+### Implementation -

The easiest way to add an interactive object that will listen for user input is to create a button:

+The easiest way to add an interactive object that will listen for user input is to create a button: -
var buttonEnclave = this.add.button(10, 10, 'logo-enclave', this.clickEnclave, this);
+```js +var buttonEnclave = this.add.button(10, 10, 'logo-enclave', this.clickEnclave, this); +``` -

This one is formed in the MainMenu state — it will be placed ten pixels from the top left corner of the screen, use the logo-enclave image, and execute the clickEnclave() function when it is touched. This will work on mobile and desktop out of the box. There are a few buttons in the main menu, including the one that will start the game.

+This one is formed in the `MainMenu` state — it will be placed ten pixels from the top left corner of the screen, use the `logo-enclave` image, and execute the `clickEnclave()` function when it is touched. This will work on mobile and desktop out of the box. There are a few buttons in the main menu, including the one that will start the game. -

For the actual gameplay, instead of creating more buttons and covering the small mobile screen with them, we can use something a little bit different: we'll create invisible areas which respond to the given action. From a design point of view, it is better to make the field of activity bigger without covering half of the screen with button images. For example, tapping on the right side of the screen will fire the weapon:

+For the actual gameplay, instead of creating more buttons and covering the small mobile screen with them, we can use something a little bit different: we'll create invisible areas which respond to the given action. From a design point of view, it is better to make the field of activity bigger without covering half of the screen with button images. For example, tapping on the right side of the screen will fire the weapon: -
this.buttonShoot = this.add.button(this.world.width*0.5, 0, 'button-alpha', null, this);
+```js
+this.buttonShoot = this.add.button(this.world.width*0.5, 0, 'button-alpha', null, this);
 this.buttonShoot.onInputDown.add(this.goShootPressed, this);
-this.buttonShoot.onInputUp.add(this.goShootReleased, this);
+this.buttonShoot.onInputUp.add(this.goShootReleased, this); +``` -

The code above will create a new button using a transparent image that covers the right half of the screen. You can assign functions on input down and input up separately if you'd like to perform more complicated actions, but in this game touching the right side of the screen will simply fire the bullets to the right — this is all we need in this case.

+The code above will create a new button using a transparent image that covers the right half of the screen. You can assign functions on input down and input up separately if you'd like to perform more complicated actions, but in this game touching the right side of the screen will simply fire the bullets to the right — this is all we need in this case. -

Moving the player could be managed by creating the four directional buttons, but we can take the advantage of touch screens and drag the player's ship around:

+Moving the player could be managed by creating the four directional buttons, but we can take the advantage of touch screens and drag the player's ship around: -
var player = this.game.add.sprite(30, 30, 'ship');
+```js
+var player = this.game.add.sprite(30, 30, 'ship');
 player.inputEnabled = true;
 player.input.enableDrag();
 player.events.onDragStart.add(onDragStart, this);
@@ -125,29 +136,34 @@ player.events.onDragStop.add(onDragStop, this);
 
 function onDragStart(sprite, pointer) {
     // do something when dragging
-}
+} +``` -

We can pull the ship around and do something in the meantime, and react when the drag is stopped. Hauling in Phaser, if enabled, will work out of the box — you don't have to set the position of the sprite yourself manually, so you could leave the onDragStart() function empty, or place some debug output to see if it's working correctly. The pointer element contains the x and y variables storing the current position of the dragged element.

+We can pull the ship around and do something in the meantime, and react when the drag is stopped. Hauling in Phaser, if enabled, will work out of the box — you don't have to set the position of the sprite yourself manually, so you could leave the `onDragStart()` function empty, or place some debug output to see if it's working correctly. The `pointer` element contains the `x` and `y` variables storing the current position of the dragged element. -

Dedicated plugins

+### Dedicated plugins -

You could go even further and use dedicated plugins like Virtual Joystick — this is a paid, official Phaser plugin, but you can find free and open source alternatives. The initialization of Virtual Joystick looks like this:

+You could go even further and use dedicated plugins like [Virtual Joystick](http://phaser.io/shop/plugins/virtualjoystick) — this is a paid, official Phaser plugin, but you can find free and [open source alternatives](https://github.com/Gamegur-us/phaser-touch-control-plugin). The initialization of Virtual Joystick looks like this: -
this.pad = this.game.plugins.add(Phaser.VirtualJoystick);
-this.stick = this.pad.addStick(30, 30, 80, 'generic');
+```js +this.pad = this.game.plugins.add(Phaser.VirtualJoystick); +this.stick = this.pad.addStick(30, 30, 80, 'generic'); +``` -

In the create() function of the Game state we're creating a virtual pad and a generic stick that has four directional virtual buttons by default. This is placed 30 pixels from the top and left edges of the screen and is 80 pixels wide.

+In the `create()` function of the `Game` state we're creating a virtual pad and a generic stick that has four directional virtual buttons by default. This is placed 30 pixels from the top and left edges of the screen and is 80 pixels wide. -

The stick being pressed can be handled during the gameplay in the update function like so:

+The stick being pressed can be handled during the gameplay in the `update` function like so: -
if(this.stick.isDown) {
+```js
+if(this.stick.isDown) {
     // move the player
-}
+} +``` -

We can adjust the player's velocity based on the current angle of the stick and move him appropriately.

+We can adjust the player's velocity based on the current angle of the stick and move him appropriately. -

摘要

+## 摘要 -

这篇文章主要讲解如何在移动端实现触摸控制; 下一篇文章我们将看到怎样添加键盘和鼠标支持。

+这篇文章主要讲解如何在移动端实现触摸控制; 下一篇文章我们将看到怎样添加键盘和鼠标支持。 -

{{NextMenu("Games/Techniques/Control_mechanisms/Desktop_with_mouse_and_keyboard", "Games/Techniques/Control_mechanisms")}}

+{{NextMenu("Games/Techniques/Control_mechanisms/Desktop_with_mouse_and_keyboard", "Games/Techniques/Control_mechanisms")}} diff --git a/files/zh-cn/games/techniques/controls_gamepad_api/index.md b/files/zh-cn/games/techniques/controls_gamepad_api/index.md index 958c6107fe5423..7dbad1e3508ecd 100644 --- a/files/zh-cn/games/techniques/controls_gamepad_api/index.md +++ b/files/zh-cn/games/techniques/controls_gamepad_api/index.md @@ -3,45 +3,46 @@ title: 使用 Gamepad API 实现控制 slug: Games/Techniques/Controls_Gamepad_API translation_of: Games/Techniques/Controls_Gamepad_API --- -
{{GamesSidebar}}

这篇文章着眼于使用 Gamepad API 为网页游戏实现一个有效的跨浏览器控制系统,可以让你使用端游控制器来控制你的网页游戏。Hungry Fridge,就是 Enclave Games 以此制作的游戏。

+{{GamesSidebar}} -

网页游戏的控制

+这篇文章着眼于使用 Gamepad API 为网页游戏实现一个有效的跨浏览器控制系统,可以让你使用端游控制器来控制你的网页游戏。Hungry Fridge,就是 [Enclave Games](http://enclavegames.com/) 以此制作的游戏。 -

在历史上,在连接主机 (console) 的电视上玩游戏和在电脑 (PC) 上玩游戏是两种完全不一样的体验,最大的区别就是它们的控制方式。后来,额外的驱动程序和插件让我们能够使用主机控制器来游玩电脑端的游戏--不论是本地游戏,还是运行在浏览器中的游戏。 到现在的 HTML5 时代,我们终于有了 Gamepad API ,让我们能够在不安装任何插件的情况下,可以使用控制器来游玩基于浏览器的游戏。Gamepad API 通过提供一个接口公开按钮的按下和坐标的变化来实现这一点,在 JavaScript 中我们可以用这些变化来处理输入。这对于网页游戏来说是非常棒的特性。

+## 网页游戏的控制 -

API 状态与浏览器支持

+在历史上,在连接主机 (console) 的电视上玩游戏和在电脑 (PC) 上玩游戏是两种完全不一样的体验,最大的区别就是它们的控制方式。后来,额外的驱动程序和插件让我们能够使用主机控制器来游玩电脑端的游戏--不论是本地游戏,还是运行在浏览器中的游戏。 到现在的 HTML5 时代,我们终于有了 [Gamepad API](/en-US/docs/Web/API/Gamepad_API) ,让我们能够在不安装任何插件的情况下,可以使用控制器来游玩基于浏览器的游戏。Gamepad API 通过提供一个接口公开按钮的按下和坐标的变化来实现这一点,在 JavaScript 中我们可以用这些变化来处理输入。这对于网页游戏来说是非常棒的特性。 -

Gamepad API 在 W3C 的进程中仍然还是工作草案的状态,这意味着它的实现方法可能还会出现变动,但是就目前来说浏览器的支持性相当不错。Firefox 29+ 和 Chrome 35+ 对其支持得非常好。Opera 在版本 22+ 对 API 进行了支持 (一点也不奇怪,因为他们现在使用 Chrome 的引擎了。) 并且微软最近在 Edge 中对 API 实现了支持,也就是说四大主流浏览器现在都支持 Gamepad API。

+## API 状态与浏览器支持 -

哪种控制器最好?

+[Gamepad API](http://www.w3.org/TR/gamepad/) 在 W3C 的进程中仍然还是工作草案的状态,这意味着它的实现方法可能还会出现变动,但是就目前来说[浏览器的支持性](http://caniuse.com/gamepad)相当不错。Firefox 29+ 和 Chrome 35+ 对其支持得非常好。Opera 在版本 22+ 对 API 进行了支持 (一点也不奇怪,因为他们现在使用 Chrome 的引擎了。) 并且微软最近在 Edge 中对 API 实现了支持,也就是说四大主流浏览器现在都支持 Gamepad API。 -

目前最受欢迎的控制器是来自 XBox 360、XBox One、PS3 和 PS4 的 — 它们经受过时间的检验,并且在浏览器跨 Windows 与 Mac OS 平台中对 Gamepad API 的实现中工作良好。

+## 哪种控制器最好? -

还有一些其他各种各样不同布局的控制器或多或少的支持跨浏览器的实现。本文中讨论的代码使用了一些控制器进行测试,但是笔者比较喜欢的配置是:无线 XBox 360 控制器和 Mac OS X 平台的 Firefox 浏览器。

+目前最受欢迎的控制器是来自 XBox 360、XBox One、PS3 和 PS4 的 — 它们经受过时间的检验,并且在浏览器跨 Windows 与 Mac OS 平台中对 Gamepad API 的实现中工作良好。 -

实例分析:Hungry Fridge

+还有一些其他各种各样不同布局的控制器或多或少的支持跨浏览器的实现。本文中讨论的代码使用了一些控制器进行测试,但是笔者比较喜欢的配置是:无线 XBox 360 控制器和 Mac OS X 平台的 Firefox 浏览器。 -

GitHub Game Off II 比赛举行于 2013 年 11 月,Enclave Games 决定参加比赛。比赛的主题为“改变”(change),所以他们提交了这样一个游戏——你需要通过点击来喂食饥饿的冰箱健康的食物 (苹果、萝卜、莴苣) 并避开“坏”的食物 (啤酒、汉堡、披萨) 。其中会有倒计时会改变接下来几秒内冰箱想吃的东西,所以你又要小心动作又要块。你可以在这里尝试 Hungry Fridge

+## 实例分析:Hungry Fridge -

第二个隐藏的“改变”的实现是可以从单纯静态的冰箱改变成涡轮驱动、射击和吞食的机器能力。当你连接控制器后,游戏会有很明显的改变 (饥饿冰箱会变成超级涡轮的饥饿冰箱) 并且你可以使用 Gamepad API 来控制装甲冰箱。你需要击落食物但是你仍然需要找到冰箱目前想吃的食物,否则你会失去能量。

+[GitHub Game Off II](https://github.com/blog/1674-github-game-off-ii) 比赛举行于 2013 年 11 月,[Enclave Games](http://enclavegames.com/) 决定参加比赛。比赛的主题为“改变”(change),所以他们提交了这样一个游戏——你需要通过点击来喂食饥饿的冰箱健康的食物 (苹果、萝卜、莴苣) 并避开“坏”的食物 (啤酒、汉堡、披萨) 。其中会有倒计时会改变接下来几秒内冰箱想吃的东西,所以你又要小心动作又要块。你可以[在这里尝试 Hungry Fridge](http://enclavegames.com/games/hungry-fridge/)。 -

游戏封装了两种截然不同的“变化”(change) ——好食物对坏食物,与移动端对桌面端。

+第二个隐藏的“改变”的实现是可以从单纯静态的冰箱改变成涡轮驱动、射击和吞食的机器能力。当你连接控制器后,游戏会有很明显的改变 (饥饿冰箱会变成超级涡轮的饥饿冰箱) 并且你可以使用 Gamepad API 来控制装甲冰箱。你需要击落食物但是你仍然需要找到冰箱目前想吃的食物,否则你会失去能量。 -

示例

+游戏封装了两种截然不同的“变化”(change) ——好食物对坏食物,与移动端对桌面端。 -

Game API 的动作展示与 JavaScript 的源代码公布是在完整版的 Hungry Fridge 构建之后才开始的,然后据此创建了一个 简单的示例。部分 Gamepad API Content Kit 在 Github 上供你分析代码并研究其如何工作。

+## 示例 -

以下讨论的代码来自于完整的 Hungry Fridge 游戏中,除了原代码需要 turbo 变量来决定是否启动“超级涡轮模式”以外几乎一模一样。此代码可以独立运行,就算不连接控制器也可以。

+Game API 的动作展示与 JavaScript 的源代码公布是在完整版的 Hungry Fridge 构建之后才开始的,然后据此创建了一个 [简单的示例](https://end3r.github.io/Gamepad-API-Content-Kit/demo/demo.html)。部分 [Gamepad API Content Kit](https://end3r.github.io/Gamepad-API-Content-Kit/) 在 Github 上供你分析代码并研究其如何工作。 -
-

备注: 一个彩蛋:点击界面右上角的控制器图标有个隐藏选项——不连接控制器也能启动“超级涡轮模式” 。你可以使用键盘上的 A 和 D 控制左右旋转,W 射击,方向键移动。

-
+以下讨论的代码来自于完整的 Hungry Fridge 游戏中,除了原代码需要 `turbo` 变量来决定是否启动“超级涡轮模式”以外几乎一模一样。此代码可以独立运行,就算不连接控制器也可以。 -

实现方法

+> **备注:** 一个彩蛋:点击界面右上角的控制器图标有个隐藏选项——不连接控制器也能启动“超级涡轮模式” 。你可以使用键盘上的 A 和 D 控制左右旋转,W 射击,方向键移动。 -

使用 Gamepad API 时有两个重要的事件——gamepadconnectedgamepaddisconnected。前者将于浏览器侦测到新控制器连接时触发;而后者则是断开连接 (不管是物理断开还是无响应了) 的时候触发。在示例中 gamepadAPI 对象通常存储着所有关于 API 的东西:

+## 实现方法 -
var gamepadAPI = {
+使用 Gamepad API 时有两个重要的事件——`gamepadconnected` 和 `gamepaddisconnected`。前者将于浏览器侦测到新控制器连接时触发;而后者则是断开连接 (不管是物理断开还是无响应了) 的时候触发。在示例中 `gamepadAPI` 对象通常存储着所有关于 API 的东西:
+
+```js
+var gamepadAPI = {
   controller: {},
   turbo: false,
   connect: function() {},
@@ -52,65 +53,73 @@ translation_of: Games/Techniques/Controls_Gamepad_API
   buttonsCache: [],
   buttonsStatus: [],
   axesStatus: []
-};
+}; +``` -

数组 buttons 存储着 XBox 360 控制器的按键布局 button layout:

+数组 `buttons` 存储着 XBox 360 控制器的按键布局 button layout: -
buttons: [
+```js
+buttons: [
   'DPad-Up','DPad-Down','DPad-Left','DPad-Right',
   'Start','Back','Axis-Left','Axis-Right',
   'LB','RB','Power','A','B','X','Y',
-],
+], +``` -

这可能和例如 PS3 控制器 (或者其他没名字的通用控制器) 等其他控制器有所不同,所以你需要注意并不要假设你期望的布局和你真正使用的控制器布局是一样。接下来我们设置两个事件侦听器来获取数据:

+这可能和例如 PS3 控制器 (或者其他没名字的通用控制器) 等其他控制器有所不同,所以你需要注意并不要假设你期望的布局和你真正使用的控制器布局是一样。接下来我们设置两个事件侦听器来获取数据: -
window.addEventListener("gamepadconnected", gamepadAPI.connect);
-window.addEventListener("gamepaddisconnected", gamepadAPI.disconnect);
+```js +window.addEventListener("gamepadconnected", gamepadAPI.connect); +window.addEventListener("gamepaddisconnected", gamepadAPI.disconnect); +``` -

由于安全策略,你必须先与控制器产生交互才能触发当前显示页面的事件。如果 API 在没有接收到用户交互的时候工作,那它可能会在不知情的情况下被用来识别指纹。

+由于安全策略,你必须先与控制器产生交互才能触发当前显示页面的事件。如果 API 在没有接收到用户交互的时候工作,那它可能会在不知情的情况下被用来识别指纹。 -

两个函数都十分简单:

+两个函数都十分简单: -
connect: function(evt) {
+```js
+connect: function(evt) {
   gamepadAPI.controller = evt.gamepad;
   gamepadAPI.turbo = true;
   console.log('控制器已连接。');
-},
+}, +``` -

函数 connect() 接受一个事件作为参数,并将其中的 gamepad 对象分配给 gamepadAPI.controller 变量。我们在这个游戏中只使用一个控制器,所以这个变量是一个单独的对象而不是控制器的数组。然后我们设置 turbo 属性为 true。 (这个可以直接用 gamepad.connected 实现,但我们想单独设置一个变量来控制“涡轮模式”而不需要连接控制器,原因已在前面说明过了。)

+函数 `connect()` 接受一个事件作为参数,并将其中的 `gamepad` 对象分配给 `gamepadAPI.controller` 变量。我们在这个游戏中只使用一个控制器,所以这个变量是一个单独的对象而不是控制器的数组。然后我们设置 `turbo` 属性为 `true`。 (这个可以直接用 `gamepad.connected` 实现,但我们想单独设置一个变量来控制“涡轮模式”而不需要连接控制器,原因已在前面说明过了。) -
disconnect: function(evt) {
+```js
+disconnect: function(evt) {
   gamepadAPI.turbo = false;
   delete gamepadAPI.controller;
   console.log('控制器已断开。');
-},
+}, +``` -

函数 disconnect 设置 gamepad.turbo 属性为 false 并移除存储着 gamepad 对象的变量。

+函数 `disconnect` 设置 `gamepad.turbo` 属性为 `false` 并移除存储着 `gamepad` 对象的变量。 -

Gamepad 对象

+### Gamepad 对象 -

对象 gamepad 中有包含了许多有用的信息,其中就包括按钮和坐标轴的状态等重要信息:

+对象 `gamepad` 中有包含了许多有用的信息,其中就包括按钮和坐标轴的状态等重要信息: -
    -
  • id: 一个包含关于控制器信息的字符串。
  • -
  • index: 一个为已连接的设备分配的唯一标识。
  • -
  • connected: 一个布尔变量,true 表示设备已连接。
  • -
  • mapping: 键位的布局类型;现在只有 standard 是唯一可用的值。
  • -
  • axes: 每一个坐标轴的状态。表示为存储浮点值的数组。
  • -
  • buttons : 每个按钮的状态,表示为一个 GamepadButton 对象,其包含 pressedvalue 属性。
  • -
+- `id`: 一个包含关于控制器信息的字符串。 +- `index`: 一个为已连接的设备分配的唯一标识。 +- `connected`: 一个布尔变量,`true` 表示设备已连接。 +- `mapping`: 键位的布局类型;现在只有 `standard` 是唯一可用的值。 +- `axes`: 每一个坐标轴的状态。表示为存储浮点值的数组。 +- `buttons` : 每个按钮的状态,表示为一个 `GamepadButton` 对象,其包含 `pressed` 和 `value` 属性。 -

变量 index 在我们连接了多个控制器时非常有用,我们可以用此来区分它们的操作——例如我们有一个需要连接两个控制器的双人游戏。

+变量 `index` 在我们连接了多个控制器时非常有用,我们可以用此来区分它们的操作——例如我们有一个需要连接两个控制器的双人游戏。 -

查询控制器对象

+### 查询控制器对象 -

除了 connect()disconnect()gamepadAPI 对象中还有另外两个方法:update()buttonPressed()update() 会在游戏循环的每一帧中执行,来更新 gamepad 对象的实时状态:

+除了 `connect()` 和 `disconnect()` ,`gamepadAPI` 对象中还有另外两个方法:`update()` 和 `buttonPressed()`。`update()` 会在游戏循环的每一帧中执行,来更新 gamepad 对象的实时状态: -
update: function() {
+```js
+update: function() {
   // 清除按钮缓存
   gamepadAPI.buttonsCache = [];
   // 从上一帧中移动按钮状态到缓存中
-  for(var k=0; k<gamepadAPI.buttonsStatus.length; k++) {
+  for(var k=0; k

+}, +``` -

在每一帧上,update() 都会将上一帧的按钮状态保存至数组 buttonsCache 中,并在 gamepadAPI.controller 对象提取出新的状态信息。然后它就能轮询按钮和坐标值并获得它们的实时状态和值。

+在每一帧上,`update()` 都会将上一帧的按钮状态保存至数组 `buttonsCache` 中,并在 `gamepadAPI.controller` 对象提取出新的状态信息。然后它就能轮询按钮和坐标值并获得它们的实时状态和值。 -

监测按钮按下

+### 监测按钮按下 -

方法 buttonPressed() 也位于主游戏循环中来监听按钮的按下。它有两个参数——我们想要监听的按钮和 (可选) 用来告诉游戏接收的按键是(从之前就)被按住了的。没了它你需要松开并再按一次按钮才能得到想要的结果。

+方法 `buttonPressed()` 也位于主游戏循环中来监听按钮的按下。它有两个参数——我们想要监听的按钮和 (可选) 用来告诉游戏接收的按键是(从之前就)被按住了的。没了它你需要松开并再按一次按钮才能得到想要的结果。 -
buttonPressed: function(button, hold) {
+```js
+buttonPressed: function(button, hold) {
   var newPress = false;
   // 轮询按下的按钮
-  for(var i=0,s=gamepadAPI.buttonsStatus.length; i<s; i++) {
+  for(var i=0,s=gamepadAPI.buttonsStatus.length; i

+}, +``` -

在一个按钮中有两种动作:单次按下和按住。变量 newPress 布尔变量将会指出这个是不是一个按钮新的按下操作。下次我们再轮询已按下按钮的数组——如果有按钮是我们正在找的,那么设 newPress 变量为 true 。通过检查本次按下是不是新按下的,就能得出玩家是不是按住按钮了。我们从游戏循环中的上一帧轮询按钮的缓存状态,如果我们找到了,就说明按钮被按住了,所以就不是新的按下。最后 newPress 变量被返回。函数 buttonPressed 通常这样来更新游戏循环:

+在一个按钮中有两种动作:单次按下和按住。变量 `newPress` 布尔变量将会指出这个是不是一个按钮新的按下操作。下次我们再轮询已按下按钮的数组——如果有按钮是我们正在找的,那么设 `newPress` 变量为 `true` 。通过检查本次按下是不是新按下的,就能得出玩家是不是按住按钮了。我们从游戏循环中的上一帧轮询按钮的缓存状态,如果我们找到了,就说明按钮被按住了,所以就不是新的按下。最后 `newPress` 变量被返回。函数 `buttonPressed` 通常这样来更新游戏循环: -
if(gamepadAPI.turbo) {
+```js
+if(gamepadAPI.turbo) {
   if(gamepadAPI.buttonPressed('A','hold')) {
     this.turbo_fire();
   }
   if(gamepadAPI.buttonPressed('B')) {
     this.managePause();
   }
-}
+} +``` -

如果 gamepadAPI.turbotrue 并有按钮被按下 (或被按住),我们就会为其分配恰当的操作。在本例中,按下或按住 A 开火,按下 B 暂停游戏。

+如果 `gamepadAPI.turbo` 为 `true` 并有按钮被按下 (或被按住),我们就会为其分配恰当的操作。在本例中,按下或按住 `A` 开火,按下 `B` 暂停游戏。 -

坐标阈值

+### 坐标阈值 -

按钮只有两种状态:01,但是摇杆可以有许多不同的值——他们在 XY 轴上都有一个范围为 -11 的浮点值。

+按钮只有两种状态:`0` 或 `1`,但是摇杆可以有许多不同的值——他们在 `X` 和 `Y` 轴上都有一个范围为 `-1` 到 `1` 的浮点值。 -

控制器放在一边不活动时轴值也可能有一定波动 (get dusty) ,这也就是说通过判断等于绝对的 -1 或 1 来可能是会有问题的。因此对此最好是给轴值设定一个阈值来触发生效。比如说,“冰箱坦克”仅会在 X 值大于 0.5 的时候向右转:

+控制器放在一边不活动时轴值也可能有一定波动 (get dusty) ,这也就是说通过判断等于绝对的 -1 或 1 来可能是会有问题的。因此对此最好是给轴值设定一个阈值来触发生效。比如说,“冰箱坦克”仅会在 `X` 值大于 `0.5` 的时候向右转: -
if(gamepadAPI.axesStatus[0].x > 0.5) {
-  this.player.angle += 3;
-  this.turret.angle += 3;
-}
+ if(gamepadAPI.axesStatus[0].x > 0.5) { + this.player.angle += 3; + this.turret.angle += 3; + } -

即使我们稍微误推摇杆或者摇杆没有弹回原始位置,“冰箱坦克”也不会意外转向。

+即使我们稍微误推摇杆或者摇杆没有弹回原始位置,“冰箱坦克”也不会意外转向。 -

规范更新

+## 规范更新 -

经过长达一年多的规范化,W3C Gamepaf API 于 2015 年 4 月更新了规范 (查看最新信息)。更新的改动并不是很大,但是我们最好了解一下到底更新了些什么—— 以下为更新。

+经过长达一年多的规范化,W3C Gamepaf API 于 2015 年 4 月更新了规范 ([查看最新信息](https://w3c.github.io/gamepad/))。更新的改动并不是很大,但是我们最好了解一下到底更新了些什么—— 以下为更新。 -

获取控制器

+### 获取控制器 -

{{domxref("Naviagator.getGamepads()")}} 方法已用更长的说明和示例代码更新。现在控制器数组的长度必须为 n+1 ( n 是已连接设备的数量) —— 当设备连接且其有索引 1,数组长度为 2,那么它将会是这样: [null, [object Gamepad]]。如果设备被断开或不可用的话,值将被设为 null

+{{domxref("Naviagator.getGamepads()")}} 方法已用[更长的说明和示例代码](https://w3c.github.io/gamepad/#navigator-interface-extension)更新。现在控制器数组的长度必须为 `n+1` ( `n` 是已连接设备的数量) —— 当设备连接且其有索引 1,数组长度为 2,那么它将会是这样: `[null, [object Gamepad]]`。如果设备被断开或不可用的话,值将被设为 `null`。 -

映射标准

+### 映射标准 -

布局类型现在是一个可枚举的对象而不是字符串:

+布局类型现在是一个可枚举的对象而不是字符串: -
enum GamepadMappingType {
-    "",
-    "standard"
-};
+ enum GamepadMappingType { + "", + "standard" + }; -

此枚举中定义了已知的控制器映射集。目前只有 standard 布局可用,但是未来可能会有新的布局。如果布局未知,那么将会是空字符串。

+此枚举中定义了已知的控制器映射集。目前只有 `standard` 布局可用,但是未来可能会有新的布局。如果布局未知,那么将会是空字符串。 -

事件

+### 事件 -

除了当前可用的 gamepadconnectedgamepaddisconnected 事件,其实还有其它事件也曾在规范中,但它们因为不是非常的有用所以被移出了规范。相关讨论仍在进行中,关于它们是否应该恢复规范,以及以什么形式恢复。

+除了当前可用的 `gamepadconnected` 和 `gamepaddisconnected` 事件,其实还有其它事件也曾在规范中,但它们因为不是非常的有用所以被移出了规范。相关讨论仍在进行中,关于它们是否应该恢复规范,以及以什么形式恢复。 -

总结

+## 总结 -

Gamepad API 非常易于开发。现在它比以往更容易向浏览器提供游戏主机的体验而不需要任何插件。你可以直接在你的浏览器中游玩完整的 Hungry Fridge 游戏。你可以从 Firefox Marketplace 中安装,或者可以在 Gamepad API Content Kit 中查看示例源代码。

+Gamepad API 非常易于开发。现在它比以往更容易向浏览器提供游戏主机的体验而不需要任何插件。你可以直接在你的浏览器中游玩完整的 [Hungry Fridge](http://enclavegames.com/games/hungry-fridge/) 游戏。你可以从 [Firefox Marketplace](https://marketplace.firefox.com/app/hungry-fridge) 中安装,或者可以在 [Gamepad API Content Kit](https://github.com/EnclaveGames/Hungry-Fridge) 中查看示例源代码。 diff --git a/files/zh-cn/games/techniques/index.md b/files/zh-cn/games/techniques/index.md index 40269267843e54..09b5a00984bc1f 100644 --- a/files/zh-cn/games/techniques/index.md +++ b/files/zh-cn/games/techniques/index.md @@ -8,25 +8,21 @@ tags: - TopicStub translation_of: Games/Techniques --- -
{{GamesSidebar}}
+{{GamesSidebar}} -
-

这个页面为想要使用开放的网页技术来开发游戏的人列举出了必要的核心技术。

-
+这个页面为想要使用开放的网页技术来开发游戏的人列举出了必要的核心技术。 -
-
使用 asm.js 中的异步脚本
-
尤其在制作中大型游戏时,异步脚本是一项必备技术,你游戏中的 JavaScript 因此可以在主进程之外被编译,并被缓存以之后游戏的运行,这会带来显著的性能提升。这篇文章解释了如何做到。
-
Optimizing startup performance
-
How to make sure your game starts up quickly, smoothly, and without appearing to lock up the user's browser or device.
-
Using WebRTC peer-to-peer data channels
-
In addition to providing support for audio and video communication, WebRTC lets you set up peer-to-peer data channels to exchange text or binary data actively between your players. This article explains what this can do for you, and shows how to use libraries that make this easy.
-
Efficient animation for web games
-
This article covers techniques and advice for creating efficient animation for web games, with a slant towards supporting lower end devices such as mobile phones. We touch on CSS transitions and CSS animations, and JavaScript loops involving {{ domxref("window.requestAnimationFrame") }}.
-
Audio for Web Games
-
Audio is an important part of any game — it adds feedback and atmosphere. Web-based audio is maturing fast, but there are still many browser differences to negotiate. This article provides a detailed guide to implementing audio for web games, looking at what works currently across as wide a range of platforms as possible.
-
2D collision detection
-
A concise introduction to collision detection in 2D games.
-
Tilemaps
-
Tiles are a very popular technique in 2D games for building the game world. These articles provide an introduction to tilemaps and how to implement them with the Canvas API.
-
+- [使用 asm.js 中的异步脚本](/en-US/docs/Games/Techniques/Async_scripts) + - : 尤其在制作中大型游戏时,异步脚本是一项必备技术,你游戏中的 JavaScript 因此可以在主进程之外被编译,并被缓存以之后游戏的运行,这会带来显著的性能提升。这篇文章解释了如何做到。 +- [Optimizing startup performance](/en-US/docs/Apps/Developing/Optimizing_startup_performance) + - : How to make sure your game starts up quickly, smoothly, and without appearing to lock up the user's browser or device. +- [Using WebRTC peer-to-peer data channels](/en-US/docs/Games/WebRTC_data_channels) + - : In addition to providing support for audio and video communication, WebRTC lets you set up peer-to-peer data channels to exchange text or binary data actively between your players. This article explains what this can do for you, and shows how to use libraries that make this easy. +- [Efficient animation for web games](/en-US/docs/Games/Techniques/Efficient_animation_for_web_games) + - : This article covers techniques and advice for creating efficient animation for web games, with a slant towards supporting lower end devices such as mobile phones. We touch on CSS transitions and CSS animations, and JavaScript loops involving {{ domxref("window.requestAnimationFrame") }}. +- [Audio for Web Games](/en-US/docs/Games/Techniques/Audio_for_Web_Games) + - : Audio is an important part of any game — it adds feedback and atmosphere. Web-based audio is maturing fast, but there are still many browser differences to negotiate. This article provides a detailed guide to implementing audio for web games, looking at what works currently across as wide a range of platforms as possible. +- [2D collision detection](/en-US/docs/Games/Techniques/2D_collision_detection) + - : A concise introduction to collision detection in 2D games. +- [Tilemaps](/en-US/docs/Games/Techniques/Tilemaps) + - : Tiles are a very popular technique in 2D games for building the game world. These articles provide an introduction to tilemaps and how to implement them with the Canvas API. diff --git a/files/zh-cn/games/tools/index.md b/files/zh-cn/games/tools/index.md index c6276627d8c037..579ce15eb69da2 100644 --- a/files/zh-cn/games/tools/index.md +++ b/files/zh-cn/games/tools/index.md @@ -10,31 +10,24 @@ tags: - TopicStub translation_of: Games/Tools --- -
{{GamesSidebar}}
+{{GamesSidebar}} -
-

On this page you can find links to our game development tools articles, which eventually aims to cover frameworks, compilers, and debugging tools.

-
+On this page you can find links to our game development tools articles, which eventually aims to cover frameworks, compilers, and debugging tools. -
-
asm.js
-
asm.js is a very limited subset of the JavaScript language, which can be greatly optimized and run in an ahead-of-time (AOT) compiling engine for much faster performance than your typical JavaScript performance. This is, of course, great for games.
-
Emscripten
-
-

An LLVM to JavaScript compiler; with Emscripten, you can compile C++ and other languages that can compile to LLVM bytecode into high-performance JavaScript. This is a great tool for porting applications to the Web! There is a useful Emscripten tutorial available on the wiki. Note that we are aiming to cover Emscripten in its own section of MDN.

-
-
Gecko profiler
-
The Gecko profiler extension lets you profile your code to help figure out where your performance issues are so that you can make your game run at top speed.
-
Game engines and tools
-
A list of engines, templates and technologies useful to game developers.
-
Shumway
-
Shumway is a renderer for Adobe Flash built entirely in JavaScript, WebGL, etc., bridging the gap between Flash and web standards. This article shows how to make use of Shumway, and how to contribute fixes and bugs to the project.
-
Toolchain for developing and debugging games
-
How does this differ from normal web app debugging? What specialist tools are available? A lot of this is going to be covered by Will in tools, but here we should provide a kind of practical toolchain tutorial for debugging games, with links to Will's stuff: -
    -
  • Basic tools overview
  • -
  • Shader editor
  • -
  • Performance tools (still in production, estimated early 2014)
  • -
-
-
+- [asm.js](/en-US/docs/Games/Tools/asm.js) + - : asm.js is a very limited subset of the JavaScript language, which can be greatly optimized and run in an ahead-of-time (AOT) compiling engine for much faster performance than your typical JavaScript performance. This is, of course, great for games. +- [Emscripten](https://github.com/kripken/emscripten/wiki) + - : An LLVM to JavaScript compiler; with Emscripten, you can compile C++ and other languages that can compile to LLVM bytecode into high-performance JavaScript. This is a great tool for porting applications to the Web! There is a [useful Emscripten tutorial](https://github.com/kripken/emscripten/wiki/Tutorial) available on the wiki. Note that we are [aiming to cover Emscripten in its own section of MDN](/en-US/docs/Emscripten). +- [Gecko profiler](https://addons.mozilla.org/en-us/firefox/addon/gecko-profiler/) + - : The Gecko profiler extension lets you profile your code to help figure out where your performance issues are so that you can make your game run at top speed. +- [Game engines and tools](/en-US/docs/Games/Tools/Engines_and_tools) + - : A list of engines, templates and technologies useful to game developers. +- [Shumway](/en-US/docs/Mozilla/Projects/Shumway) + - : Shumway is a renderer for Adobe Flash built entirely in JavaScript, WebGL, etc., bridging the gap between Flash and web standards. This article shows how to make use of Shumway, and how to contribute fixes and bugs to the project. +- Toolchain for developing and debugging games + + - : How does this differ from normal web app debugging? What specialist tools are available? A lot of this is going to be covered by Will in [tools](/en-US/docs/Tools), but here we should provide a kind of practical toolchain tutorial for debugging games, with links to Will's stuff: + + - Basic tools overview + - [Shader editor](/en-US/docs/Tools/Shader_Editor) + - Performance tools (still in production, estimated early 2014) diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/animations_and_tweens/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/animations_and_tweens/index.md index 741788b4092568..fa46da20f011ad 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/animations_and_tweens/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/animations_and_tweens/index.md @@ -13,103 +13,103 @@ tags: - tween translation_of: Games/Tutorials/2D_breakout_game_Phaser/Animations_and_tweens --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Extra_lives", "Games/Workflows/2D_Breakout_game_Phaser/Buttons")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Extra_lives", "Games/Workflows/2D_Breakout_game_Phaser/Buttons")}} -
-

这是Gamedev Phaser 教程 16 的第 14 步。您可以在Gamedev-Phaser-Content-Kit / demos / lesson14.html完成本课程后找到源代码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第 14 步**。您可以在[Gamedev-Phaser-Content-Kit / demos / lesson14.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson14.html)完成本课程后找到源代码。 -

为了使游戏看起来更加多汁和活泼,我们可以使用动画和补间。这将导致更好,更有趣的体验。让我们来探讨如何在游戏中实现 Phaser 动画和补间。

+为了使游戏看起来更加多汁和活泼,我们可以使用动画和补间。这将导致更好,更有趣的体验。让我们来探讨如何在游戏中实现 Phaser 动画和补间。 -

动画

+## 动画 -

在 Phaser,动画中,涉及从外部来源获取 spritesheet 并依次显示 sprites。作为一个例子,当碰到一些东西时,我们会让球摇摆。

+在 Phaser,动画中,涉及从外部来源获取 spritesheet 并依次显示 sprites。作为一个例子,当碰到一些东西时,我们会让球摇摆。 -

首先,从 Github 抓取 spritesheet并将其保存在您的/img目录中。

+首先,[从 Github 抓取 spritesheet](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/img/wobble.png)并将其保存在您的`/img`目录中。 -

接下来,我们将加载 spritesheet - 将以下行放在preload()函数的底部:

+接下来,我们将加载 spritesheet - 将以下行放在`preload()`函数的底部: -
game.load.spritesheet('ball', 'img/wobble.png', 20, 20);
-
+```js +game.load.spritesheet('ball', 'img/wobble.png', 20, 20); +``` -

而不是加载单个图像的球,我们可以加载整个 spritesheet - 不同图像的集合。我们将按顺序显示精灵,创造动画的幻觉。该spritesheet()方法的两个额外的表格确定给定 spritesheet 文件中每个单个框架的宽度和高度,指示程序如何切割以获取单个框架。

+而不是加载单个图像的球,我们可以加载整个 spritesheet - 不同图像的集合。我们将按顺序显示精灵,创造动画的幻觉。该`spritesheet()`方法的两个额外的表格确定给定 spritesheet 文件中每个单个框架的宽度和高度,指示程序如何切割以获取单个框架。 -

加载动画

+## 加载动画 -

接下来,进入你的 create() 函数,找到加载球精灵的行,下面的调用animations.add()如下所示:

+接下来,进入你的 create() 函数,找到加载球精灵的行,下面的调用`animations.add()`如下所示: -
ball = game.add.sprite(50, 250, 'ball');
+```js
+ball = game.add.sprite(50, 250, 'ball');
 ball.animations.add('wobble', [0,1,0,2,0,1,0,2,0], 24);
-
+``` -

要向对象添加动画,我们使用该animations.add()方法,其中包含以下参数

+要向对象添加动画,我们使用该`animations.add()`方法,其中包含以下参数 -
    -
  • 我们为动画选择的名称
  • -
  • 一个数组,定义在动画过程中显示帧的顺序。如果您再次查看wobble.png图像,您会看到有三个框架。Phaser 提取它们并将它们存储在数组中 - 位置 0,1 和 2.上面的数组表示我们显示帧 0,然后是 1,然后是 0 等。
  • -
  • 帧速率,以 fps 为单位。由于我们以 24fps 运行动画,有 9 帧,动画每秒将显示三次以下。
  • -
+- 我们为动画选择的名称 +- 一个数组,定义在动画过程中显示帧的顺序。如果您再次查看`wobble.png`图像,您会看到有三个框架。Phaser 提取它们并将它们存储在数组中 - 位置 0,1 和 2.上面的数组表示我们显示帧 0,然后是 1,然后是 0 等。 +- 帧速率,以 fps 为单位。由于我们以 24fps 运行动画,有 9 帧,动画每秒将显示三次以下。 -

当球击中桨时应用动画

+## 当球击中桨时应用动画 -

arcade.collide()处理球和桨(第一行内部update(),见下文)之间的碰撞的方法调用中,我们可以添加一个额外的参数,该参数指定每次发生碰撞时执行的功能,与该ballHitBrick()功能相同。更新内部的第一行update(),如下所示:

+在`arcade.collide()`处理球和桨(第一行内部`update()`,见下文)之间的碰撞的方法调用中,我们可以添加一个额外的参数,该参数指定每次发生碰撞时执行的功能,与该`ballHitBrick()`功能相同。更新内部的第一行`update()`,如下所示: -
function update() {
+```js
+function update() {
     game.physics.arcade.collide(ball, paddle, ballHitPaddle);
     game.physics.arcade.collide(ball, bricks, ballHitBrick);
     paddle.x = game.input.x || game.world.width*0.5;
 }
-
+``` -

然后我们可以创建ballHitPaddle()函数(具有ballpaddle作为默认参数),在调用时播放摆动动画。在结束</script>标签之前添加以下方法:

+然后我们可以创建`ballHitPaddle()`函数(具有`ball`和`paddle`作为默认参数),在调用时播放摆动动画。在结束``标签之前添加以下方法: -
function ballHitPaddle(ball, paddle) {
+```js
+function ballHitPaddle(ball, paddle) {
     ball.animations.play('wobble');
 }
-
+``` -

每次球击中桨时都会播放动画。你也可以animations.play()ballHitBrick()函数内添加调用,如果你觉得它会使游戏看起来更好。

+每次球击中桨时都会播放动画。你也可以`animations.play()`在`ballHitBrick()`函数内添加调用,如果你觉得它会使游戏看起来更好。 -

补间

+## 补间 -

而动画依次播放外部精灵,补间游戏中物体的属性平滑,如宽度或不透明度。

+而动画依次播放外部精灵,补间游戏中物体的属性平滑,如宽度或不透明度。 -

让我们在游戏中增加一个补间,使砖块在被球击中时顺利消失。转到您的ballhitBrick()功能,找到您的brick.kill();行,并将其替换为以下内容:

+让我们在游戏中增加一个补间,使砖块在被球击中时顺利消失。转到您的`ballhitBrick()`功能,找到您的`brick.kill();`行,并将其替换为以下内容: -
var killTween = game.add.tween(brick.scale);
+```js
+var killTween = game.add.tween(brick.scale);
 killTween.to({x:0,y:0}, 200, Phaser.Easing.Linear.None);
 killTween.onComplete.addOnce(function(){
     brick.kill();
 }, this);
 killTween.start();
-
+``` -

让我们来看看这里,看看这里发生了什么:

+让我们来看看这里,看看这里发生了什么: -
    -
  1. 当定义一个新的补间时,你必须指定哪些属性将被补间 - 在我们的例子中,而不是在被球击中时立即隐藏砖块,我们将把它们的宽度和高度缩放到零,所以它们将很好地消失。最后,我们使用该add.tween()方法,指定brick.scale为参数,因为这是我们想要补间。
  2. -
  3. to()方法定义补间结束时对象的状态。它需要一个包含所选参数的期望结束值的对象(比例取尺度值,1 为大小的 100%,0 为大小的 0%等),补间的时间(以毫秒为单位)以及使用的宽松类型补间。
  4. -
  5. 我们还将添加可选的onComplete事件处理程序,该处理程序定义了在补间程序完成时要执行的函数。
  6. -
  7. 最后一件事是立即开始补间start()
  8. -
+1. 当定义一个新的补间时,你必须指定哪些属性将被补间 - 在我们的例子中,而不是在被球击中时立即隐藏砖块,我们将把它们的宽度和高度缩放到零,所以它们将很好地消失。最后,我们使用该`add.tween()`方法,指定`brick.scale`为参数,因为这是我们想要补间。 +2. 该`to()`方法定义补间结束时对象的状态。它需要一个包含所选参数的期望结束值的对象(比例取尺度值,1 为大小的 100%,0 为大小的 0%等),补间的时间(以毫秒为单位)以及使用的宽松类型补间。 +3. 我们还将添加可选的`onComplete`事件处理程序,该处理程序定义了在补间程序完成时要执行的函数。 +4. 最后一件事是立即开始补间`start()`。 -

这是补间定义的扩展版本,但是我们也可以使用速记语法:

+这是补间定义的扩展版本,但是我们也可以使用速记语法: -
game.add.tween(brick.scale).to({x:2,y:2}, 500, Phaser.Easing.Elastic.Out, true, 100);
-
+```js +game.add.tween(brick.scale).to({x:2,y:2}, 500, Phaser.Easing.Elastic.Out, true, 100); +``` -

这个补间将使用弹性宽松在半秒内将砖的比例翻倍,将自动启动,延迟 100 毫秒。

+这个补间将使用弹性宽松在半秒内将砖的比例翻倍,将自动启动,延迟 100 毫秒。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/9o4pakrb/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/9o4pakrb/","","400")}} -

下一步

+## 下一步 -

动画和 tweens 看起来很不错,但我们可以添加更多的我们的游戏 - 在下一节我们将看看处理按钮输入。

+动画和 tweens 看起来很不错,但我们可以添加更多的我们的游戏 - 在下一节我们将看看处理[按钮](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Buttons)输入。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Extra_lives", "Games/Workflows/2D_Breakout_game_Phaser/Buttons")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Extra_lives", "Games/Workflows/2D_Breakout_game_Phaser/Buttons")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.md index ac6dd6f30c2dd4..4f9e476e1b2c8a 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.md @@ -12,38 +12,38 @@ tags: - bouncing translation_of: Games/Tutorials/2D_breakout_game_Phaser/Bounce_off_the_walls --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Physics", "Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Physics", "Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls")}} -
-

这是Gamedev Phaser 教程 6 。在Gamedev-Phaser-Content-Kit / demos / lesson06.html完成本课后,您可以找到源代码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser)的**第** 6 **步**。在[Gamedev-Phaser-Content-Kit / demos / lesson06.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson06.html)完成本课后,您可以找到源代码。 -

现在已经介绍了物理引擎,我们可以开始在游戏中实现碰撞检测 - 首先我们来看看墙壁。

+现在已经介绍了物理引擎,我们可以开始在游戏中实现碰撞检测 - 首先我们来看看墙壁。 -

反弹边界

+## 反弹边界 -

让我们的球从墙壁上弹起的最简单的方法是告诉框架,我们想要将元素可用于通过脚本(通常为JavaScript)绘制图形。 例如,它可以用于绘制图形,制作照片,甚至执行动画。 您可以(并且应该)在<canvas>块内提供备用内容。 该内容将在不支持画布的旧浏览器和禁用JavaScript的浏览器中呈现。"><canvas>元素的边界视为墙壁,而不是让球移过它们。在 Phaser 中,可以使用该collideWorldsBound属性轻松实现。在现有game.physics.enable()方法调用之后添加此行:

+让我们的球从墙壁上弹起的最简单的方法是告诉框架,我们想要将[元素可用于通过脚本(通常为 JavaScript)绘制图形。 例如,它可以用于绘制图形,制作照片,甚至执行动画。 您可以(并且应该)在\块内提供备用内容。 该内容将在不支持画布的旧浏览器和禁用 JavaScript 的浏览器中呈现。">``](/en-US/docs/Web/HTML/Element/canvas)元素的边界视为墙壁,而不是让球移过它们。在 Phaser 中,可以使用该`collideWorldsBound`属性轻松实现。在现有`game.physics.enable()`方法调用之后添加此行: -
ball.body.collideWorldBounds = true;
-
+```js +ball.body.collideWorldBounds = true; +``` -

现在球将停在屏幕的边缘,而不是消失,但它不会弹起。为了使这种情况发生,我们必须设置它的 bounciness。在上一行下面添加以下行:

+现在球将停在屏幕的边缘,而不是消失,但它不会弹起。为了使这种情况发生,我们必须设置它的 bounciness。在上一行下面添加以下行: -
ball.body.bounce.set(1);
-
+```js +ball.body.bounce.set(1); +``` -

再次尝试重新加载 index.html - 现在您应该看到球从墙壁上弹起并在画布区域内移动。

+再次尝试重新加载 index.html - 现在您应该看到球从墙壁上弹起并在画布区域内移动。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/dcw36opz/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/dcw36opz/","","400")}} -

下一步

+## 下一步 -

现在开始看起来更像是一个游戏,但是我们无法以任何方式控制它 - 现在是介绍玩家挡板和控制的时候了

+现在开始看起来更像是一个游戏,但是我们无法以任何方式控制它 - 现在是介绍[玩家挡板和控制的时候了](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls)。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Physics", "Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Physics", "Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.md index 33f0a00c8395dd..00c1bd14713669 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.md @@ -11,52 +11,54 @@ tags: - Tutorial translation_of: Games/Tutorials/2D_breakout_game_Phaser/Build_the_brick_field --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Game_over", "Games/Workflows/2D_Breakout_game_Phaser/Collision_detection")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Game_over", "Games/Workflows/2D_Breakout_game_Phaser/Collision_detection")}} -
-

这是Gamedev Phaser 教程 16 的第 9 步。在Gamedev-Phaser-Content-Kit / demos / lesson09.html完成本课后,您可以找到源代码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第 9 步**。在[Gamedev-Phaser-Content-Kit / demos / lesson09.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson09.html)完成本课后,您可以找到源代码。 -

建立砖块比将单个对象添加到屏幕要复杂一点,尽管使用 Phaser 还是比纯 JavaScript 更容易。我们来探讨如何创建一组砖块,并使用循环在屏幕上打印。

+建立砖块比将单个对象添加到屏幕要复杂一点,尽管使用 Phaser 还是比纯 JavaScript 更容易。我们来探讨如何创建一组砖块,并使用循环在屏幕上打印。 -

定义新变量

+## 定义新变量 -

首先,我们定义所需的变量 - 在以前的变量定义中添加以下内容:

+首先,我们定义所需的变量 - 在以前的变量定义中添加以下内容: -
var bricks;
+```js
+var bricks;
 var newBrick;
 var brickInfo;
-
+``` -

bricks变量将用于创建一个组,newBrick将在循环的每次迭代中添加到组中的新对象,brickInfo并将存储我们需要的所有数据。

+该`bricks`变量将用于创建一个组,`newBrick`将在循环的每次迭代中添加到组中的新对象,`brickInfo`并将存储我们需要的所有数据。 -

渲染砖图像

+## 渲染砖图像 -

接下来,我们加载砖的图像 - load.image()在其他地方添加以下调用:

+接下来,我们加载砖的图像 - `load.image()`在其他地方添加以下调用: -
function preload() {
+```js
+function preload() {
     // ...
     game.load.image('brick', 'img/brick.png');
 }
-
+``` -

您还需要从 Github 抓取砖图像并将其保存在您的/img目录中。

+您还需要[从 Github 抓取砖图像](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/img/brick.png)并将其保存在您的`/img`目录中。 -

画砖

+## 画砖 -

我们将将所有用于绘制砖块的代码放在一个initBricks函数中,以使其与其余代码分离。initBrickscreate()函数末尾添加一个调用:

+我们将将所有用于绘制砖块的代码放在一个`initBricks`函数中,以使其与其余代码分离。`initBricks`在`create()`函数末尾添加一个调用: -
function create(){
+```js
+function create(){
     // ...
     initBricks();
 }
-
+``` -

现在到函数本身。initBricks()在我们的游戏代码末尾添加功能,就在关闭</ script>标签之前,如下所示。首先我们已经包括了这个 brickInfo对象,因为这很快就会派上用场:

+现在到函数本身。`initBricks()`在我们的游戏代码末尾添加功能,就在关闭\标签之前,如下所示。首先我们已经包括了这个 `brickInfo`对象,因为这很快就会派上用场: -
function initBricks() {
+```js
+function initBricks() {
     brickInfo = {
         width: 50,
         height: 20,
@@ -71,28 +73,31 @@ var brickInfo;
         padding: 10
     };
 }
-
+``` -

这个brickInfo对象将包含我们需要的所有信息:单个砖的宽度和高度,我们将在屏幕上看到的砖的行数和列数,顶部和左边的偏移量(画布上我们将开始绘制的位置)砖块)和每一列和砖块之间的填充。

+这个`brickInfo`对象将包含我们需要的所有信息:单个砖的宽度和高度,我们将在屏幕上看到的砖的行数和列数,顶部和左边的偏移量(画布上我们将开始绘制的位置)砖块)和每一列和砖块之间的填充。 -

现在,让我们开始创建砖块 - 首先添加一个空组来包含砖块,在initBricks()函数底部添加以下行:

+现在,让我们开始创建砖块 - 首先添加一个空组来包含砖块,在`initBricks()`函数底部添加以下行: -
bricks = game.add.group();
-
+```js +bricks = game.add.group(); +``` -

我们可以循环遍历行和列,以便在每次迭代中创建新的砖块 - 在上一行代码下面添加以下嵌套循环:

+我们可以循环遍历行和列,以便在每次迭代中创建新的砖块 - 在上一行代码下面添加以下嵌套循环: -
for(c=0; c<brickInfo.count.col; c++) {
-    for(r=0; r<brickInfo.count.row; r++) {
+```js
+for(c=0; c
+```
 
-

这样我们将创建我们需要的确切数量的砖,并将它们全部包含在一个组中。现在我们需要在嵌套循环结构中添加一些代码来绘制每个砖块。填写内容如下图所示:

+这样我们将创建我们需要的确切数量的砖,并将它们全部包含在一个组中。现在我们需要在嵌套循环结构中添加一些代码来绘制每个砖块。填写内容如下图所示: -
for(c=0; c<brickInfo.count.col; c++) {
-    for(r=0; r<brickInfo.count.row; r++) {
+```js
+for(c=0; c
+```
 
-

在这里,我们循环遍历行和列,创建新的砖块并将其放在屏幕上。新创建的砖块为 Arcade 物理引擎启用,它的身体被设置为不可移动(所以当球被击中时它不会移动),我们还将锚点放在中间并添加砖到集团。

+在这里,我们循环遍历行和列,创建新的砖块并将其放在屏幕上。新创建的砖块为 Arcade 物理引擎启用,它的身体被设置为不可移动(所以当球被击中时它不会移动),我们还将锚点放在中间并添加砖到集团。 -

目前的问题是,我们在一个地方绘制所有的砖,坐标(0,0)。我们需要做的是将每个砖块绘制在自己的 x 和 y 位置。更新brickXbrickY行如下:

+目前的问题是,我们在一个地方绘制所有的砖,坐标(0,0)。我们需要做的是将每个砖块绘制在自己的 x 和 y 位置。更新`brickX`和`brickY`行如下: -
var brickX = (r*(brickInfo.width+brickInfo.padding))+brickInfo.offset.left;
+```js
+var brickX = (r*(brickInfo.width+brickInfo.padding))+brickInfo.offset.left;
 var brickY = (c*(brickInfo.height+brickInfo.padding))+brickInfo.offset.top;
-
+``` -

每个brickX位置都是brickInfo.widthbrickInfo.padding号乘以行号r,加上brickInfo.offset.left; 用于所述逻辑brickY是不同之处在于它使用的值列号相同cbrickInfo.heightbrickInfo.offset.top。现在每个砖都可以放置在正确的位置,每个砖块之间填充,并从左侧和顶部画布边缘偏移绘制。

+每个`brickX`位置都是`brickInfo.width`加`brickInfo.padding`号乘以行号`r`,加上`brickInfo.offset.left`; 用于所述逻辑`brickY`是不同之处在于它使用的值列号相同`c`,`brickInfo.height`和`brickInfo.offset.top`。现在每个砖都可以放置在正确的位置,每个砖块之间填充,并从左侧和顶部画布边缘偏移绘制。 -

检查 initBricks() 代码

+## 检查 initBricks() 代码 -

这是功能的完整代码initBricks()

+这是功能的完整代码`initBricks()`: -
function initBricks() {
+```js
+function initBricks() {
     brickInfo = {
         width: 50,
         height: 20,
@@ -133,8 +140,8 @@ var brickY = (c*(brickInfo.height+brickInfo.padding))+brickInfo.offset.top;
         padding: 10
     }
     bricks = game.add.group();
-    for(c=0; c<brickInfo.count.col; c++) {
-        for(r=0; r<brickInfo.count.row; r++) {
+    for(c=0; c
+```
 
-

如果您现在重新加载index.html,您应该看到在屏幕上打印的砖块彼此相距甚远。

+如果您现在重新加载`index.html`,您应该看到在屏幕上打印的砖块彼此相距甚远。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/cck2b9e8/","","400")}} -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/cck2b9e8/","","400")}}

+## 下一步 -

下一步

+有些东西丢失了 球不经停,经过砖块 - 我们需要适当的[碰撞检测](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Collision_detection)。 -

有些东西丢失了 球不经停,经过砖块 - 我们需要适当的碰撞检测

- -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Game_over", "Games/Workflows/2D_Breakout_game_Phaser/Collision_detection")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Game_over", "Games/Workflows/2D_Breakout_game_Phaser/Collision_detection")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/buttons/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/buttons/index.md index e66de3e1dea66d..385878e02e4e54 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/buttons/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/buttons/index.md @@ -12,93 +12,92 @@ tags: - Tutorial translation_of: Games/Tutorials/2D_breakout_game_Phaser/Buttons --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens", "Games/Workflows/2D_Breakout_game_Phaser/Randomizing_gameplay")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens", "Games/Workflows/2D_Breakout_game_Phaser/Randomizing_gameplay")}} -
-

这是Gamedev Phaser 教程 16 的第 15 步。您可以在Gamedev-Phaser-Content-Kit / demos / lesson15.html完成本课程后找到源代码

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第 15 步**。您可以在[Gamedev-Phaser-Content-Kit / demos / lesson15.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson15.html)完成本课程后找到源代码 -

而不是立即开始游戏,我们可以通过添加他们可以按的开始按钮将该决定留给玩家。我们来调查如何做到这一点。

+而不是立即开始游戏,我们可以通过添加他们可以按的开始按钮将该决定留给玩家。我们来调查如何做到这一点。 -

新变量

+## 新变量 -

我们需要一个变量来存储表示游戏当前是否正在播放的布尔值,另一个代表我们的按钮。将以下行添加到其他变量定义之下:

+我们需要一个变量来存储表示游戏当前是否正在播放的布尔值,另一个代表我们的按钮。将以下行添加到其他变量定义之下: -
var playing = false;
+```js
+var playing = false;
 var startButton;
-
+``` -

加载按钮 spritesheet

+## 加载按钮 spritesheet -

我们可以加载按钮 spritesheet 与我们加载球的摆动动画相同的方式。将以下内容添加到preload()函数底部:

+我们可以加载按钮 spritesheet 与我们加载球的摆动动画相同的方式。将以下内容添加到`preload()`函数底部: -
game.load.spritesheet('button', 'img/button.png', 120, 40);
-
+```js +game.load.spritesheet('button', 'img/button.png', 120, 40); +``` -

单个按钮框架宽 120 像素,高 40 像素。

+单个按钮框架宽 120 像素,高 40 像素。 -

您还需要从 Github 抓取按钮 spritesheet,并将其保存在您的/img目录中。

+您还需要[从 Github 抓取按钮 spritesheet](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/img/button.png),并将其保存在您的`/img`目录中。 -

将按钮添加到游戏中

+## 将按钮添加到游戏中 -

使用该add.button方法可以将新的按钮添加到游戏中。将以下行添加到create()函数的底部:

+使用该`add.button`方法可以将新的按钮添加到游戏中。将以下行添加到`create()`函数的底部: -
startButton = game.add.button(game.world.width*0.5, game.world.height*0.5, 'button', startGame, this, 1, 0, 2);
+```js
+startButton = game.add.button(game.world.width*0.5, game.world.height*0.5, 'button', startGame, this, 1, 0, 2);
 startButton.anchor.set(0.5);
-
+``` -

button()方法的参数如下:

+该`button()`方法的参数如下: -
    -
  • 按钮的 x 和 y 坐标
  • -
  • 要显示按钮的图形资产的名称
  • -
  • 按下按钮时将执行的回调函数
  • -
  • this指定执行上下文的引用
  • -
  • 将用于过度超出向下事件的框架。
  • -
+- 按钮的 x 和 y 坐标 +- 要显示按钮的图形资产的名称 +- 按下按钮时将执行的回调函数 +- `this`指定执行上下文的引用 +- 将用于*过度*,*超出*和*向下*事件的框架。 -
-

备注: 超越事件与悬停相同,当指针从按钮中移出时,当按下按钮时,向下移动。

-
+> **备注:** 超越事件与悬停相同,当指针从按钮中移出时,当按下按钮时,向下移动。 -

现在我们需要定义startGame()上面代码中引用的函数:

+现在我们需要定义`startGame()`上面代码中引用的函数: -
function startGame() {
+```js
+function startGame() {
     startButton.destroy();
     ball.body.velocity.set(150, -150);
     playing = true;
 }
-
+``` -

当按下按钮时,我们删除按钮,设置球的初始速度并将playing变量设置为true

+当按下按钮时,我们删除按钮,设置球的初始速度并将`playing`变量设置为`true`。 -

最后对于这一部分,回到你的create()函数,找到ball.body.velocity.set(150, -150);一行,并删除它。你只需要按下按钮时移动球,而不是之前!

+最后对于这一部分,回到你的`create()`函数,找到`ball.body.velocity.set(150, -150);`一行,并删除它。你只需要按下按钮时移动球,而不是之前! -

在游戏开始之前仍然保持桨

+## 在游戏开始之前仍然保持桨 -

它按预期工作,但是当游戏尚未开始时,我们仍然可以移动桨,这看起来有点愚蠢。为了阻止这一点,我们可以利用playing变量,使得桨只有在游戏开始时才能移动。要做到这一点,调整update()功能如下所示:

+它按预期工作,但是当游戏尚未开始时,我们仍然可以移动桨,这看起来有点愚蠢。为了阻止这一点,我们可以利用`playing`变量,使得桨只有在游戏开始时才能移动。要做到这一点,调整`update()`功能如下所示: -
function update() {
+```js
+function update() {
     game.physics.arcade.collide(ball, paddle, ballHitPaddle);
     game.physics.arcade.collide(ball, bricks, ballHitBrick);
     if(playing) {
         paddle.x = game.input.x || game.world.width*0.5;
     }
 }
-
+``` -

这样一来,在所有的装载和准备之后,但在实际游戏开始之前,桨是不可移动的。

+这样一来,在所有的装载和准备之后,但在实际游戏开始之前,桨是不可移动的。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/1rpj71k4/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/1rpj71k4/","","400")}} -

下一步

+## 下一步 -

在本系列文章中我们将做的最后一件事情是,通过添加一些随机化的方式,球从球上弹起来,使游戏更有趣。

+在本系列文章中我们将做的最后一件事情是,通过添加一些[随机化](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Randomizing_gameplay)的方式,球从球上弹起来,使游戏更有趣。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens", "Games/Workflows/2D_Breakout_game_Phaser/Randomizing_gameplay")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens", "Games/Workflows/2D_Breakout_game_Phaser/Randomizing_gameplay")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/collision_detection/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/collision_detection/index.md index b998249781fa14..c69521972682a5 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/collision_detection/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/collision_detection/index.md @@ -12,48 +12,48 @@ tags: - collision detection translation_of: Games/Tutorials/2D_breakout_game_Phaser/Collision_detection --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_Phaser/The_score")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_Phaser/The_score")}} -
-

这是Gamedev Phaser 教程 16 的第 10 步。您可以在Gamedev-Phaser-Content-Kit / demos / lesson10.html完成本课程后找到源代码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第 10 步**。您可以在[Gamedev-Phaser-Content-Kit / demos / lesson10.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson10.html)完成本课程后找到源代码。 -

现在接下来的挑战 - 球和砖块之间的碰撞检测。幸运的是,我们可以使用物理引擎来检查单个对象(如球和桨)之间的碰撞,也可以检测对象和组之间的碰撞。

+现在接下来的挑战 - 球和砖块之间的碰撞检测。幸运的是,我们可以使用物理引擎来检查单个对象(如球和桨)之间的碰撞,也可以检测对象和组之间的碰撞。 -

砖/球碰撞检测

+## 砖/球碰撞检测 -

物理引擎使一切都变得更容易 - 我们只需要添加两个简单的代码。首先,在你的update()函数中添加一行,检查球和砖之间的碰撞检测,如下所示:

+物理引擎使一切都变得更容易 - 我们只需要添加两个简单的代码。首先,在你的`update()`函数中添加一行,检查球和砖之间的碰撞检测,如下所示: -
function update() {
+```js
+function update() {
     game.physics.arcade.collide(ball, paddle);
     game.physics.arcade.collide(ball, bricks, ballHitBrick);
     paddle.x = game.input.x || game.world.width*0.5;
 }
-
+``` -

球的位置是根据组中所有砖的位置计算的。第三个可选参数是发生冲突时执行的功能ballHitBrick()。创建这个新功能作为代码的底部,就在结束</script>标签之前,如下所示:

+球的位置是根据组中所有砖的位置计算的。第三个可选参数是发生冲突时执行的功能`ballHitBrick()`。创建这个新功能作为代码的底部,就在结束``标签之前,如下所示: -
function ballHitBrick(ball, brick) {
+```js
+function ballHitBrick(ball, brick) {
     brick.kill();
 }
-
+``` -

就是这样!重新加载你的代码,你应该看到新的碰撞检测工作正常。

+就是这样!重新加载你的代码,你应该看到新的碰撞检测工作正常。 -

感谢 Phaser,有两个参数传递给函数 - 第一个是球,我们在碰撞方法中明确定义,第二个是球碰撞的砖组中的单个砖。在功能内部,我们从屏幕上删除所讨论的砖块,只需运行其kill()上的方法即可。

+感谢 Phaser,有两个参数传递给函数 - 第一个是球,我们在碰撞方法中明确定义,第二个是球碰撞的砖组中的单个砖。在功能内部,我们从屏幕上删除所讨论的砖块,只需运行其`kill()`上的方法即可。 -

您将期望在使用纯 JavaScript时编写更多自己的计算机来实现碰撞检测。这是使用框架的好处 - 您可以为 Phaser 留下大量无聊的代码,并专注于制作游戏中最有趣和最有趣的部分。

+您将期望在使用[纯 JavaScript](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection)时编写更多自己的计算机来实现碰撞检测。这是使用框架的好处 - 您可以为 Phaser 留下大量无聊的代码,并专注于制作游戏中最有趣和最有趣的部分。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/wwneakwf/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/wwneakwf/","","400")}} -

下一步

+## 下一步 -

我们可以打砖块并删除它们,这已经是游戏的一个很好的补充。结果,更好地计算被毁砖增加得分

+我们可以打砖块并删除它们,这已经是游戏的一个很好的补充。结果,更好地计算被毁砖增加[得分](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/The_score)。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_Phaser/The_score")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_Phaser/The_score")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/extra_lives/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/extra_lives/index.md index e64b4aa4ec68e4..f920fe2c1ce384 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/extra_lives/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/extra_lives/index.md @@ -12,79 +12,84 @@ tags: - lives translation_of: Games/Tutorials/2D_breakout_game_Phaser/Extra_lives --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Win_the_game", "Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Win_the_game", "Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens")}} -
-

这是Gamedev Phaser 教程 16 的第 13 步。您可以在Gamedev-Phaser-Content-Kit / demos / lesson13.html完成本课程后找到源代码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第 13 步**。您可以在[Gamedev-Phaser-Content-Kit / demos / lesson13.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson13.html)完成本课程后找到源代码。 -

我们可以通过增加生活使游戏更愉快。在这篇文章中,我们将实施一个生活系统,以便玩家可以继续玩,直到他们失去了三个生命,而不仅仅是一个人。

+我们可以通过增加生活使游戏更愉快。在这篇文章中,我们将实施一个生活系统,以便玩家可以继续玩,直到他们失去了三个生命,而不仅仅是一个人。 -

新变量

+## 新变量 -

在代码中的现有添加下面添加以下新变量:

+在代码中的现有添加下面添加以下新变量: -
var lives = 3;
+```js
+var lives = 3;
 var livesText;
 var lifeLostText;
-
+``` -

这些分别将存储生命数,显示剩余生命数的文本标签,以及当玩家失去生命之后将在屏幕上显示的文本标签。

+这些分别将存储生命数,显示剩余生命数的文本标签,以及当玩家失去生命之后将在屏幕上显示的文本标签。 -

定义新的文本标签

+## 定义新的文本标签 -

定义文本看起来像我们已经在分数课上已经做scoreTextcreate()函数内的现有定义下方添加以下行:

+定义文本看起来像我们已经在[分数](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/The_score)课上已经做[的](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/The_score)。`scoreText`在`create()`函数内的现有定义下方添加以下行: -
livesText = game.add.text(game.world.width-5, 5, 'Lives: '+lives, { font: '18px Arial', fill: '#0095DD' });
+```js
+livesText = game.add.text(game.world.width-5, 5, 'Lives: '+lives, { font: '18px Arial', fill: '#0095DD' });
 livesText.anchor.set(1,0);
 lifeLostText = game.add.text(game.world.width*0.5, game.world.height*0.5, 'Life lost, click to continue', { font: '18px Arial', fill: '#0095DD' });
 lifeLostText.anchor.set(0.5);
 lifeLostText.visible = false;
-
+``` -

livesTextlifeLostText物体看起来非常相似的scoreText一个 - 它们定义在屏幕上的位置,显示实际文本和字体样式。前者被锚定在其右上边缘上,与屏幕正确对齐,后者位于中心位置,两者均使用anchor.set()

+在`livesText`与`lifeLostText`物体看起来非常相似的`scoreText`一个 - 它们定义在屏幕上的位置,显示实际文本和字体样式。前者被锚定在其右上边缘上,与屏幕正确对齐,后者位于中心位置,两者均使用`anchor.set()`。 -

lifeLostText会表示,只有当生命消失,因此其知名度初始设置为false

+该`lifeLostText`会表示,只有当生命消失,因此其知名度初始设置为`false`。 -

使我们的文字造型干燥

+### 使我们的文字造型干燥 -

正如你可能已经注意到,我们使用相同的造型为三种文本:scoreTextlivesTextlifeLostText。如果我们想要更改字体大小或颜色,我们必须在多个地方进行。为了使我们更容易维护,将来我们可以创建一个单独的变量来保存我们的样式,让我们textStyle将其调用并放在文本定义之前:

+正如你可能已经注意到,我们使用相同的造型为三种文本:`scoreText`,`livesText`和`lifeLostText`。如果我们想要更改字体大小或颜色,我们必须在多个地方进行。为了使我们更容易维护,将来我们可以创建一个单独的变量来保存我们的样式,让我们`textStyle`将其调用并放在文本定义之前: -
textStyle = { font: '18px Arial', fill: '#0095DD' };
-
+```js +textStyle = { font: '18px Arial', fill: '#0095DD' }; +``` -

现在我们可以在使用文本标签的时候使用这个变量 - 更新你的代码,使文本样式的多个实例被替换为变量:

+现在我们可以在使用文本标签的时候使用这个变量 - 更新你的代码,使文本样式的多个实例被替换为变量: -
scoreText = game.add.text(5, 5, 'Points: 0', textStyle);
+```js
+scoreText = game.add.text(5, 5, 'Points: 0', textStyle);
 livesText = game.add.text(game.world.width-5, 5, 'Lives: '+lives, textStyle);
 livesText.anchor.set(1,0);
 lifeLostText = game.add.text(game.world.width*0.5, game.world.height*0.5, 'Life lost, click to continue', textStyle);
 lifeLostText.anchor.set(0.5);
 lifeLostText.visible = false;
-
+``` -

这样一来,改变一个变量中的字体将会将更改应用于每个使用的地方。

+这样一来,改变一个变量中的字体将会将更改应用于每个使用的地方。 -

生活处理代码

+## 生活处理代码 -

为了在我们的游戏中实现生活,让我们先改变球对onOutOfBounds事件的影响。而不是执行匿名函数并立即显示警报:

+为了在我们的游戏中实现生活,让我们先改变球对`onOutOfBounds`事件的影响。而不是执行匿名函数并立即显示警报: -
ball.events.onOutOfBounds.add(function(){
+```js
+ball.events.onOutOfBounds.add(function(){
     alert('Game over!');
     location.reload();
-}, this);
-
+}, this); +``` -

我们将分配一个所谓的新功能ballLeaveScreen; 删除以前的事件处理程序(如上所示),并将其替换为以下行:

+我们将分配一个所谓的新功能`ballLeaveScreen`; 删除以前的事件处理程序(如上所示),并将其替换为以下行: -
ball.events.onOutOfBounds.add(ballLeaveScreen, this);
-
+```js +ball.events.onOutOfBounds.add(ballLeaveScreen, this); +``` -

我们想减少每次球离开帆布的人数。ballLeaveScreen()在代码末尾添加函数定义:

+我们想减少每次球离开帆布的人数。`ballLeaveScreen()`在代码末尾添加函数定义: -
function ballLeaveScreen() {
+```js
+function ballLeaveScreen() {
     lives--;
     if(lives) {
         livesText.setText('Lives: '+lives);
@@ -101,24 +106,24 @@ lifeLostText.visible = false;
         location.reload();
     }
 }
-
+``` -

而不是立即打印警报,当你失去了一生,我们首先从当前的数字减去一个生命,并检查它是否是一个非零值。如果是,那么玩家还是有一些生命剩下,可以继续玩 - 他们会看到生命中的消息,球和桨的位置将被重置在屏幕上和下一个输入(点击或触摸),消息将被隐藏球将再次开始移动。

+而不是立即打印警报,当你失去了一生,我们首先从当前的数字减去一个生命,并检查它是否是一个非零值。如果是,那么玩家还是有一些生命剩下,可以继续玩 - 他们会看到生命中的消息,球和桨的位置将被重置在屏幕上和下一个输入(点击或触摸),消息将被隐藏球将再次开始移动。 -

当可用生活数量达到零时,游戏结束,并显示游戏过期警报消息。

+当可用生活数量达到零时,游戏结束,并显示游戏过期警报消息。 -

事件

+## 事件 -

您可能已经注意到了add(),并addOnce()在上面的两个代码块的方法调用,并想知道它们的区别。不同之处在于,该add()方法绑定给定的函数,并使其在每次事件发生时执行,同时addOnce()当您希望绑定函数只执行一次,然后解除绑定时有用,因此不会再次执行。在我们的例子中,每个outOfBounds事件ballLeaveScreen都将被执行,但当球离开屏幕时,我们只想从屏幕上删除一次消息。

+您可能已经注意到了`add()`,并`addOnce()`在上面的两个代码块的方法调用,并想知道它们的区别。不同之处在于,该`add()`方法绑定给定的函数,并使其在每次事件发生时执行,同时`addOnce()`当您希望绑定函数只执行一次,然后解除绑定时有用,因此不会再次执行。在我们的例子中,每个`outOfBounds`事件`ballLeaveScreen`都将被执行,但当球离开屏幕时,我们只想从屏幕上删除一次消息。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/yk1c5n0b/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/yk1c5n0b/","","400")}} -

下一步

+## 下一步 -

生活让游戏更加宽容 - 如果你失去一个生命,你还剩下两个,可以继续玩。现在让我们通过添加动画和补间来扩展游戏的外观和感觉。

+生活让游戏更加宽容 - 如果你失去一个生命,你还剩下两个,可以继续玩。现在让我们通过添加[动画和补间来](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens)扩展游戏的外观和感觉。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Win_the_game", "Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Win_the_game", "Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/game_over/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/game_over/index.md index 1da360d301e3b5..bf8dc87ff2427c 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/game_over/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/game_over/index.md @@ -12,42 +12,42 @@ tags: - game over translation_of: Games/Tutorials/2D_breakout_game_Phaser/Game_over --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls", "Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls", "Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field")}} -
-

这是Gamedev Phaser 教程 16 的第 8 步。在Gamedev-Phaser-Content-Kit / demos / lesson08.html完成本课后,您可以找到源代码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第 8 步**。在[Gamedev-Phaser-Content-Kit / demos / lesson08.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson08.html)完成本课后,您可以找到源代码。 -

为了使游戏更有趣,我们可以引入失去的能力 - 如果在到达屏幕底部边缘之前没有击球,那么这个游戏将会结束。

+为了使游戏更有趣,我们可以引入失去的能力 - 如果在到达屏幕底部边缘之前没有击球,那么这个游戏将会结束。 -

如何输

+## 如何输 -

为了提供丢失的能力,我们将禁用球与屏幕底部的碰撞。在create()函数内添加下面的代码; 刚刚定义球的属性就好了:

+为了提供丢失的能力,我们将禁用球与屏幕底部的碰撞。在`create()`函数内添加下面的代码; 刚刚定义球的属性就好了: -
game.physics.arcade.checkCollision.down = false;
-
+```js +game.physics.arcade.checkCollision.down = false; +``` -

这将使三个墙壁(顶部,左侧和右侧)弹回球,但是第四个(底部)将消失,如果桨错过,则球从屏幕上脱落。我们需要一种方法来检测并相应地采取行动。在以前的新的下方添加以下行:

+这将使三个墙壁(顶部,左侧和右侧)弹回球,但是第四个(底部)将消失,如果桨错过,则球从屏幕上脱落。我们需要一种方法来检测并相应地采取行动。在以前的新的下方添加以下行: -
ball.checkWorldBounds = true;
+```js
+ball.checkWorldBounds = true;
 ball.events.onOutOfBounds.add(function(){
     alert('Game over!');
     location.reload();
 }, this);
-
+``` -

添加这些行将使得球检查世界(在我们的例子中是画布)边界并执行绑定到onOutOfBounds事件的函数。当您点击生成的警报时,页面将被重新加载,以便您可以再次播放。

+添加这些行将使得球检查世界(在我们的例子中是画布)边界并执行绑定到`onOutOfBounds`事件的函数。当您点击生成的警报时,页面将被重新加载,以便您可以再次播放。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/436bckb7/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/436bckb7/","","400")}} -

下一步

+## 下一步 -

现在的基本游戏就是让我们通过引入砖块来更有趣的是 - 现在是建造砖块的时候了。

+现在的基本游戏就是让我们通过引入砖块来更有趣的是 - 现在是[建造砖块](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field)的时候了。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls", "Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls", "Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/index.md index 25b434361b7cad..17738f096fe54c 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/index.md @@ -7,51 +7,47 @@ tags: - 游戏 translation_of: Games/Tutorials/2D_breakout_game_Phaser --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{Next("Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework")}}

+{{Next("Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework")}} -

在这个手把手的教程中,我们将使用 Phaser 框架制作一个使用 JavaScript 构建简单的 MDN 消除游戏。

+在这个手把手的教程中,我们将使用 Phaser 框架制作一个使用 JavaScript 构建简单的 MDN 消除游戏。 -

教程的每一步骤都会有可供修改的样品来玩,所以你可以看到开发的每一步中间步骤。您将学到如何使用 Phaser 框架来实现基础游戏机制的基本知识,诸如渲染和移动图像,碰撞检测,控制机制,框架特定的帮助器功能,动画和补间,以及获胜和失败状态等。

+教程的每一步骤都会有可供修改的样品来玩,所以你可以看到开发的每一步中间步骤。您将学到如何使用 Phaser 框架来实现基础游戏机制的基本知识,诸如渲染和移动图像,碰撞检测,控制机制,框架特定的帮助器功能,动画和补间,以及获胜和失败状态等。 -

为了充分理解这一系列的文章,您应该确保已有基本的中级 JavaScript 知识。学完本教程,您将有能力用 Phaser 构建简单的 Web 游戏。

+为了充分理解这一系列的文章,您应该确保已有基本的中级 JavaScript 知识。学完本教程,您将有能力用 Phaser 构建简单的 Web 游戏。 -

Gameplay screen from the game MDN Breakout created with Phaser where you can use your paddle to bounce the ball and destroy the brick field, with keeping the points and lives.

+![Gameplay screen from the game MDN Breakout created with Phaser where you can use your paddle to bounce the ball and destroy the brick field, with keeping the points and lives.](mdn-breakout-phaser.png) -

教学清单

+## 教学清单 -

所有的课程 — 以及我们接下来将一起做的各个版本的 MDN Breakout game 都能在 GitHub上找到

+所有的课程 — 以及我们接下来将一起做的各个版本的 [MDN Breakout game](https://end3r.github.io/Gamedev-Phaser-Content-Kit/demos/lesson16.html) 都能在 [GitHub](https://end3r.github.io/Gamedev-Phaser-Content-Kit/demos/)上找到 -
    -
  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. -
+1. [初始化框架](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework) +2. [缩放](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Scaling) +3. [加载资源并在屏幕上打印](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen) +4. [移动小球](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Move_the_ball) +5. [物理](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Physics) +6. [从墙上弹开](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls) +7. [弹块和控制](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls) +8. [游戏结束](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Game_over) +9. [建立砖块](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field) +10. [碰撞检测](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Collision_detection) +11. [得分](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/The_score) +12. [胜利](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Win_the_game) +13. [额外生命](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Extra_lives) +14. [动画与补间](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens) +15. [按钮](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Buttons) +16. [随机游戏](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Randomizing_gameplay) -

学习路线的小提示 — 最好先熟悉使用原生 JavaScript 进行网页游戏开发,这样可以打下坚实的基础。如果你还不熟悉原生 javascript 开发,我们建议你先过一遍这个系列,使用原生 Javascript 开发 MDN 消除游戏.

+学习路线的小提示 — 最好先熟悉使用原生 JavaScript 进行网页游戏开发,这样可以打下坚实的基础。如果你还不熟悉原生 javascript 开发,我们建议你先过一遍这个系列,[使用原生 Javascript 开发 MDN 消除游戏](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript). -

在那之后,你就能随意挑选框架并用在你的项目中;我们选择了 Phaser 这个稳定优越的框架,它有着好的支持和社区环境以及大量优秀的插件。框架加速了开发并能帮你管理无趣的部分,让你专注于有意思的事务。然而,框架也有不好的地方,所以当一些意想不到的事情发生了或者想实现一些框架没有提供的功能时,你就将需要原生的 JavaScript 知识了。

+在那之后,你就能随意挑选框架并用在你的项目中;我们选择了 Phaser 这个稳定优越的框架,它有着好的支持和社区环境以及大量优秀的插件。框架加速了开发并能帮你管理无趣的部分,让你专注于有意思的事务。然而,框架也有不好的地方,所以当一些意想不到的事情发生了或者想实现一些框架没有提供的功能时,你就将需要原生的 JavaScript 知识了。 -
-

备注: 本系列文章可用作实际游戏开发的材料。如果您想要使用 Phaser 讨论游戏开发,您还可以使用基于本教程的 Gamedev Phaser 内容套件.

-
+> **备注:** 本系列文章可用作实际游戏开发的材料。如果您想要使用 Phaser 讨论游戏开发,您还可以使用基于本教程的 [Gamedev Phaser 内容套件](https://github.com/end3r/Gamedev-Phaser-Content-Kit). -

Next steps

+## Next steps -

好了,那我们就开始吧!前往系列第一部分 — 初始化框架.

+好了,那我们就开始吧!前往系列第一部分 — [初始化框架](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework). -

{{Next("Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework")}}

+{{Next("Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.md index a64602491ee638..55783fa3f7f0f7 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.md @@ -12,79 +12,72 @@ tags: - 游戏 translation_of: Games/Tutorials/2D_breakout_game_Phaser/Initialize_the_framework --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser", "Games/Tutorials/2D_Breakout_game_Phaser/Scaling")}}

+{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser", "Games/Tutorials/2D_Breakout_game_Phaser/Scaling")}} -
-

这是Gamedev Phaser 教程系列的第一课。在课程完成之后,你可以在Gamedev-Phaser-Content-Kit/demos/lesson01.html找到源码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser)系列的第一课。在课程完成之后,你可以在[Gamedev-Phaser-Content-Kit/demos/lesson01.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson01.html)找到源码。 -

在我们开始写游戏的功能之前,我们需要创建一个用来内部渲染游戏的基础架构。使用 HTML 就能做到 — Parser 框架将生成所需的 {{htmlelement("canvas")}} 元素。

+在我们开始写游戏的功能之前,我们需要创建一个用来内部渲染游戏的基础架构。使用 HTML 就能做到 — Parser 框架将生成所需的 {{htmlelement("canvas")}} 元素。 -

游戏的 HTML

+## 游戏的 HTML -

HTML 文档结构非常的简单,这个游戏将整个被渲染在框架生成的{{htmlelement("canvas")}} 元素上。拿起你最爱的编辑器,挑一个好目录,创建一个 HTML 文档,存成 index.html,然后写下下面的代码:

+HTML 文档结构非常的简单,这个游戏将整个被渲染在框架生成的{{htmlelement("canvas")}} 元素上。拿起你最爱的编辑器,挑一个好目录,创建一个 HTML 文档,存成 index.html,然后写下下面的代码: -
<!DOCTYPE html>
-<html>
-<head>
-    <meta charset="utf-8" />
-    <title>Gamedev Phaser Workshop - lesson 01: Initialize the framework</title>
-    <style>* { padding: 0; margin: 0; }</style>
-    <script src="js/phaser.min.js"></script>
-</head>
-<body>
-<script>
+```html
+
+
+
+    
+    Gamedev Phaser Workshop - lesson 01: Initialize the framework
+    
+    
+
+
+
+
+
+```
 
-

下载 Phaser

+## 下载 Phaser -

下面我们将下载 Phaser 的代码,并应用到我们的 HTML 文档中。

+下面我们将下载 Phaser 的代码,并应用到我们的 HTML 文档中。 -
    -
  1. 进入 Phaser 下载页面.
  2. -
  3. 选择最适合你的下载项 — 我们建议选择 min.js,因为它最小,而且你不太可能想去看它的源码
  4. -
  5. 将 Phaser 的源码存到一个和 index.html 同级的 /js 的目录下
  6. -
  7. 在上面第一个 {{htmlelement("script")}} 标签里写下 phaser 的路径。
  8. -
+1. 进入 [Phaser 下载页面](http://phaser.io/download/stable). +2. 选择最适合你的下载项 — 我们建议选择 min.js,因为它最小,而且你不太可能想去看它的源码 +3. 将 Phaser 的源码存到一个和 index.html 同级的 /js 的目录下 +4. 在上面第一个 {{htmlelement("script")}} 标签里写下 phaser 的路径。 -

捋一捋我们干了些啥

+## 捋一捋我们干了些啥 -

这个时候我们在 {{htmlelement("header")}} 里定义了 {{htmlelement("charset")}} ,{{htmlelement("title")}} 和一些基础的 css 来重置默认的 margin 和 padding. 我们也用 {{htmlelement("script")}} 标签向页面引入了 Phaser 源码。{{htmlelement("body ")}} 里也有一个 {{htmlelement("script")}} 标签,我们将在里面写 JavaScript 代码来渲染和控制游戏。

+这个时候我们在 {{htmlelement("header")}} 里定义了 {{htmlelement("charset")}} ,{{htmlelement("title")}} 和一些基础的 css 来重置默认的 margin 和 padding. 我们也用 {{htmlelement("script")}} 标签向页面引入了 Phaser 源码。{{htmlelement("body ")}} 里也有一个 {{htmlelement("script")}} 标签,我们将在里面写 JavaScript 代码来渲染和控制游戏。 -

{{htmlelement("canvas")}} 元素是由框架自动生成的。我们是通过 Phaser.Game 创建一个对象并赋给了 game 变量来完成初始化的。参数的含义是:

+{{htmlelement("canvas")}} 元素是由框架自动生成的。我们是通过 `Phaser.Game `创建一个对象并赋给了 game 变量来完成初始化的。参数的含义是: -
    -
  • width 和 height 设置了 {{htmlelement("canvas")}} 宽高。
  • -
  • 渲染方式。有三个选项分别是 AUTO,CANVASWEBGL。我们可以指定使用 Canvas 还是 WebGL 来渲染,如果使用了 Auto 则优先使用 WebGL,如果浏览器不支持则会选择 Canvas。
  • -
  • {{htmlelement("canvas")}} 的 id。如果该参数有值,则使用该值作为 canvas 标签的 id,我们传入 null,则 phaser 会决定 canvas 的 id 值。
  • -
  • 第四个参数指定了 phaser 的三个生命周期所对应的函数。我们使用相同的名字来让程序更清晰 -
      -
    • preload 进行资源的加载。
    • -
    • create 会在资源加载完成后执行一次。
    • -
    • update 会一直循环执行来处理每一帧动画。
    • -
    -
  • -
+- width 和 height 设置了 {{htmlelement("canvas")}} 宽高。 +- 渲染方式。有三个选项分别是 ` AUTO,``CANVAS ` 和 `WEBGL`。我们可以指定使用 Canvas 还是 WebGL 来渲染,如果使用了 Auto 则优先使用 WebGL,如果浏览器不支持则会选择 Canvas。 +- {{htmlelement("canvas")}} 的 id。如果该参数有值,则使用该值作为 canvas 标签的 id,我们传入 null,则 phaser 会决定 canvas 的 id 值。 +- 第四个参数指定了 phaser 的三个生命周期所对应的函数。我们使用相同的名字来让程序更清晰 -

完整示例

+ - `preload` 进行资源的加载。 + - `create` 会在资源加载完成后执行一次。 + - `update` 会一直循环执行来处理每一帧动画。 -

以下是第一章的完整代码,可以直接在 JSFiddle 中运行:

+## 完整示例 -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/h6cwzv2b/","","400")}}

+以下是第一章的完整代码,可以直接在 JSFiddle 中运行: -

下一步

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/h6cwzv2b/","","400")}} -

现在我们已经完成了一个简单的 HTML 页面,并且学习了如何安装 Phaser, 让我们继续学习第二章: scaling.

+## 下一步 -

{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser", "Games/Tutorials/2D_Breakout_game_Phaser/Scaling")}}

+现在我们已经完成了一个简单的 HTML 页面,并且学习了如何安装 Phaser, 让我们继续学习第二章: [scaling](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Scaling). + +{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser", "Games/Tutorials/2D_Breakout_game_Phaser/Scaling")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.md index fecb1100dada51..36c34d2a508237 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.md @@ -14,58 +14,57 @@ tags: translation_of: >- Games/Tutorials/2D_breakout_game_Phaser/Load_the_assets_and_print_them_on_screen --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Scaling", "Games/Workflows/2D_Breakout_game_Phaser/Move the ball")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Scaling", "Games/Workflows/2D_Breakout_game_Phaser/Move the ball")}} -
-

这是Gamedev Phaser 教程 16 的第三步。您可以在Gamedev-Phaser-Content-Kit / demos / lesson03.html完成本课程后找到源代码

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第三步**。您可以在[Gamedev-Phaser-Content-Kit / demos / lesson03.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson03.html)完成本课程后找到源代码 -

我们的游戏将围绕屏幕滚动,弹出一个桨,摧毁砖块赚取积分 - 熟悉吗?在本文中,我们将介绍如何将 sprite 添加到我们的 gameworld 中。

+我们的游戏将围绕屏幕滚动,弹出一个桨,摧毁砖块赚取积分 - 熟悉吗?在本文中,我们将介绍如何将 sprite 添加到我们的 gameworld 中。 -

有一个球

+## 有一个球 -

我们开始创建一个 JavaScript 变量来表示我们的球 - 在游戏初始化代码(我们的var game...块)和preload()函数之间添加以下行:

+我们开始创建一个 JavaScript 变量来表示我们的球 - 在游戏初始化代码(我们的`var game...`块)和`preload()`函数之间添加以下行: -
var ball;
-
+```js +var ball; +``` -
-

备注: 为了本教程,我们将使用全局变量。本教程的目的是教导 Phaser 特定的游戏开发方法,而不是主观的最佳方法。

-
+> **备注:** 为了本教程,我们将使用全局变量。**本教程的目的是教导 Phaser 特定的游戏开发方法,而不是主观的最佳方法。** -

加载球精灵

+## 加载球精灵 -

使用 Phaser 加载图像并将其打印在我们的画布上比使用纯 JavaScript 容易得多。要加载资产,我们将使用game由 Phaser 创建的对象,执行其load.image()方法。在preload()函数的底部添加以下新行:

+使用 Phaser 加载图像并将其打印在我们的画布上比使用纯 JavaScript 容易得多。要加载资产,我们将使用`game`由 Phaser 创建的对象,执行其`load.image()`方法。在`preload()`函数的底部添加以下新行: -
function preload() {
+```js
+function preload() {
     // ...
     game.load.image('ball', 'img/ball.png');
 }
-
+``` -

第一个参数是我们要提供资产的名称 - 这将在我们的游戏代码中使用,例如我们的ball变量名称,所以我们需要确保它是一样的。第二个参数是图形资源的相对路径。在我们的情况下,我们将加载我们的球的图像(请注意,文件名不一定是一致的,但我们建议,因为它使一切更容易遵循。)

+第一个参数是我们要提供资产的名称 - 这将在我们的游戏代码中使用,例如我们的`ball`变量名称,所以我们需要确保它是一样的。第二个参数是图形资源的相对路径。在我们的情况下,我们将加载我们的球的图像(请注意,文件名不一定是一致的,但我们建议,因为它使一切更容易遵循。) -

当然,要加载图像,它需要在我们的代码目录中可用。从 Github 抓住球图像,并将其保存/img在与index.html文件相同位置的目录中。

+当然,要加载图像,它需要在我们的代码目录中可用。[从 Github 抓住球图像](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/img/ball.png),并将其保存`/img`在与`index.html`文件相同位置的目录中。 -

现在,要在屏幕上显示,我们将使用另一种 Phaser 方法add.sprite():在create()函数内添加以下新的代码行,如图所示:

+现在,要在屏幕上显示,我们将使用另一种 Phaser 方法`add.sprite()`:在`create()`函数内添加以下新的代码行,如图所示: -
function create() {
+```js
+function create() {
     ball = game.add.sprite(50, 50, 'ball');
 }
-
+``` -

这将添加球到游戏,并将其呈现在屏幕上。前两个参数是要添加的画布的 x 和 y 坐标,第三个是我们之前定义的资产的名称。就是这样 - 如果你加载你的index.html文件,你会看到已经加载并在画布上渲染的图像!

+这将添加球到游戏,并将其呈现在屏幕上。前两个参数是要添加的画布的 x 和 y 坐标,第三个是我们之前定义的资产的名称。就是这样 - 如果你加载你的`index.html`文件,你会看到已经加载并在画布上渲染的图像! -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/98xrv9x5/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/98xrv9x5/","","400")}} -

下一步

+## 下一步 -

打出球很容易; 接下来我们将尝试在屏幕上移动球

+打出球很容易; 接下来我们将尝试在屏幕上[移动球](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Move_the_ball)。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Scaling", "Games/Workflows/2D_Breakout_game_Phaser/Move the ball")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Scaling", "Games/Workflows/2D_Breakout_game_Phaser/Move the ball")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.md index f5d36f56589fac..f4c17ede396bd1 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.md @@ -12,38 +12,37 @@ tags: - moving translation_of: Games/Tutorials/2D_breakout_game_Phaser/Move_the_ball --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen", "Games/Workflows/2D_Breakout_game_Phaser/Physics")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen", "Games/Workflows/2D_Breakout_game_Phaser/Physics")}} -
-

这是Gamedev Phaser 教程 16 的第 4 步。在Gamedev-Phaser-Content-Kit / demos / lesson04.html完成本课后,您可以找到源代码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第 4 步**。在[Gamedev-Phaser-Content-Kit / demos / lesson04.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson04.html)完成本课后,您可以找到源代码。 -

我们在屏幕上打印了我们的蓝色球,但它什么都不做,这样做会很酷。本文介绍如何做到这一点。

+我们在屏幕上打印了我们的蓝色球,但它什么都不做,这样做会很酷。本文介绍如何做到这一点。 -

在每个框架上更新球的位置

+## 在每个框架上更新球的位置 -

记住update()功能及其定义?其中的代码在每个框架上执行,所以它是一个完美的地方,将代码更新球的位置在屏幕上。在里面添加以下新行代码update(),如下所示:

+记住`update()`功能及其定义?其中的代码在每个框架上执行,所以它是一个完美的地方,将代码更新球的位置在屏幕上。在里面添加以下新行代码`update()`,如下所示: -
function update() {
+```js
+function update() {
     ball.x += 1;
     ball.y += 1;
 }
-
+``` -

上面的代码在每个框架上为表示画布上的球坐标的属性xy属性添加了一个。重新加载 index.html,你应该看到球在屏幕上滚动。

+上面的代码在每个框架上为表示画布上的球坐标的属性`x`和`y`属性添加了一个。重新加载 index.html,你应该看到球在屏幕上滚动。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/g1cfp0vv/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/g1cfp0vv/","","400")}} -

下一步

+## 下一步 -

下一步是添加一些基本的碰撞检测,所以我们的球可以从墙壁反弹。这将需要几行代码 - 一个比我们迄今为止看到的更复杂的步骤,特别是如果我们也想添加桨和砖碰撞 - 但是幸运的是 Phaser 使我们比我们想要使用纯粹的方法更容易做到这一点 JavaScript 的。

+下一步是添加一些基本的碰撞检测,所以我们的球可以从墙壁反弹。这将需要几行代码 - 一个比我们迄今为止看到的更复杂的步骤,特别是如果我们也想添加桨和砖碰撞 - 但是幸运的是 Phaser 使我们比我们想要使用纯粹的方法更容易做到这一点 JavaScript 的。 -

无论如何,在我们做所有的事情之前,我们将首先介绍 Phaser 的物理引擎,并做一些设置工作。

+无论如何,在我们做所有的事情之前,我们将首先介绍 Phaser 的[物理](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Physics)引擎,并做一些设置工作。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen", "Games/Workflows/2D_Breakout_game_Phaser/Physics")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen", "Games/Workflows/2D_Breakout_game_Phaser/Physics")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/physics/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/physics/index.md index ffc3407d8f86b4..562e20033d3905 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/physics/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/physics/index.md @@ -12,52 +12,55 @@ tags: - physics translation_of: Games/Tutorials/2D_breakout_game_Phaser/Physics --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Move_the_ball", "Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Move_the_ball", "Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls")}} -
-

这是Gamedev Phaser 教程 16 的第 5 步。您可以在Gamedev-Phaser-Content-Kit / demos / lesson05.html完成本课程后找到源代码

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第 5 步**。您可以在[Gamedev-Phaser-Content-Kit / demos / lesson05.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson05.html)完成本课程后找到源代码 -

为了在我们的游戏中的对象之间进行正确的碰撞检测,我们将需要物理学; 本文将向您介绍 Phaser 中的可用内容,以及演示典型的简单设置。

+为了在我们的游戏中的对象之间进行正确的碰撞检测,我们将需要物理学; 本文将向您介绍 Phaser 中的可用内容,以及演示典型的简单设置。 -

添加物理效果

+## 添加物理效果 -

Phaser 与三个不同的物理引擎(Arcade Physics,P2 和 Ninja Physics)捆绑在一起,第四个选项 Box2D 可作为商业插件使用。对于像我们这样的简单游戏,我们可以使用 Arcade Physics 引擎。我们不需要任何重的几何计算 - 毕竟只是一个球从墙壁和砖块弹起来。

+Phaser 与三个不同的物理引擎(Arcade Physics,P2 和 Ninja Physics)捆绑在一起,第四个选项 Box2D 可作为商业插件使用。对于像我们这样的简单游戏,我们可以使用 Arcade Physics 引擎。我们不需要任何重的几何计算 - 毕竟只是一个球从墙壁和砖块弹起来。 -

首先,让我们在游戏中初始化 Arcade Physics 引擎。physics.startSystem()create函数开头添加方法(使其成为函数内的第一行),如下所示:

+首先,让我们在游戏中初始化 Arcade Physics 引擎。`physics.startSystem()`在`create`函数开头添加方法(使其成为函数内的第一行),如下所示: -
game.physics.startSystem(Phaser.Physics.ARCADE);
-
+```js +game.physics.startSystem(Phaser.Physics.ARCADE); +``` -

接下来,我们需要为物理系统启用我们的球 - 默认情况下,Phaser 对象物理不启用。在create()函数底部添加以下行:

+接下来,我们需要为物理系统启用我们的球 - 默认情况下,Phaser 对象物理不启用。在`create()`函数底部添加以下行: -
game.physics.enable(ball, Phaser.Physics.ARCADE);
-
+```js +game.physics.enable(ball, Phaser.Physics.ARCADE); +``` -

接下来,如果我们要在屏幕上移动我们的球,我们可以设置velocitybody。再次添加以下行create()

+接下来,如果我们要在屏幕上移动我们的球,我们可以设置`velocity`它`body`。再次添加以下行`create()`: -
ball.body.velocity.set(150, 150);
-
+```js +ball.body.velocity.set(150, 150); +``` -

删除我们以前的更新说明

+## 删除我们以前的更新说明 -

记得删除添加值的我们的老方法x,并yupdate()功能:

+记得删除添加值的我们的老方法`x`,并`y`从`update()`功能: -
function update() {
-    ball.x += 1;
-    ball.y += 1;
+```js
+function update() {
+    ball.x += 1;
+    ball.y += 1;
 }
-
+``` -

我们正在使用物理引擎正确处理。

+我们正在使用物理引擎正确处理。 -

最终代码检查

+## 最终代码检查 -

最新的代码应该如下所示:

+最新的代码应该如下所示: -
var ball;
+```js
+var ball;
 
 function preload() {
     game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
@@ -76,24 +79,24 @@ function create() {
 
 function update() {
 }
-
+``` -

尝试重新加载index.html- 球应该在给定的方向上不断移动。目前,物理引擎的重力和摩擦力设定为零。增加重力将导致球落下,同时摩擦力最终会停止球。

+尝试重新加载`index.html`- 球应该在给定的方向上不断移动。目前,物理引擎的重力和摩擦力设定为零。增加重力将导致球落下,同时摩擦力最终会停止球。 -

物理效果趣味

+## 物理效果趣味 -

你可以用物理学来做更多的事情,例如添加ball.body.gravity.y = 100;你将设置球的垂直重力。因此,它将向上发射,但是由于重力的作用而下降。

+你可以用物理学来做更多的事情,例如添加`ball.body.gravity.y = 100;`你将设置球的垂直重力。因此,它将向上发射,但是由于重力的作用而下降。 -

这种功能只是冰山一角 - 有各种功能和变量可以帮助您操纵物理对象。查看官方物理文档,并使用ArcadeP2物理系统查看大量示例。

+这种功能只是冰山一角 - 有各种功能和变量可以帮助您操纵物理对象。查看官方[物理文档,](http://phaser.io/docs#physics)并使用[Arcade](http://phaser.io/examples/v2/category/arcade-physics)和[P2](http://phaser.io/examples/v2/category/p2-physics)物理系统查看大量示例。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/bjto9nj8/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/bjto9nj8/","","400")}} -

下一步

+## 下一步 -

现在我们可以转到下一课,看看如何让球从墙上弹起

+现在我们可以转到下一课,看看如何让球[从墙上弹起](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls)。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Move_the_ball", "Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Move_the_ball", "Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.md index 7c32901b3fdc3e..8b5157deb27d86 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.md @@ -11,112 +11,122 @@ tags: - Tutorial translation_of: Games/Tutorials/2D_breakout_game_Phaser/Player_paddle_and_controls --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_Phaser/Game_over")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_Phaser/Game_over")}} -
-

这是Gamedev Phaser 教程 16 的第 7 步。您可以在Gamedev-Phaser-Content-Kit / demos / lesson07.html完成本课程后找到源代码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第 7 步**。您可以在[Gamedev-Phaser-Content-Kit / demos / lesson07.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson07.html)完成本课程后找到源代码。 -

我们有球从墙上移动并弹跳,但它很快变得无聊 - 没有互动!我们需要一种介绍游戏的方法,所以在这篇文章中,我们将创建一个桨来移动并击中球。

+我们有球从墙上移动并弹跳,但它很快变得无聊 - 没有互动!我们需要一种介绍游戏的方法,所以在这篇文章中,我们将创建一个桨来移动并击中球。 -

渲染桨

+## 渲染桨 -

从框架的角度看,桨非常类似于球 - 我们需要添加一个变量来表示它,加载相关的图像资源,然后做出魔法。

+从框架的角度看,桨非常类似于球 - 我们需要添加一个变量来表示它,加载相关的图像资源,然后做出魔法。 -

装载桨

+### 装载桨 -

首先,添加paddle我们将在我们的游戏中使用的ball变量,就在变量之后:

+首先,添加`paddle`我们将在我们的游戏中使用的`ball`变量,就在变量之后: -
var paddle;
-
+```js +var paddle; +``` -

然后,在该preload功能中,paddle通过添加以下新load.image()调用来加载图像:

+然后,在该`preload`功能中,`paddle`通过添加以下新`load.image()`调用来加载图像: -
function preload() {
+```js
+function preload() {
     // ...
     game.load.image('ball', 'img/ball.png');
     game.load.image('paddle', 'img/paddle.png');
 }
-
+``` -

添加桨图形

+### 添加桨图形 -

所以我们不要忘记,在这一点上,你应该从 Github 抓住这个图形,并保存在你的/img文件夹中。

+所以我们不要忘记,在这一点上,你应该从 Github 抓住这个[图形](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/img/paddle.png),并保存在你的`/img`文件夹中。 -

渲染桨用物理引擎

+### 渲染桨用物理引擎 -

接下来,我们将通过add.sprite()create()函数中添加以下调用来初始化我们的桨,将其添加到底部:

+接下来,我们将通过`add.sprite()`在`create()`函数中添加以下调用来初始化我们的桨,将其添加到底部: -
paddle = game.add.sprite(game.world.width*0.5, game.world.height-5, 'paddle');
-
+```js +paddle = game.add.sprite(game.world.width*0.5, game.world.height-5, 'paddle'); +``` -

我们可以使用world.widthworld.height值来将桨定位到我们想要的位置:game.world.width*0.5将在屏幕中间。在我们这个例子中,世界和画布是一样的,但是对于其他类型的游戏,例如侧滚滚,这个世界会变大,你可以修改它来创造有趣的效果。

+我们可以使用`world.width`和`world.height`值来将桨定位到我们想要的位置:`game.world.width*0.5`将在屏幕中间。在我们这个例子中,世界和画布是一样的,但是对于其他类型的游戏,例如侧滚滚,这个世界会变大,你可以修改它来创造有趣的效果。 -

你会注意到,如果你index.html在这一点上重新加载,那么桨是目前不完全在中间的。为什么?因为计算位置的锚总是从对象的左上角开始。我们可以改变它,使锚在桨的宽度的中间和它的高度的底部,所以更容易将其定位在底部边缘。添加以下新行以下的行:

+你会注意到,如果你`index.html`在这一点上重新加载,那么桨是目前不完全在中间的。为什么?因为计算位置的锚总是从对象的左上角开始。我们可以改变它,使锚在桨的宽度的中间和它的高度的底部,所以更容易将其定位在底部边缘。添加以下新行以下的行: -
paddle.anchor.set(0.5,1);
-
+```js +paddle.anchor.set(0.5,1); +``` -

桨现在位于我们想要的地方。现在,为了使它与球碰撞,我们必须为桨提供物理效果。继续添加以下新行,再次在create()函数的底部:

+桨现在位于我们想要的地方。现在,为了使它与球碰撞,我们必须为桨提供物理效果。继续添加以下新行,再次在`create()`函数的底部: -
game.physics.enable(paddle, Phaser.Physics.ARCADE);
-
+```js +game.physics.enable(paddle, Phaser.Physics.ARCADE); +``` -

现在,魔法可以开始发生 - 该框架可以在每个框架上检查碰撞检测。要启用桨和球之间的碰撞检测,请将collide()方法添加到如下update()功能中:

+现在,魔法可以开始发生 - 该框架可以在每个框架上检查碰撞检测。要启用桨和球之间的碰撞检测,请将`collide()`方法添加到如下`update()`功能中: -
function update() {
+```js
+function update() {
     game.physics.arcade.collide(ball, paddle);
 }
-
+``` -

第一个参数是我们感兴趣的对象之一 - 球 - 第二个是另一个,桨。这有效,但不如我们预期的那样 - 当球击中桨时,桨从屏幕上掉下来!我们想要的就是球从跳板上跳起来,而桨子停在同一个地方。我们可以将body桨设置成immovable球,所以当球击中它时不会移动。为此,请在create()函数底部添加以下行:

+第一个参数是我们感兴趣的对象之一 - 球 - 第二个是另一个,桨。这有效,但不如我们预期的那样 - 当球击中桨时,桨从屏幕上掉下来!我们想要的就是球从跳板上跳起来,而桨子停在同一个地方。我们可以将`body`桨设置成`immovable`球,所以当球击中它时不会移动。为此,请在`create()`函数底部添加以下行: -
paddle.body.immovable = true;
-
+```js +paddle.body.immovable = true; +``` -

现在它按预期工作。

+现在它按预期工作。 -

控制桨

+## 控制桨 -

接下来的问题是我们不能移动桨。要做到这一点,我们可以使用系统的默认输入(鼠标或触摸,取决于平台),并将桨位置设置到位置的input位置。将以下新行添加到update()函数中,如下所示:

+接下来的问题是我们不能移动桨。要做到这一点,我们可以使用系统的默认输入(鼠标或触摸,取决于平台),并将桨位置设置到位置的`input`位置。将以下新行添加到`update()`函数中,如下所示: -
function update() {
+```js
+function update() {
     game.physics.arcade.collide(ball, paddle);
     paddle.x = game.input.x;
 }
-
+``` -

现在在每个新的一帧上,桨的x位置将根据输入的x位置进行调整,但是当我们开始游戏时,桨的位置不在中间。这是因为输入位置尚未定义。要修复,我们可以将默认位置(如果输入位置尚未定义)设置为屏幕中间。更新上一行如下:

+现在在每个新的一帧上,桨的`x`位置将根据输入的`x`位置进行调整,但是当我们开始游戏时,桨的位置不在中间。这是因为输入位置尚未定义。要修复,我们可以将默认位置(如果输入位置尚未定义)设置为屏幕中间。更新上一行如下: -
paddle.x = game.input.x || game.world.width*0.5;
-
+```js +paddle.x = game.input.x || game.world.width*0.5; +``` -

如果您还没有这样做,请重新加载index.html并尝试!

+如果您还没有这样做,请重新加载`index.html`并尝试! -

定位球

+## 定位球 -

我们有桨按预期工作,所以我们把球放在上面。它非常类似于定位桨 - 我们需要将其放置在屏幕中间水平和垂直的底部,与底部有一点偏移。要按照我们想要的方式放置它,我们将把锚定位到球的正中间。找到现有的行,并将其替换为以下两行:ball = game.add.sprite( ... )

+我们有桨按预期工作,所以我们把球放在上面。它非常类似于定位桨 - 我们需要将其放置在屏幕中间水平和垂直的底部,与底部有一点偏移。要按照我们想要的方式放置它,我们将把锚定位到球的正中间。找到现有的行,并将其替换为以下两行:` ball = game.add.``sprite( ... ) ` -
ball = game.add.sprite(game.world.width*0.5, game.world.height-25, 'ball');
-ball.anchor.set(0.5);
+```js +ball = game.add.sprite(game.world.width*0.5, game.world.height-25, 'ball'); +ball.anchor.set(0.5); +``` -

速度保持不变 - 我们只是将第二个参数的值从 150 改为 -150,所以球将通过向上移动而不是下降来开始游戏。查找现有ball.body.velocity.set( ... )行并将其更新为以下内容:

+速度保持不变 - 我们只是将第二个参数的值从 150 改为 -150,所以球将通过向上移动而不是下降来开始游戏。查找现有`ball.body.velocity.set( ... )`行并将其更新为以下内容: -
ball.body.velocity.set(150, -150);
-
+```js +ball.body.velocity.set(150, -150); +``` -

现在球将从桨的中间开始。

+现在球将从桨的中间开始。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/ogqza0ye/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/ogqza0ye/","","400")}} -

下一步

+## 下一步 -

我们可以移动桨,并将球反弹,但是如果球从屏幕的底部边缘反弹,那又有什么意义?我们来介绍丢失的可能性 - 也称为游戏逻辑。

+我们可以移动桨,并将球反弹,但是如果球从屏幕的底部边缘反弹,那又有什么意义?我们来介绍丢失的可能性 - 也称为[游戏](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Game_over)逻辑。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_Phaser/Game_over")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_Phaser/Game_over")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/randomizing_gameplay/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/randomizing_gameplay/index.md index 5fdc4a9312ce6c..17038d2a129c54 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/randomizing_gameplay/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/randomizing_gameplay/index.md @@ -11,51 +11,49 @@ tags: - Tutorial translation_of: Games/Tutorials/2D_breakout_game_Phaser/Randomizing_gameplay --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{Previous("Games/Workflows/2D_Breakout_game_Phaser/Buttons")}}

+{{Previous("Games/Workflows/2D_Breakout_game_Phaser/Buttons")}} -
-

这是Gamedev Phaser 教程 16 中的第16 步。您可以在Gamedev-Phaser-Content-Kit / demos / lesson16.html完成本课程后找到源代码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 中的第**16 步**。您可以在[Gamedev-Phaser-Content-Kit / demos / lesson16.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson16.html)完成本课程后找到源代码。 -

我们的游戏似乎已经完成了,但是如果你看起来足够近,你会发现球在整个游戏中都以相同的角度从桨上弹起。这意味着每个游戏都非常相似。为了解决这个问题,提高可玩性,我们应该使反弹角度更加随机,在本文中我们将介绍一下如何。

+我们的游戏似乎已经完成了,但是如果你看起来足够近,你会发现球在整个游戏中都以相同的角度从桨上弹起。这意味着每个游戏都非常相似。为了解决这个问题,提高可玩性,我们应该使反弹角度更加随机,在本文中我们将介绍一下如何。 -

让篮板更随机

+## 让篮板更随机 -

我们可以根据撞击桨的确切位置来改变球的速度,通过使用沿着下方的线路运行功能来修改x速度ballHitPaddle()。现在添加这一行到您的代码,并尝试。

+我们可以根据撞击桨的确切位置来改变球的速度,通过使用沿着下方的线路运行功能来修改`x`速度`ballHitPaddle()`。现在添加这一行到您的代码,并尝试。 -
function ballHitPaddle(ball, paddle) {
+```js
+function ballHitPaddle(ball, paddle) {
     ball.animations.play('wobble');
     ball.body.velocity.x = -1*5*(paddle.x-ball.x);
-}
+} +``` -

这有点魔法 - 新的速度越高,桨的中心和球撞到的地方之间的距离就越大。此外,方向(左或右)由该值确定 - 如果球击中桨的左侧,则其将向左反弹,而击球右侧将向右反弹。最终这样做是因为对某些值进行了一些实验,您可以进行自己的实验,看看会发生什么。这当然不是完全随机的,但它确实使游戏玩法变得更加不可预测,因此更有趣。

+这有点魔法 - 新的速度越高,桨的中心和球撞到的地方之间的距离就越大。此外,方向(左或右)由该值确定 - 如果球击中桨的左侧,则其将向左反弹,而击球右侧将向右反弹。最终这样做是因为对某些值进行了一些实验,您可以进行自己的实验,看看会发生什么。这当然不是完全随机的,但它确实使游戏玩法变得更加不可预测,因此更有趣。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/3yds5ege/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/3yds5ege/","","400")}} -

概要

+## 概要 -

你已经完成了所有的课程 - 恭喜你!在这一点上,您将了解到 Phaser 的基础知识和简单 2D 游戏背后的逻辑。

+你已经完成了所有的课程 - 恭喜你!在这一点上,您将了解到 Phaser 的基础知识和简单 2D 游戏背后的逻辑。 -

练习跟随

+### 练习跟随 -

你可以在游戏中做更多的事情 - 添加任何你觉得最好的东西,使它更有趣和有趣。Phaser 提供的无数有用的方法的基本介绍。以下是关于如何扩展我们的小游戏的一些建议,让您开始:

+你可以在游戏中做更多的事情 - 添加任何你觉得最好的东西,使它更有趣和有趣。Phaser 提供的无数有用的方法的基本介绍。以下是关于如何扩展我们的小游戏的一些建议,让您开始: -
    -
  • 添加第二个球或桨。
  • -
  • 改变每次命中背景的颜色。
  • -
  • 更改图像并使用自己的图像。
  • -
  • 如果砖块被迅速摧毁,并排排列(或您选择的其他奖金),则可获得额外的奖励积分。
  • -
  • 创建不同砖块布局的水平。
  • -
+- 添加第二个球或桨。 +- 改变每次命中背景的颜色。 +- 更改图像并使用自己的图像。 +- 如果砖块被迅速摧毁,并排排列(或您选择的其他奖金),则可获得额外的奖励积分。 +- 创建不同砖块布局的水平。 -

一定要检查越来越多的示例列表和官方文档,如果您需要任何帮助,请访问HTML5 Gamedevs 论坛

+一定要检查越来越多的[示例](http://examples.phaser.io/)列表和[官方文档](http://docs.phaser.io/),如果您需要任何帮助,请访问[HTML5 Gamedevs 论坛](http://www.html5gamedevs.com/forum/14-phaser/)。 -

您也可以返回本教程系列的索引页

+您也可以返回[本教程系列的索引页](/en-US/docs/Games/Workflows/2D_breakout_game_Phaser)。 -

{{Previous("Games/Workflows/2D_Breakout_game_Phaser/Buttons")}}

+{{Previous("Games/Workflows/2D_Breakout_game_Phaser/Buttons")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/scaling/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/scaling/index.md index 74dd8b87829601..bc52a0a34a6316 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/scaling/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/scaling/index.md @@ -11,54 +11,52 @@ tags: - Tutorial translation_of: Games/Tutorials/2D_breakout_game_Phaser/Scaling --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser/Initialize_the_framework", "Games/Tutorials/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen")}}

+{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser/Initialize_the_framework", "Games/Tutorials/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen")}} -
-

这是Gamedev Phaser 教程系列的第二课。在课程完成之后,你可以在Gamedev-Phaser-Content-Kit/demos/lesson02.html找到源码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser)系列的第二课。在课程完成之后,你可以在[Gamedev-Phaser-Content-Kit/demos/lesson02.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson01.html)找到源码。 -

缩放是指游戏画布如何在不同的屏幕尺寸上进行显示。我们可以在预加载阶段自动使游戏规模适合任何屏幕尺寸,之后就可以不用再担心屏幕尺寸的问题了。

+缩放是指游戏画布如何在不同的屏幕尺寸上进行显示。我们可以在预加载阶段自动使游戏规模适合任何屏幕尺寸,之后就可以不用再担心屏幕尺寸的问题了。 -

Phaser 中 scale 对象

+## Phaser 中 scale 对象 -

Phaser 中有一个特殊的对象:scale,它包含一些特别的方法和属性。让我们来更改一下上一节中创建的的preload()函数:

+Phaser 中有一个特殊的对象:`scale`,它包含一些特别的方法和属性。让我们来更改一下上一节中创建的的`preload()`函数: -
function preload() {
+```js
+function preload() {
     game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
     game.scale.pageAlignHorizontally = true;
     game.scale.pageAlignVertically = true;
 }
-
+``` -

scaleMode 有几个不同的选项来指定 Canvas 应该如何缩放:

+`scaleMode` 有几个不同的选项来指定 Canvas 应该如何缩放: -
    -
  • NO_SCALE — 不进行任何缩放。
  • -
  • EXACT_FIT — 拉伸,填充屏幕,不保留长宽比。
  • -
  • SHOW_ALL — 等比缩放,填充屏幕,保留长宽比,剩余空间用黑色填充。
  • -
  • RESIZE — 动态,每次都会根据屏幕生成画布,所以你需要在游戏运行时动态的放置游戏元素。这是一种进阶的模式。
  • -
  • USER_SCALE — 自定义,允许您自己计算大小和比例。这也是一种进阶的模式。
  • -
+- `NO_SCALE` — 不进行任何缩放。 +- `EXACT_FIT` — 拉伸,填充屏幕,不保留长宽比。 +- `SHOW_ALL` — 等比缩放,填充屏幕,保留长宽比,剩余空间用黑色填充。 +- `RESIZE` — 动态,每次都会根据屏幕生成画布,所以你需要在游戏运行时动态的放置游戏元素。这是一种进阶的模式。 +- `USER_SCALE` — 自定义,允许您自己计算大小和比例。这也是一种进阶的模式。 -

preload()中的其他两行代码负责水平和垂直居中画布,所以它始终以屏幕为中心,无论大小如何。

+`preload()`中的其他两行代码负责水平和垂直居中画布,所以它始终以屏幕为中心,无论大小如何。 -

设置背景颜色

+## 设置背景颜色 -

我们还可以给画布设置背景颜色来替代磨人的黑色背景。通过更改stage对象的backgroundColor属性来添加,我们可以使用 CSS 颜色定义语法进行设置。我们在刚才的代码下面添加以下代码:

+我们还可以给画布设置背景颜色来替代磨人的黑色背景。通过更改`stage`对象的`backgroundColor`属性来添加,我们可以使用 CSS 颜色定义语法进行设置。我们在刚才的代码下面添加以下代码: -
game.stage.backgroundColor = '#eee';
-
+```js +game.stage.backgroundColor = '#eee'; +``` -

完整的代码

+## 完整的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/6a64vecL/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/6a64vecL/","","400")}} -

下一步

+## 下一步 -

现在我们设置了我们游戏的缩放比例,让我们继续第三课,并设计出如何加载资源并将其显示在屏幕上

+现在我们设置了我们游戏的缩放比例,让我们继续第三课,并设计出如何[加载资源并将其显示在屏幕上](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen)。 -

{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser/Initialize_the_framework", "Games/Tutorials/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen")}}

+{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser/Initialize_the_framework", "Games/Tutorials/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/the_score/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/the_score/index.md index 64fd002fdd7268..b644ac468042e4 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/the_score/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/the_score/index.md @@ -12,65 +12,64 @@ tags: - scoring translation_of: Games/Tutorials/2D_breakout_game_Phaser/The_score --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Collision_detection", "Games/Workflows/2D_Breakout_game_Phaser/Win_the_game")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Collision_detection", "Games/Workflows/2D_Breakout_game_Phaser/Win_the_game")}} -
-

这是Gamedev Phaser 教程 16 的第 11 步。您可以在Gamedev-Phaser-Content-Kit / demos / lesson11.html完成本课程后找到源代码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第 11 步**。您可以在[Gamedev-Phaser-Content-Kit / demos / lesson11.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson11.html)完成本课程后找到源代码。 -

得分也可以使游戏更有趣 - 你可以尝试击败自己的高分,或者你的朋友。在这篇文章中,我们将为我们的游戏添加一个评分系统。

+得分也可以使游戏更有趣 - 你可以尝试击败自己的高分,或者你的朋友。在这篇文章中,我们将为我们的游戏添加一个评分系统。 -

我们将使用一个单独的变量来存储分数和 Phaser 的text()方法将其打印到屏幕上。

+我们将使用一个单独的变量来存储分数和 Phaser 的`text()`方法将其打印到屏幕上。 -

新变量

+## 新变量 -

在以前定义的之后添加两个新变量:

+在以前定义的之后添加两个新变量: -
// ...
+```js
+// ...
 var scoreText;
 var score = 0;
-
+``` -

将得分文字添加到游戏显示

+## 将得分文字添加到游戏显示 -

现在在create()函数末尾添加这一行:

+现在在`create()`函数末尾添加这一行: -
scoreText = game.add.text(5, 5, 'Points: 0', { font: '18px Arial', fill: '#0095DD' });
-
+```js +scoreText = game.add.text(5, 5, 'Points: 0', { font: '18px Arial', fill: '#0095DD' }); +``` -

text()方法可以采用四个参数:

+该`text()`方法可以采用四个参数: -
    -
  • x 和 y 坐标来绘制文本。
  • -
  • 将呈现的实际文本。
  • -
  • 用于呈现文本的字体样式。
  • -
+- x 和 y 坐标来绘制文本。 +- 将呈现的实际文本。 +- 用于呈现文本的字体样式。 -

最后一个参数与 CSS 样式非常相似。在我们的例子中,乐谱文字将为蓝色,大小为 18 像素,并使用 Arial 字体。

+最后一个参数与 CSS 样式非常相似。在我们的例子中,乐谱文字将为蓝色,大小为 18 像素,并使用 Arial 字体。 -

当砖块被破坏时更新分数

+## 当砖块被破坏时更新分数 -

每当球击中砖块时,我们将增加点数,更新scoreText显示当前得分。这可以使用setText()方法 - 添加以下两行新ballHitBrick()功能:

+每当球击中砖块时,我们将增加点数,更新`scoreText`显示当前得分。这可以使用`setText()`方法 - 添加以下两行新`ballHitBrick()`功能: -
function ballHitBrick(ball, brick) {
+```js
+function ballHitBrick(ball, brick) {
     brick.kill();
     score += 10;
     scoreText.setText('Points: '+score);
 }
-
+``` -

这是现在 - 重新加载你的,index.html并检查得分更新每个砖击。

+这是现在 - 重新加载你的,`index.html`并检查得分更新每个砖击。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/n8o6rhrf/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/n8o6rhrf/","","400")}} -

下一步

+## 下一步 -

我们现在有一个得分系统,但是如果你不能赢得,那么玩和保持分数是多少?让我们看看我们如何能够增加胜利的状态,让我们赢得比赛

+我们现在有一个得分系统,但是如果你不能赢得,那么玩和保持分数是多少?让我们看看我们如何能够增加胜利的状态,让我们[赢得比赛](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Win_the_game)。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Collision_detection", "Games/Workflows/2D_Breakout_game_Phaser/Win_the_game")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Collision_detection", "Games/Workflows/2D_Breakout_game_Phaser/Win_the_game")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/win_the_game/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/win_the_game/index.md index 4360b8b8f8be81..877a330816a242 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/win_the_game/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/win_the_game/index.md @@ -12,27 +12,26 @@ tags: - winning translation_of: Games/Tutorials/2D_breakout_game_Phaser/Win_the_game --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/The_score", "Games/Workflows/2D_Breakout_game_Phaser/Extra_lives")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/The_score", "Games/Workflows/2D_Breakout_game_Phaser/Extra_lives")}} -
-

这是Gamedev Phaser 教程 16 的第 12 步。您可以在Gamedev-Phaser-Content-Kit / demos / lesson12.html完成本课程后找到源代码。

-
+这是[Gamedev Phaser 教程](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser) 16 的**第 12 步**。您可以在[Gamedev-Phaser-Content-Kit / demos / lesson12.html](https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson12.html)完成本课程后找到源代码。 -

在我们的游戏中实现获胜是相当容易的:如果你碰巧摧毁所有的砖块,那么你赢了。

+在我们的游戏中实现获胜是相当容易的:如果你碰巧摧毁所有的砖块,那么你赢了。 -

如何取胜?

+## 如何取胜? -

将以下新代码添加到您的ballHitBrick()函数中:

+将以下新代码添加到您的`ballHitBrick()`函数中: -
function ballHitBrick(ball, brick) {
+```js
+function ballHitBrick(ball, brick) {
     brick.kill();
     score += 10;
     scoreText.setText('Points: '+score);
 
     var count_alive = 0;
-    for (i = 0; i < bricks.children.length; i++) {
+    for (i = 0; i < bricks.children.length; i++) {
       if (bricks.children[i].alive == true) {
         count_alive++;
       }
@@ -42,18 +41,18 @@ translation_of: Games/Tutorials/2D_breakout_game_Phaser/Win_the_game
       location.reload();
     }
 }
-
+``` -

我们循环使用组中的砖块bricks.children,检查每个砖块的.alive() 方法的活力。如果没有更多的砖块活着,那么我们会显示一个获胜的消息,一旦警报被关闭,重新启动游戏。

+我们循环使用组中的砖块`bricks.children`,检查每个砖块的`.alive() `方法的活力。如果没有更多的砖块活着,那么我们会显示一个获胜的消息,一旦警报被关闭,重新启动游戏。 -

比较你的代码

+## 比较你的代码 -

您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:

+您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/u8waa4Lx/1/","","400")}}

+{{JSFiddleEmbed("https://jsfiddle.net/u8waa4Lx/1/","","400")}} -

下一步

+## 下一步 -

失败和获胜都是实施的,所以我们的游戏的核心游戏就完成了。现在让我们添加一些额外的东西 - 我们会给玩家将 3 个生活的,而不是一个。

+失败和获胜都是实施的,所以我们的游戏的核心游戏就完成了。现在让我们添加一些额外的东西 - 我们会给玩家将 3 个[生活](/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Extra_lives)的,而不是一个。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/The_score", "Games/Workflows/2D_Breakout_game_Phaser/Extra_lives")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/The_score", "Games/Workflows/2D_Breakout_game_Phaser/Extra_lives")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.md index 36a0f37545708f..ca6bbea34f11db 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.md @@ -3,97 +3,107 @@ title: 反弹的墙壁 slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls")}} -
-

本篇是 Gamedev Canvas tutorial 10 节教程中的第三节。如果你完成了本篇教程之后,你可以从 Gamedev-Canvas-workshop/lesson3.html 看到源码。

-
+本篇是 [Gamedev Canvas tutorial](/en-US/docs/Games/Workflows/Breakout_game_from_scratch) 10 节教程中的第三节。如果你完成了本篇教程之后,你可以从 [Gamedev-Canvas-workshop/lesson3.html](https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson03.html) 看到源码。 -

看到我们的球动起来很惊讶吧,但是它很快就从屏幕上消失了,当然我们是可以控制它的。我们会实现一些非常简单的碰撞检测 (详细后面解释),使球在画布的四周反弹回来。

+看到我们的球动起来很惊讶吧,但是它很快就从屏幕上消失了,当然我们是可以控制它的。我们会实现一些非常简单的碰撞检测 (详细后面解释),使球在画布的四周反弹回来。 -

简单的碰撞

+## 简单的碰撞 -

我们将检查球体是否与边缘接触,如果有接触我们将相应的改变它的运动方向。

+我们将检查球体是否与边缘接触,如果有接触我们将相应的改变它的运动方向。 -

为了运算方便我们定义一个名为 ballRadius 的变量,来存储球的半径。向代码中添加一下内容:

+为了运算方便我们定义一个名为 ballRadius 的变量,来存储球的半径。向代码中添加一下内容: -
var ballRadius = 10;
+```js +var ballRadius = 10; +``` -

现在更新绘制球的 drawBall() 函数:

+现在更新绘制球的 drawBall() 函数: -
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
+```js +ctx.arc(x, y, ballRadius, 0, Math.PI*2); +``` -

从顶部和底部弹起

+### 从顶部和底部弹起 -

有四面墙壁可以让它反弹回来,我们先来看上面的那面墙。我们需要判断球运动的每一帧,球体是否与画布的顶部边缘接触。如果有接触,我们将会改变球体的运动方向,使它向相反的方向移动,并保证它在画布的可见范围之内。记住坐标系统的左上角,让我们开始并加以下代码:

+有四面墙壁可以让它反弹回来,我们先来看上面的那面墙。我们需要判断球运动的每一帧,球体是否与画布的顶部边缘接触。如果有接触,我们将会改变球体的运动方向,使它向相反的方向移动,并保证它在画布的可见范围之内。记住坐标系统的左上角,让我们开始并加以下代码: -
if(y + dy < 0) {
+```js
+if(y + dy < 0) {
     dy = -dy;
-}
+} +``` -

如果球的纵坐标(y 轴)值小于零,我们将在球体原有的运动方向上逆转。如果球体向上移动的速度是 2 像素/帧,现在就是向上移动速度是 -2 像素。这相当于此时向下移动的速度是 2 像素/帧。

+如果球的纵坐标(y 轴)值小于零,我们将在球体原有的运动方向上逆转。如果球体向上移动的速度是 2 像素/帧,现在就是向上移动速度是 -2 像素。这相当于此时向下移动的速度是 2 像素/帧。 -

上面的代码将处理球与画布顶部边缘的反射,现在让我们思考一下底部边缘如何处理:

+上面的代码将处理球与画布顶部边缘的反射,现在让我们思考一下底部边缘如何处理: -
if(y + dy > canvas.height) {
+```js
+if(y + dy > canvas.height) {
     dy = -dy;
-}
+} +``` -

如果球的 y 位置大于canvas的高度(记住,我们从左上角计算 y 值,所以顶部边缘从 0 开始,底部边缘在 480 像素),然后通过像以前那样反转 y 轴运动而离开底部边缘。

+如果球的 y 位置大于`canvas`的高度(记住,我们从左上角计算 y 值,所以顶部边缘从 0 开始,底部边缘在 480 像素),然后通过像以前那样反转 y 轴运动而离开底部边缘。 -

我们可以将这两句冗长的代码合二为一:

+我们可以将这两句冗长的代码合二为一: -
if(y + dy > canvas.height || y + dy < 0) {
+```js
+if(y + dy > canvas.height || y + dy < 0) {
     dy = -dy;
-}
+} +``` -

如果其中一个判断为 true, 则反转球的运动。

+如果其中一个判断为 `true`, 则反转球的运动。 -

从左边和右边反弹

+### 从左边和右边反弹 -

我们有顶部和底部的边缘,所以我们来考虑一下左边和右边的边缘。实际上非常相似,你所要做的就是颠倒x而不是y:

+我们有顶部和底部的边缘,所以我们来考虑一下左边和右边的边缘。实际上非常相似,你所要做的就是颠倒`x`而不是`y`: -
if(x + dx > canvas.width || x + dx < 0) {
+```js
+if(x + dx > canvas.width || x + dx < 0) {
     dx = -dx;
 }
 
-if(y + dy > canvas.height || y + dy < 0) {
+if(y + dy > canvas.height || y + dy < 0) {
     dy = -dy;
-}
+} +``` -

你应该把上面的代码块插入到 draw()函数中,就在大括号之前。

+你应该把上面的代码块插入到 draw()函数中,就在大括号之前。 -

球部分消失在墙上!

+### 球部分消失在墙上! -

测试你的代码,你会看到我们的球碰到任一边缘都会反弹!然而,我们还发现了一个问题,当球碰撞到边缘,反弹之前:

+测试你的代码,你会看到我们的球碰到任一边缘都会反弹!然而,我们还发现了一个问题,当球碰撞到边缘,反弹之前: -

+![](ball-in-wall.png) -

这是因为我们正在计算墙和球的中心碰撞点,而我们应该围绕它的周长来做。如果碰到墙壁,球应该会弹起来,而不是陷入墙壁一半时,所以让我们来调整一下我们的判断条件。更新你之前添加的代码:

+这是因为我们正在计算墙和球的中心碰撞点,而我们应该围绕它的周长来做。如果碰到墙壁,球应该会弹起来,而不是陷入墙壁一半时,所以让我们来调整一下我们的判断条件。更新你之前添加的代码: -
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
+```js
+if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
     dx = -dx;
 }
-if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
+if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
     dy = -dy;
-}
+} +``` -

当球的中心到墙的边缘之间的距离与球的半径完全相同时,它将改变运动的方向。

+当球的中心到墙的边缘之间的距离与球的半径完全相同时,它将改变运动的方向。 -

比较你的代码

+## 比较你的代码 -

让我们再次检查这个部分的代码与你之间有何差异:

+让我们再次检查这个部分的代码与你之间有何差异: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/redj37dc/","","370")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/redj37dc/","","370")}} -
-

备注: 尝试修改你的代码,在每次碰到墙壁时都要把球的颜色改成随机的颜色。

-
+> **备注:** 尝试修改你的代码,在每次碰到墙壁时都要把球的颜色改成随机的颜色。 -

下一步

+## 下一步 -

现在我们已经到了我们的球正在移动和留在游戏板上的阶段。在第四章中,我们将看看如何实现一个可控制的 paddle - 参见paddle 和键盘控制

+现在我们已经到了我们的球正在移动和留在游戏板上的阶段。在第四章中,我们将看看如何实现一个可控制的 paddle - 参见[paddle 和键盘控制](/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Paddle_and_keyboard_controls)。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md index 906d9e978870bf..2f70e860f8c682 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.md @@ -3,49 +3,52 @@ title: Build the brick field slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Build_the_brick_field translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Build_the_brick_field --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection")}} -
-

这是 Gamedev Canvas tutorial教程 10 节的第 6 节。您可以在完成本课程后在这里Gamedev-Canvas-workshop/lesson6.html找到源代码。

-
+这是 [Gamedev Canvas tutorial](/en-US/docs/Games/Workflows/Breakout_game_from_scratch)教程 10 节的第 6 节。您可以在完成本课程后在这里[Gamedev-Canvas-workshop/lesson6.html](https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson06.html)找到源代码。 -

在修改游戏机制后,我们可以输了 — 这样这游戏看起来终于像是一个游戏了,这真是太好了。但是,如果你总是让球与墙、板碰撞的话,很快就会感到无聊的。 好游戏需要的是让球消灭砖,这就是我们即将要做的!

+在修改游戏机制后,我们可以输了 — 这样这游戏看起来终于像是一个游戏了,这真是太好了。但是,如果你总是让球与墙、板碰撞的话,很快就会感到无聊的。 好游戏需要的是让球消灭砖,这就是我们即将要做的! -

设置砖变量

+## 设置砖变量 -

本课题的总体目标是使用一个二维数组嵌套的循环,给出砖的几行代码。首先我们需要设置一些变量定义的砖,如宽度和高度信息,行和列,等。在之前的变量声明处加入以下几行代码。

+本课题的总体目标是使用一个二维数组嵌套的循环,给出砖的几行代码。首先我们需要设置一些变量定义的砖,如宽度和高度信息,行和列,等。在之前的变量声明处加入以下几行代码。 -
var brickRowCount = 3;
+```js
+var brickRowCount = 3;
 var brickColumnCount = 5;
 var brickWidth = 75;
 var brickHeight = 20;
 var brickPadding = 10;
 var brickOffsetTop = 30;
-var brickOffsetLeft = 30;
+var brickOffsetLeft = 30; +``` -

在这里,我们定义了砖的行数和列,宽度和高度,砖块之间的填充物,这样它们就不会互相接触;有一个上、左偏移量,所以它们不会从画布的边缘开始绘制。

+在这里,我们定义了砖的行数和列,宽度和高度,砖块之间的填充物,这样它们就不会互相接触;有一个上、左偏移量,所以它们不会从画布的边缘开始绘制。 -

我们将在一个二维数组容纳我们所有的砖。它将包含砖列(c),砖行(R),每一个包含一个对象,其中包含 x 和 y 位置,让每个砖显示在屏幕上。在变量下面添加以下代码:

+我们将在一个二维数组容纳我们所有的砖。它将包含砖列(c),砖行(R),每一个包含一个对象,其中包含 x 和 y 位置,让每个砖显示在屏幕上。在变量下面添加以下代码: -
var bricks = [];
-for(c=0; c<brickColumnCount; c++) {
+```js
+var bricks = [];
+for(c=0; c
+}
+```
 
-

上面的代码将通过行和列的循环和创造新砖。注意,砖块对象稍后也将用于碰撞检测。

+上面的代码将通过行和列的循环和创造新砖。注意,砖块对象稍后也将用于碰撞检测。 -

画砖的逻辑

+## 画砖的逻辑 -

现在让我们创建一个函数来遍历数组中的所有砖块并在屏幕上绘制它们。. 代码如下:

+现在让我们创建一个函数来遍历数组中的所有砖块并在屏幕上绘制它们。. 代码如下: -
function drawBricks() {
-    for(c=0; c<brickColumnCount; c++) {
-        for(r=0; r<brickRowCount; r++) {
+```js
+function drawBricks() {
+    for(c=0; c
+}
+```
 
-

再次,我们遍历的行和列,给每一块砖的位置设置XY,我们也画布上画砖,---brickwidth X brickheight 。问题是我们都画在一个地方坐标(0,0)处。我们需要做的是增加一些计算,计算每个循环迭代后的砖块的 x 和 y 位置:

+再次,我们遍历的行和列,给每一块砖的位置设置`X`和`Y`,我们也画布上画砖,---`brickwidth` X `brickheight` 。问题是我们都画在一个地方坐标`(0,0)`处。我们需要做的是增加一些计算,计算每个循环迭代后的砖块的 x 和 y 位置: -
var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
-var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
+```js +var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft; +var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop; +``` -

每个brickX位置是 brickWidth + brickPadding,乘以列数C,再加上brickOffsetLeft;对于砖brickY的逻辑相同,除了名称不同,使用行数RbrickHeight,和brickOffsetTop。现在,每一块砖都可以放在正确的地方,排成一排,每一块砖之间都有填充物,从左上角和顶部的帆布边缘偏移。

+每个`brickX`位置是` brickWidth + brickPadding`,乘以列数`C`,再加上`brickOffsetLeft`;对于砖`brickY`的逻辑相同,除了名称不同,使用行数`R`,`brickHeight`,和`brickOffsetTop`。现在,每一块砖都可以放在正确的地方,排成一排,每一块砖之间都有填充物,从左上角和顶部的帆布边缘偏移。 -

在设置brickXbrickY作为对应砖的坐标之后,形成了 drawBricks()函数的最终版本。将以下代码加在drawPaddle()函数后面:

+在设置`brickX`和`brickY`作为对应砖的坐标之后,形成了 `drawBricks()`函数的最终版本。将以下代码加在`drawPaddle()`函数后面: -
function drawBricks() {
-    for(c=0; c<brickColumnCount; c++) {
-        for(r=0; r<brickRowCount; r++) {
+```js
+function drawBricks() {
+    for(c=0; c
             ctx.closePath();
         }
     }
-}
+} +``` -

到了展现真正画砖的时候了

+## 到了展现真正画砖的时候了 -

最后一件事就是在draw()中调用drawBricks(), 位置最好在函数开始处,在清除画布和画球之间。直接将下面代码加在drawBall() 处:

+最后一件事就是在`draw()`中调用`drawBricks()`, 位置最好在函数开始处,在清除画布和画球之间。直接将下面代码加在`drawBall()` 处: -
drawBricks();
-
+```js +drawBricks(); +``` -

比较你的代码

+## 比较你的代码 -

这样,游戏变得更有趣了 :

+这样,游戏变得更有趣了 : -

{{JSFiddleEmbed("https://jsfiddle.net/kundan333/myd4vbwg/2/","","320")}}

+{{JSFiddleEmbed("https://jsfiddle.net/kundan333/myd4vbwg/2/","","320")}} -
-

备注: 练习:尝试在行或列上改变砖块数量,或者它们的位置。

-
+> **备注:** 练习:尝试在行或列上改变砖块数量,或者它们的位置。 -

下一节

+## 下一节 -

现在,我们有砖啦!但是球根本就没有和它们互动 —— 接下来的第七章我们将让球和砖产生碰撞:碰撞检测

+现在,我们有砖啦!但是球根本就没有和它们互动 —— 接下来的第七章我们将让球和砖产生碰撞:[碰撞检测](/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Collision_detection)。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.md index 8ab2d63b3283e2..ccbe0a7fd8a1b7 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.md @@ -3,72 +3,75 @@ title: 撞击处理 slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Collision_detection translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Collision_detection --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win")}} -
-

本篇为Gamedev Canvas tutorial10 节教程中的第 7 节。在你完成这篇课程之后,你可以在Gamedev-Canvas-workshop/lesson7.html.找到我们的源代码。

-
+本篇为[Gamedev Canvas tutorial](/en-US/docs/Games/Workflows/Breakout_game_from_scratch)10 节教程中的**第 7 节。**在你完成这篇课程之后,你可以在[Gamedev-Canvas-workshop/lesson7.html](https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson07.html).找到我们的源代码。 -

我们已经在屏幕上画出了砖块,但游戏仍然没有那么有趣,因为球通过它们。我们需要考虑增加碰撞检测,这样球就可以弹击砖块并打破它们。

+我们已经在屏幕上画出了砖块,但游戏仍然没有那么有趣,因为球通过它们。我们需要考虑增加碰撞检测,这样球就可以弹击砖块并打破它们。 -

当然,这是我们的决定如何实现的,但是计算球是否触及矩形是很困难的,因为在画布中没有辅助函数。为了这个教程,我们将尽可能地做到这一点。我们将检查球的中心是否与任何给定的砖块碰撞。这不会每次都给出一个完美的结果,而且有很多更复杂的方法来进行碰撞检测,但是这对指导你的基本概念很有效。

+当然,这是我们的决定如何实现的,但是计算球是否触及矩形是很困难的,因为在画布中没有辅助函数。为了这个教程,我们将尽可能地做到这一点。我们将检查球的中心是否与任何给定的砖块碰撞。这不会每次都给出一个完美的结果,而且有很多更复杂的方法来进行碰撞检测,但是这对指导你的基本概念很有效。 -

撞击侦测函数

+## **撞击侦测函数** -

踢掉这一切,我们想创建一个碰撞检测功能,将循环通过所有砖块,并比较每一个砖的位置与球的坐标,因为每个帧绘制。为了更好地理解代码,我们将定义用于在碰撞检测的每个循环中存储砖块对象的 B 变量:

+踢掉这一切,我们想创建一个碰撞检测功能,将循环通过所有砖块,并比较每一个砖的位置与球的坐标,因为每个帧绘制。为了更好地理解代码,我们将定义用于在碰撞检测的每个循环中存储砖块对象的 B 变量: -
function collisionDetection() {
-    for(c=0; c<brickColumnCount; c++) {
-        for(r=0; r<brickRowCount; r++) {
+```js
+function collisionDetection() {
+    for(c=0; c
+}
+```
 
-

如果球的中心在我们的一块砖块的坐标内,我们将改变球的方向。对于球的中心在砖块内,以下四个陈述都必须是正确的:

+如果球的中心在我们的一块砖块的坐标内,我们将改变球的方向。对于球的中心在砖块内,以下四个陈述都必须是正确的: -
    -
  • 球的 X 位置大于砖的 X 位置。
  • -
  • 球的 X 位置小于砖的 X 位置加上它的宽度。
  • -
  • 球的 Y 位置大于砖的 Y 位置。
  • -
  • 球的 Y 位置小于砖块的 Y 位置加上它的高度。
  • -
+- 球的 X 位置大于砖的 X 位置。 +- 球的 X 位置小于砖的 X 位置加上它的宽度。 +- 球的 Y 位置大于砖的 Y 位置。 +- 球的 Y 位置小于砖块的 Y 位置加上它的高度。 -

让我们在代码中写下:

+让我们在代码中写下: -
function collisionDetection() {
-    for(c=0; c<brickColumnCount; c++) {
-        for(r=0; r<brickRowCount; r++) {
+```js
+function collisionDetection() {
+    for(c=0; c b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
                 dy = -dy;
             }
         }
     }
-}
+} +``` -

将上面的块添加到代码中,在 keyUpHandler() 函数下面。

+将上面的块添加到代码中,在 `keyUpHandler()` 函数下面。 -

让砖块在被撞击之后消失

+## 让砖块在被撞击之后消失 -

上述代码将按需要工作,球改变其方向。问题是砖块留在原地。我们必须想出一个办法来摆脱那些我们已经用球打中的砖。我们可以通过添加一个额外的参数来指示我们是否想在屏幕上画每个砖块。在初始化砖块的代码的一部分中,让我们为每个砖块对象添加一个状态属性。更新代码的下面部分,如突出显示的行所示:

+上述代码将按需要工作,球改变其方向。问题是砖块留在原地。我们必须想出一个办法来摆脱那些我们已经用球打中的砖。我们可以通过添加一个额外的参数来指示我们是否想在屏幕上画每个砖块。在初始化砖块的代码的一部分中,让我们为每个砖块对象添加一个状态属性。更新代码的下面部分,如突出显示的行所示: -
var bricks = [];
-for(c=0; c<brickColumnCount; c++) {
+```js
+var bricks = [];
+for(c=0; c
+}
+```
 
-

接下来,我们将在绘制之前在 drawBricks() 中检查每个砖块的 status属性的值 - 如果 status1,然后画它,但是如果它是 0,那么它被球击中,我们不再希望它在屏幕上。更新您的 drawBricks() 函数如下:

+接下来,我们将在绘制之前在 `drawBricks()` 中检查每个砖块的 `status`属性的值 - 如果 `status`是 `1`,然后画它,但是如果它是 `0`,那么它被球击中,我们不再希望它在屏幕上。更新您的 `drawBricks()` 函数如下: -
function drawBricks() {
-    for(c=0; c<brickColumnCount; c++) {
-        for(r=0; r<brickRowCount; r++) {
+```js
+function drawBricks() {
+    for(c=0; c
+}
+```
 
-

跟踪并更新在撞击侦测函数中的状态

+## 跟踪并更新在撞击侦测函数中的状态 -

现在我们需要将砖块 status 属性包含在 collisionDetection()函数中:如果砖块是活动的(它的状态是 1),我们将检查碰撞是否发生;如果发生碰撞,我们将给定砖块的状态设置为 0,这样它就不会被绘制在屏幕上。更新您的 collisionDetection() 函数,如下所示:

+现在我们需要将砖块 `status` 属性包含在 `collisionDetection()`函数中:如果砖块是活动的(它的状态是 `1`),我们将检查碰撞是否发生;如果发生碰撞,我们将给定砖块的状态设置为 `0`,这样它就不会被绘制在屏幕上。更新您的 `collisionDetection()` 函数,如下所示: -
function collisionDetection() {
-    for(c=0; c<brickColumnCount; c++) {
-        for(r=0; r<brickRowCount; r++) {
+```js
+function collisionDetection() {
+    for(c=0; c b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
                     dy = -dy;
                     b.status = 0;
                 }
             }
         }
     }
-}
+} +``` -

调用我们的撞击侦测函数

+## 调用我们的撞击侦测函数 -

最后要做的是向 collisionDetection() 函数添加一个调用到我们的主要draw() 函数。将下面的行添加到 draw() 函数中,就在drawPaddle() 调用的下面:

+最后要做的是向 `collisionDetection()` 函数添加一个调用到我们的主要`draw()` 函数。将下面的行添加到 `draw()` 函数中,就在`drawPaddle()` 调用的下面: -
collisionDetection();
-
+```js +collisionDetection(); +``` -

对比你的代码

+## 对比你的代码 -

现在,在每一帧,每一块砖上都检查了球的碰撞检测。现在我们可以毁掉砖头:-!

+现在,在每一帧,每一块砖上都检查了球的碰撞检测。现在我们可以毁掉砖头:-! -

{{JSFiddleEmbed("https://jsfiddle.net/kundan333/myd4vbwg/5/","","320")}}

+{{JSFiddleEmbed("https://jsfiddle.net/kundan333/myd4vbwg/5/","","320")}} -
-

备注: 练习:当球碰到砖头时,改变球的颜色。

-
+> **备注:** 练习:当球碰到砖头时,改变球的颜色。 -

下一节

+## 下一节 -

我们现在肯定到了,继续前进吧!在第八章中,我们将探讨如何跟踪得分和获胜。Track the score and win.

+我们现在肯定到了,继续前进吧!在第八章中,我们将探讨如何跟踪得分和获胜。[Track the score and win](/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Track_the_score_and_win). -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.md index a3f3a65d31520b..f08fa09e07a5b3 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.md @@ -5,104 +5,105 @@ slug: >- translation_of: >- Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball")}} -
-

本篇是 Gamedev Canvas tutorial 10 节教程中的第一节。如果你完成了本篇教程之后,你可以从 Gamedev-Canvas-workshop/lesson1.html 看到源码。

-
+本篇是 [Gamedev Canvas tutorial](/en-US/docs/Games/Workflows/Breakout_game_from_scratch) 10 节教程中的第一节。如果你完成了本篇教程之后,你可以从 [Gamedev-Canvas-workshop/lesson1.html](https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson01.html) 看到源码。 -

在我们开始编写游戏功能之前,我们可以通过 HTML 的 canvas 标签创建支撑游戏的基本结构。

+在我们开始编写游戏功能之前,我们可以通过 HTML 的 canvas 标签创建支撑游戏的基本结构。 -

页面部分

+## 页面部分 -

HTML 文档的结构是非常简单的,我们的游戏将完全呈现在这个 HTML 的 canvas 标签中。你可以选择一款你最喜欢的文本编辑器,创建一个 HTML 文件,保存到你理想的位置,名称为 index.html。并添加以下代码:

+HTML 文档的结构是非常简单的,我们的游戏将完全呈现在这个 HTML 的 canvas 标签中。你可以选择一款你最喜欢的文本编辑器,创建一个 HTML 文件,保存到你理想的位置,名称为 index.html。并添加以下代码: -
<!DOCTYPE html>
-<html>
-<head>
-    <meta charset="utf-8" />
-    <title>Gamedev Canvas Workshop</title>
-    <style>
+```html
+
+
+
+    
+    Gamedev Canvas Workshop
+    
+
+
 
-<canvas id="myCanvas" width="480" height="320"></canvas>
+
 
-<script>
+
 
-</body>
-</html>
-
+ + +``` -

在 head 标签中我们需要定义字符集(charset),标题(title)和一些基本的样式。在 body 标签中包含 canvas 标签和 javascript 标签,我们将在 javascript 标签中使用 JavaScript 代码来控制 canvas 标签中的内容展现。在 canvas 标签有一个名为 myCanvas 的 Id,根据这个属性我们可以很容易的获取到这个元素并设置他的宽为 480 像素,高为 320 像素。 之后我们会将所有的 JavaScript 代码全部写到 javascript 标签中(<script>...</script>)。

+在 head 标签中我们需要定义字符集(charset),标题(title)和一些基本的样式。在 body 标签中包含 canvas 标签和 javascript 标签,我们将在 javascript 标签中使用 JavaScript 代码来控制 canvas 标签中的内容展现。在 canvas 标签有一个名为 myCanvas 的 Id,根据这个属性我们可以很容易的获取到这个元素并设置他的宽为 480 像素,高为 320 像素。 之后我们会将所有的 JavaScript 代码全部写到 javascript 标签中(\)。 -

画布的基本属性

+## 画布的基本属性 -

要想在 canvas 标签中呈现图像内容,我们必须在 JavaScript 代码中获取到这个元素。在 javascript 标签中添加以下代码;

+要想在 canvas 标签中呈现图像内容,我们必须在 JavaScript 代码中获取到这个元素。在 javascript 标签中添加以下代码; -
var canvas = document.getElementById("myCanvas");
-var ctx = canvas.getContext("2d");
+```js +var canvas = document.getElementById("myCanvas"); +var ctx = canvas.getContext("2d"); +``` -

在这里我们可以声明一个变量保存 canvas 标签,然后我们需要创建变量 ctx, 这个变量可用来存储 2d 的渲染上下文,我们实际上就用它在 canvas 标签上绘制内容。

+在这里我们可以声明一个变量保存 canvas 标签,然后我们需要创建变量 ctx, 这个变量可用来存储 2d 的渲染上下文,我们实际上就用它在 canvas 标签上绘制内容。 -

让我们来看一个例子,打印在画布上的红色正方形。添加以下代码到你的 JavaScript 里,然后在浏览器中打开 index.html 来看看效果。

+让我们来看一个例子,打印在画布上的红色正方形。添加以下代码到你的 JavaScript 里,然后在浏览器中打开 index.html 来看看效果。 -
ctx.beginPath();
+```js
+ctx.beginPath();
 ctx.rect(20, 40, 50, 50);
 ctx.fillStyle = "#FF0000";
 ctx.fill();
-ctx.closePath();
+ctx.closePath(); +``` -

把全部指令放到 ctx.beginPath() 方法 和 ctx.closePath() 方法之间。我们使用 ctx.rect() 方法创建了一个矩形。这个方法的第一组参数(20,40)是确定这个矩形的左上角在画布上的坐标,第二组参数(50, 50)是指定矩形的宽度和高度。例子中矩形左上角的 x 坐标为 20 像素,y 坐标为 40 像素;宽和高各为 50 像素,这样画出一个完美的正方形。ctx.fillStyle 属性是用于填充绘画的颜色,这里填充的颜色为红色。ctx.fill() 方法是填充路径的内容区域生成实心的图形。

+把全部指令放到 ctx.beginPath() 方法 和 ctx.closePath() 方法之间。我们使用 ctx.rect() 方法创建了一个矩形。这个方法的第一组参数(20,40)是确定这个矩形的左上角在画布上的坐标,第二组参数(50, 50)是指定矩形的宽度和高度。例子中矩形左上角的 x 坐标为 20 像素,y 坐标为 40 像素;宽和高各为 50 像素,这样画出一个完美的正方形。ctx.fillStyle 属性是用于填充绘画的颜色,这里填充的颜色为红色。ctx.fill() 方法是填充路径的内容区域生成实心的图形。 -

我们不局限于绘制矩形 — 下面这段代码会绘制出一个绿色的圆;尝试添加到 JavaScript 代码的底部,保存并刷新:

+我们不局限于绘制矩形 — 下面这段代码会绘制出一个绿色的圆;尝试添加到 JavaScript 代码的底部,保存并刷新: -
ctx.beginPath();
-ctx.arc(240, 160, 20, 0, Math.PI*2, false);
-ctx.fillStyle = "green";
-ctx.fill();
-ctx.closePath();
+ ctx.beginPath(); + ctx.arc(240, 160, 20, 0, Math.PI*2, false); + ctx.fillStyle = "green"; + ctx.fill(); + ctx.closePath(); -

正如你所见,我们再一次使用了 ctx.beginPath() 方法 和 ctx.closePath() 方法;在这两个方法中间,最重要的部分是 ctx.arc() 方法。它需要六个参数:

+正如你所见,我们再一次使用了 ctx.beginPath() 方法 和 ctx.closePath() 方法;在这两个方法中间,最重要的部分是 ctx.arc() 方法。它需要六个参数: -
    -
  • 圆心的 xy 轴坐标
  • -
  • 半径
  • -
  • 起始角度,结束角度。以弧度计(弧的圆形的三点钟位置是 0 度)
  • -
  • 规定应该逆时针还是顺时针绘图。false = 顺时针,true = 逆时针。(可选)
  • -
+- `圆心的 x` 和 `y` 轴坐标 +- 半径 +- 起始角度,结束角度。以弧度计(弧的圆形的三点钟位置是 0 度) +- 规定应该逆时针还是顺时针绘图。false = 顺时针,true = 逆时针。(可选) -

ctx.fillStyle 属性的值看起来和之前不大一样。这是因为它与 CSS 一样,颜色可以指定为十六进制值也可以指定为 rgba() 函数,或者任何其他可用的颜色值函数。

+ctx.fillStyle 属性的值看起来和之前不大一样。这是因为它与 CSS 一样,颜色可以指定为十六进制值也可以指定为 rgba() 函数,或者任何其他可用的颜色值函数。 -

当然我们也可以不使用 ctx.fill() 函数来填充图形和颜色,用 ctx.stroke() 函数来绘制定义图形的路径。试着将这段代码添加到您的 JavaScript:

+当然我们也可以不使用 ctx.fill() 函数来填充图形和颜色,用 ctx.stroke() 函数来绘制定义图形的路径。试着将这段代码添加到您的 JavaScript: -
ctx.beginPath();
+```js
+ctx.beginPath();
 ctx.rect(160, 10, 100, 40);
 ctx.strokeStyle = "rgba(0, 0, 255, 0.5)";
 ctx.stroke();
-ctx.closePath();
+ctx.closePath(); +``` -

上面的代码绘制出一个蓝色边框的空心矩形。由于 rgba() 函数的特性,边框为蓝色半透明的状态。

+上面的代码绘制出一个蓝色边框的空心矩形。由于 rgba() 函数的特性,边框为蓝色半透明的状态。 -

比对你的代码

+## 比对你的代码 -

以上是第一节的全部代码,可以运行在 JSFiddle(在线 JS 代码调试工具)上:

+以上是第一节的全部代码,可以运行在 JSFiddle(在线 JS 代码调试工具)上: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/x62h15e2/","","370")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/x62h15e2/","","370")}} -
-

备注: 练习:尝试改变给定几何图形的大小和颜色。

-
+> **备注:** 练习:尝试改变给定几何图形的大小和颜色。 -

下一节

+## 下一节 -

现在我们已经创建了基本的 HTML 和关于画布的基本知识。我们继续第二节,如何让球在游戏中动起来 — 让球动起来

+现在我们已经创建了基本的 HTML 和关于画布的基本知识。我们继续第二节,如何让球在游戏中动起来 — [让球动起来](/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Move_the_ball)。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.md index 84ee627787f994..de97a00be280fd 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/finishing_up/index.md @@ -12,44 +12,44 @@ tags: translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Finishing_up original_slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/收尾工作 --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{Previous("Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}}

+{{Previous("Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}} -
-

本篇为 Gamedev Canvas tutorial 10 节教程中的第 10 节也是最后一节。完成这篇课程后,你可以在 Gamedev-Canvas-workshop/lesson10.html 找到我们的源代码。

-
+本篇为 [Gamedev Canvas tutorial ](/en-US/docs/Games/Workflows/Breakout_game_from_scratch)10 节教程中的**第 10 节也是最后一节。**完成这篇课程后,你可以在 [Gamedev-Canvas-workshop/lesson10.html](https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson10.html) 找到我们的源代码。 -

不管我们做什么游戏,它总是存在优化的空间。例如,我们可以为玩家多提供几条命,让他们能在发生一两次失误的情况下顺利完成游戏。或者,我们也可以在渲染代码上下工夫。

+不管我们做什么游戏,它总是存在优化的空间。例如,我们可以为玩家多提供几条命,让他们能在发生一两次失误的情况下顺利完成游戏。或者,我们也可以在渲染代码上下工夫。 -

加入生命机制

+## 加入生命机制 -

在游戏中实现生命机制的思路很直接。让我们先新增一个变量,用来存储其生命值。把下面这行代码和我们声明其它变量的代码放在一起:

+在游戏中实现生命机制的思路很直接。让我们先新增一个变量,用来存储其生命值。把下面这行代码和我们声明其它变量的代码放在一起: -
var lives = 3;
+```js +var lives = 3; +``` -

在 canvas 上绘制生命值计数的做法几乎和绘制分数一样——把下面的函数添加到drawScore() 函数后面:

+在 canvas 上绘制生命值计数的做法几乎和绘制分数一样——把下面的函数添加到`drawScore()` 函数后面: -
function drawLives() {
+```js
+function drawLives() {
     ctx.font = "16px Arial";
     ctx.fillStyle = "#0095DD";
     ctx.fillText("Lives: "+lives, canvas.width-65, 20);
-}
+} +``` -

当玩家失误时,我们不立即结束游戏,而是减少生命计数,直到为零。在玩家用掉一条命后,我们也可以重置小球和球板位置。那么,在函数 draw() 中将下面三行:

+当玩家失误时,我们不立即结束游戏,而是减少生命计数,直到为零。在玩家用掉一条命后,我们也可以重置小球和球板位置。那么,在函数 `draw()` 中将下面三行: -
alert("GAME OVER");
+```js
+alert("GAME OVER");
 document.location.reload();
 clearInterval(interval); // Needed for Chrome to end game
-
- - - +``` +替换为下面的代码,注意到我们加入了一点点逻辑控制: -

替换为下面的代码,注意到我们加入了一点点逻辑控制:

- -
lives--;
+```js
+lives--;
 if(!lives) {
     alert("GAME OVER");
     document.location.reload();
@@ -61,52 +61,59 @@ else {
     dx = 2;
     dy = -2;
     paddleX = (canvas.width-paddleWidth)/2;
-}
+} +``` -

现在,当小球碰到屏幕底边时,我们让变量lives 的值减一。如果生命用尽,游戏就宣告结束;否则就重置小球与球板的位置,以及小球的速度。

+现在,当小球碰到屏幕底边时,我们让变量`lives` 的值减一。如果生命用尽,游戏就宣告结束;否则就重置小球与球板的位置,以及小球的速度。 -

渲染生命值

+### 渲染生命值 -

现在只需在 draw() 函数内调用drawLives() 即可。让我们把它加到drawScore() 的下一行:

+现在只需在 `draw()` 函数内调用`drawLives()` 即可。让我们把它加到`drawScore()` 的下一行: -
drawLives();
-
+```js +drawLives(); +``` -

用 requestAnimationFrame() 优化渲染

+## 用 requestAnimationFrame() 优化渲染 -

现在让我们处理一些与游戏机制无关,但与画面渲染相关的东西。和我们目前使用{{domxref("windowTimers.setInterval()", "setInterval()")}} 实现的固定帧率渲染相比,{{domxref("window.requestAnimationFrame", "requestAnimationFrame")}} 能让浏览器更好地渲染画面。让我们把下面这行代码:

+现在让我们处理一些与游戏机制无关,但与画面渲染相关的东西。和我们目前使用{{domxref("windowTimers.setInterval()", "setInterval()")}} 实现的固定帧率渲染相比,{{domxref("window.requestAnimationFrame", "requestAnimationFrame")}} 能让浏览器更好地渲染画面。让我们把下面这行代码: -
var interval = setInterval(draw, 10);
+```js +var interval = setInterval(draw, 10); +``` -

替换为:

+替换为: -
draw();
+```js +draw(); +``` -

再把代码中的每一处

+再把代码中的每一处 -
clearInterval(interval); // Needed for Chrome to end game
-
+```js +clearInterval(interval); // Needed for Chrome to end game +``` -

删除。然后,在 draw() 函数的最下方(右花括号之前)加入下面这行代码。它的作用是使 draw() 函数递归调用自身:

+删除。然后,在 `draw()` 函数的最下方(右花括号之前)加入下面这行代码。它的作用是使 `draw()` 函数递归调用自身: -
requestAnimationFrame(draw);
+```js +requestAnimationFrame(draw); +``` -

现在 draw() 函数在 requestAnimationFrame() 的循环中被反复调用,之先前做法最大的不同是,我们将帧率的控制权交给浏览器,而不是固定的 10 毫秒。浏览器会在适当的时机同步帧率,并且只在必要的时候才刷新渲染的图形。这使得我们的动画比之前的 setInterval() 方法更加流畅且高效。

+现在 `draw()` 函数在 `requestAnimationFrame()` 的循环中被反复调用,之先前做法最大的不同是,我们将帧率的控制权交给浏览器,而不是固定的 10 毫秒。浏览器会在适当的时机同步帧率,并且只在必要的时候才刷新渲染的图形。这使得我们的动画比之前的 `setInterval()` 方法更加流畅且高效。 -

比较你的代码

+## 比较你的代码 -

我们的游戏的最终版本已经完成!以上。

+我们的游戏的最终版本已经完成!以上。 -

{{JSFiddleEmbed("https://jsfiddle.net/raymondjplante/dfh2tpu1/","","395")}}

+{{JSFiddleEmbed("https://jsfiddle.net/raymondjplante/dfh2tpu1/","","395")}} -
-

备注: 试着改变生命的数目和球从球板上反弹的角度。

-
+> **备注:** 试着改变生命的数目和球从球板上反弹的角度。 -

游戏结束——暂时看来!

+## 游戏结束——暂时看来! -

祝贺你——你完成了本教程的所有小节!现在,你应该已经掌握 canvas 操纵的基础和 2D 游戏背后的逻辑了。是时候去学习一些框架,继续你的游戏开发之旅了!你可以看看本系列的姊妹篇:用 Phaser 制作 2D 打砖块游戏 或者 Cyber Orb built in Phaser 。或者,你也可以在 MDN 游戏区 中获得灵感和更多知识。

+祝贺你——你完成了本教程的所有小节!现在,你应该已经掌握 canvas 操纵的基础和 2D 游戏背后的逻辑了。是时候去学习一些框架,继续你的游戏开发之旅了!你可以看看本系列的姊妹篇:[用 Phaser 制作 2D 打砖块游戏](/en-US/docs/Games/Workflows/2D_breakout_game_Phaser) 或者 [Cyber Orb built in Phaser](/en-US/docs/Games/Workflows/HTML5_Gamedev_Phaser_Device_Orientation) 。或者,你也可以在 [MDN 游戏区](/en/docs/Games) 中获得灵感和更多知识。 -

你也可以回到本教程的目录页。祝编程愉快!

+你也可以回到[本教程的目录页](/en-US/docs/Games/Workflows/Breakout_game_from_scratch)。祝编程愉快! -

{{Previous("Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}}

+{{Previous("Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.md index efe2a34eaca488..994827f9778dd8 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.md @@ -3,77 +3,83 @@ title: 游戏结束 slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Game_over translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Game_over --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field")}} -
-

这是 Gamedev Canvas tutorial教程的第五章。您可以在完成本课程后在这里Gamedev-Canvas-workshop/lesson5.html找到源代码。

-
+这是 [Gamedev Canvas tutorial](/en-US/docs/Games/Workflows/Breakout_game_from_scratch)教程的第五章。您可以在完成本课程后在这里[Gamedev-Canvas-workshop/lesson5.html](https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson05.html)找到源代码。 -

看球从墙上反弹,并能够移动球盘是很有趣的。但除此之外,游戏什么都不做,也没有任何进展或最终目标。从游戏的角度来看,我们需要一个 game over。失败的逻辑很简单。如果你的球拍错过了球,并且球到达屏幕的底部边缘,那么游戏就结束了。

+看球从墙上反弹,并能够移动球盘是很有趣的。但除此之外,游戏什么都不做,也没有任何进展或最终目标。从游戏的角度来看,我们需要一个 game over。失败的逻辑很简单。如果你的球拍错过了球,并且球到达屏幕的底部边缘,那么游戏就结束了。 -

实现游戏失败

+## 实现游戏失败 -

让我们在代码中实现,下面是第三章里的一段代码,让球从墙上反弹:

+让我们在代码中实现,下面是第三章里的一段代码,让球从墙上反弹: -
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
+```js
+if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
     dx = -dx;
 }
 
-if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
+if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
     dy = -dy;
-}
+} +``` -

我们不需要让球从四面墙上反弹,应该只允许三个 - 左,上,右。击中底部墙将结束游戏。我们将编辑第二个 if 代码块,这是一个 if else 块,当球碰撞到画布的底部边缘时,它会触发我们的“游戏结束”状态。现在我们将保持简单,显示一条警告消息,并通过重新加载页面重新开始游戏。

+我们不需要让球从四面墙上反弹,应该只允许三个 - 左,上,右。击中底部墙将结束游戏。我们将编辑第二个 if 代码块,这是一个 if else 块,当球碰撞到画布的底部边缘时,它会触发我们的“游戏结束”状态。现在我们将保持简单,显示一条警告消息,并通过重新加载页面重新开始游戏。 -

第一步,把您最开始使用的 setInterval() 函数

+第一步,把您最开始使用的 `setInterval()` 函数 -
setInterval(draw, 10);
+```js +setInterval(draw, 10); +``` -

替换成:

+替换成: -
var interval = setInterval(draw, 10);
+```js +var interval = setInterval(draw, 10); +``` -

然后将第二个 if 块替换为以下内容:

+然后将第二个 if 块替换为以下内容: -
if(y + dy < ballRadius) {
+```js
+if(y + dy < ballRadius) {
     dy = -dy;
-} else if(y + dy > canvas.height-ballRadius) {
+} else if(y + dy > canvas.height-ballRadius) {
     alert("GAME OVER");
     document.location.reload();
-}
+} +``` -

让球拍接住球

+## 让球拍接住球 -

本课中最后要做的是在球和球拍之间创建一些碰撞检测,以便它可以反弹并返回到游戏区域。最简单的方法是检查球的中心是否在球拍的左边和右边之间。再次更新您修改的代码的最后一位(第二个 if 块),如下所示:

+本课中最后要做的是在球和球拍之间创建一些碰撞检测,以便它可以反弹并返回到游戏区域。最简单的方法是检查球的中心是否在球拍的左边和右边之间。再次更新您修改的代码的最后一位(第二个 if 块),如下所示: -
if(y + dy < ballRadius) {
+```js
+if(y + dy < ballRadius) {
     dy = -dy;
-} else if(y + dy > canvas.height-ballRadius) {
-    if(x > paddleX && x < paddleX + paddleWidth) {
+} else if(y + dy > canvas.height-ballRadius) {
+    if(x > paddleX && x < paddleX + paddleWidth) {
         dy = -dy;
     }
     else {
         alert("GAME OVER");
         document.location.reload();
     }
-}
+} +``` -

如果球击中画布的底部边缘,我们需要检查它是否碰到球拍。如果是的话,就像你所期望的那样反弹。如果没有,那么游戏就像以前一样结束。

+如果球击中画布的底部边缘,我们需要检查它是否碰到球拍。如果是的话,就像你所期望的那样反弹。如果没有,那么游戏就像以前一样结束。 -

代码对比

+## 代码对比 -

这里是完整例子,对比一下代码吧!

+这里是完整例子,对比一下代码吧! -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/z4zy79fo/","","320")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/z4zy79fo/","","320")}} -
-

备注: 当球碰到球拍时,让球移动得更快

-
+> **备注:** 当球碰到球拍时,让球移动得更快 -

下一步

+## 下一步 -

到目前为止,我们的表现相当不错,游戏变得更有趣,并且现在你可以输了!但它仍然缺少一些东西。让我们继续前进到第六章 - 建造砖块 - 并创造一些砖块来消灭它们。

+到目前为止,我们的表现相当不错,游戏变得更有趣,并且现在你可以输了!但它仍然缺少一些东西。让我们继续前进到第六章 - [建造砖块](/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Build_the_brick_field) - 并创造一些砖块来消灭它们。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/index.md index b720d7f35da1e8..b66cc5456d7ba5 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/index.md @@ -12,49 +12,41 @@ tags: - Tutorial translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{Next("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it")}}

+{{Next("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it")}} -

在这里我们将完全使用 JavaScript 语言基于 HTML5 的 canvas 标签,一步一步的绘制一个简单的 MDN 消除游戏。

+在这里我们将完全使用 JavaScript 语言基于 HTML5 的 canvas 标签,一步一步的绘制一个简单的 MDN 消除游戏。 -

过程中的每一步都会有例子可供体验,让你更清晰的了解他的制作过程。你将学习到如何使用 canvas 标签的基本语法去实现简单游戏的渲染、动画、碰撞、控制胜负。

+过程中的每一步都会有例子可供体验,让你更清晰的了解他的制作过程。你将学习到如何使用 canvas 标签的基本语法去实现简单游戏的渲染、动画、碰撞、控制胜负。 -

为了更快速高效的学习本系列教程,你需要掌握 JavaScript 的一些基础知识。学习完本教程之后你就可以创建自己的网页小游戏了。

+为了更快速高效的学习本系列教程,你需要掌握 [JavaScript](/en-US/Learn/Getting_started_with_the_web/JavaScript_basics) 的一些基础知识。学习完本教程之后你就可以创建自己的网页小游戏了。 -

Gameplay screen from the game MDN Breakout where you can use your paddle to bounce the ball and destroy the brick field, with keeping the score and lives.

+![Gameplay screen from the game MDN Breakout where you can use your paddle to bounce the ball and destroy the brick field, with keeping the score and lives.](mdn-breakout-gameplay.png) -

教程详情

+## 教程详情 -

+全部教程 — [MDN 消除小游戏](http://breakout.enclavegames.com/lesson10.html) 的各个版本我们正一起管理并托管到 [GitHub](https://github.com/end3r/Canvas-gamedev-workshop) 上: -

全部教程 — MDN 消除小游戏 的各个版本我们正一起管理并托管到 GitHub 上:

+1. [创建、绘制画布](/zh-CN/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it) +2. [让球动起来](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball) +3. [反弹的墙](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls) +4. [键盘操作](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls) +5. [游戏结束](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over) +6. [创建砖块](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field) +7. [撞击处理](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection) +8. [统计得分、获得胜利](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win) +9. [鼠标控制](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls) +10. [完成](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up) -
    -
  1. 创建、绘制画布
  2. -
  3. 让球动起来
  4. -
  5. 反弹的墙
  6. -
  7. 键盘操作
  8. -
  9. 游戏结束
  10. -
  11. 创建砖块
  12. -
  13. 撞击处理
  14. -
  15. 统计得分、获得胜利
  16. -
  17. 鼠标控制
  18. -
  19. 完成
  20. -
+对于实现一个网页游戏而言,最好的方式是从纯 JavaScirpt 着手,那样可以让我们建立更坚实的基础。之后你可以在你的项目中选择你喜欢的框架。框架也只是用 JavaScript 语言实现的工具;如果你想要在项目中使用框架,你必须先了解语言本身。框架可以帮你提高开发效率并生成一些基础的内容;但是如果没有达到你的预期,你只能慢慢调试或者使用原生 JavaScript 去实现解决方案。 -

对于实现一个网页游戏而言,最好的方式是从纯 JavaScirpt 着手,那样可以让我们建立更坚实的基础。之后你可以在你的项目中选择你喜欢的框架。框架也只是用 JavaScript 语言实现的工具;如果你想要在项目中使用框架,你必须先了解语言本身。框架可以帮你提高开发效率并生成一些基础的内容;但是如果没有达到你的预期,你只能慢慢调试或者使用原生 JavaScript 去实现解决方案。

+> **备注:** 如果你对使用第三方游戏资源库开发 2d 网页游戏感兴趣,可以参考本系列教程的 [2D breakout game using Phaser](/en-US/docs/Games/Workflows/2D_breakout_game_Phaser). -
-

备注: 如果你对使用第三方游戏资源库开发 2d 网页游戏感兴趣,可以参考本系列教程的 2D breakout game using Phaser.

-
+> **备注:** 本系列教程可以用作游戏开发工作室的素材资源。如果你想探讨普通的游戏开发,你可以利用[Gamedev Canvas Content Kit](https://github.com/end3r/Gamedev-Canvas-Content-Kit)以及本教程的内容。 -
-

备注: 本系列教程可以用作游戏开发工作室的素材资源。如果你想探讨普通的游戏开发,你可以利用Gamedev Canvas Content Kit以及本教程的内容。

-
+## 下一步 -

下一步

+好,让我们开始吧。第一步 — [创建、绘制画布](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it) -

好,让我们开始吧。第一步 — 创建、绘制画布

- -

{{Next("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it")}}

+{{Next("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.md index a5436a070da370..3478022622ab03 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/mouse_controls/index.md @@ -12,49 +12,49 @@ tags: translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Mouse_controls original_slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/鼠标控制 --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up")}} -
-

本篇为 Gamedev Canvas tutorial 10 节教程中的第 9 节。在你完成这篇课程之后,你可以在 Gamedev-Canvas-workshop/lesson9.html 找到我们的源代码。

-
+本篇为 [Gamedev Canvas tutorial](/en-US/docs/Games/Workflows/Breakout_game_from_scratch) 10 节教程中的**第 9 节**。在你完成这篇课程之后,你可以在 [Gamedev-Canvas-workshop/lesson9.html](https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson09.html) 找到我们的源代码。 -

这个游戏实际已经完成,现在让我们着手去润色。我们已经添加过键盘控制,而加入鼠标控制也同样简单。

+这个游戏实际已经完成,现在让我们着手去润色。我们已经添加过键盘控制,而加入鼠标控制也同样简单。 -

监听鼠标移动

+## 监听鼠标移动 -

监听鼠标移动甚至比监听按键更简单:只需监听 {{event("mousemove")}} 这个事件即可。把下面这行代码和其它事件监听代码放在一起,在 keyup event 的下一行:

+监听鼠标移动甚至比监听按键更简单:只需监听 {{event("mousemove")}} 这个事件即可。把下面这行代码和其它事件监听代码放在一起,在 `keyup event` 的下一行: -
document.addEventListener("mousemove", mouseMoveHandler, false);
+```js +document.addEventListener("mousemove", mouseMoveHandler, false); +``` -

将球板移动绑定到鼠标移动

+## 将球板移动绑定到鼠标移动 -

我们可以根据鼠标光标位置来更新球板位置——下面这个函数正是做这件事的。把这个函数加到你的代码中,接在你刚刚加入的那行后面:

+我们可以根据鼠标光标位置来更新球板位置——下面这个函数正是做这件事的。把这个函数加到你的代码中,接在你刚刚加入的那行后面: -
function mouseMoveHandler(e) {
+```js
+function mouseMoveHandler(e) {
     var relativeX = e.clientX - canvas.offsetLeft;
-    if(relativeX > 0 && relativeX < canvas.width) {
+    if(relativeX > 0 && relativeX < canvas.width) {
         paddleX = relativeX - paddleWidth/2;
     }
-}
+} +``` -

在这个函数中,我们首先计算 relativeX 的值,它等于鼠标在视窗中的水平位置 (e.clientX) 减去 canvas 元素左边框到视窗左边框的距离 (canvas.offsetLeft) —— 这就得到了 canvas 元素左边框到鼠标的距离。若这个值大于零,且小于 canvas 的宽度,说明鼠标指针落在 canvas 边界内,这时就把 paddleX (等于球板左边缘的坐标)设为 relativeX 减速去球板宽度的一半。这样就确保位移是相对于球板中心进行的。

+在这个函数中,我们首先计算 `relativeX` 的值,它等于鼠标在视窗中的水平位置 (`e.clientX`) 减去 canvas 元素左边框到视窗左边框的距离 (`canvas.offsetLeft`) —— 这就得到了 canvas 元素左边框到鼠标的距离。若这个值大于零,且小于 canvas 的宽度,说明鼠标指针落在 canvas 边界内,这时就把 `paddleX` (等于球板左边缘的坐标)设为 `relativeX` 减速去球板宽度的一半。这样就确保位移是相对于球板中心进行的。 -

现在球板将跟随鼠标指针。不过由于我们将球板移动限制在 canvas 大小范围内,它不会从两边完全消失。

+现在球板将跟随鼠标指针。不过由于我们将球板移动限制在 canvas 大小范围内,它不会从两边完全消失。 -

比较你的代码

+## 比较你的代码 -

以下是我们的示例代码,以便与您进行比较:

+以下是我们的示例代码,以便与您进行比较: -

{{JSFiddleEmbed("https://jsfiddle.net/raymondjplante/vt7y5hcp/","","395")}}

+{{JSFiddleEmbed("https://jsfiddle.net/raymondjplante/vt7y5hcp/","","395")}} -
-

练习:调整球板移动的范围,使得整个球板总是可见,而不是在移动到边缘时被遮住一半。

-
+练习:调整球板移动的范围,使得整个球板总是可见,而不是在移动到边缘时被遮住一半。 -

下一步

+## 下一步 -

现在我们已经拥有一个完整的游戏。我们的系列教程将以一些细节上的调整作为结束。

+现在我们已经拥有一个完整的游戏。我们的系列教程将以一些细节上的调整作为[结束。](/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Finishing_up) -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.md index 7418ae98b3ac44..fb6d38a6d82d97 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.md @@ -12,66 +12,69 @@ tags: - movement translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball --- -
{{GamesSidebar}}
+{{GamesSidebar}}{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls")}} -
{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls")}}
+本篇是 [Gamedev Canvas tutorial](/en-US/docs/Games/Workflows/Breakout_game_from_scratch) 10 节教程中的第二节。如果你完成了本篇教程之后,你可以从 [Gamedev-Canvas-workshop/lesson2.html](https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson02.html) 看到源码。 -
-

本篇是 Gamedev Canvas tutorial 10 节教程中的第二节。如果你完成了本篇教程之后,你可以从 Gamedev-Canvas-workshop/lesson2.html 看到源码。

-
+从上一节中你已经知道如何去绘制一个球。现在让我们使它动起来。从技术上讲,我们将在画布上绘制一个球,之后让它消失,然后在一个稍微不用的位置上再绘制一个一样的球。就想电影里的每一帧动起来的感觉。 -

从上一节中你已经知道如何去绘制一个球。现在让我们使它动起来。从技术上讲,我们将在画布上绘制一个球,之后让它消失,然后在一个稍微不用的位置上再绘制一个一样的球。就想电影里的每一帧动起来的感觉。

+我们需要定义一个绘图函数,每次使用一组不同的变量改变球体的位置;循环调用以保持画布上每一帧不断更新。你可以使用 JavaScript 时间函数 {{domxref("WindowTimers.setInterval()", "setInterval()")}} 或者 {{domxref("window.requestAnimationFrame()")}}。 -

我们需要定义一个绘图函数,每次使用一组不同的变量改变球体的位置;循环调用以保持画布上每一帧不断更新。你可以使用 JavaScript 时间函数 {{domxref("WindowTimers.setInterval()", "setInterval()")}} 或者 {{domxref("window.requestAnimationFrame()")}}。

+在你的 HTML 文件只保留前两行,删除其他所有的 JavaScript 代码并在 draw() 函数中添加以下内容保证每 10 毫秒执行一次 draw() 函数: -

在你的 HTML 文件只保留前两行,删除其他所有的 JavaScript 代码并在 draw() 函数中添加以下内容保证每 10 毫秒执行一次 draw() 函数:

- -
function draw() {
+```js
+function draw() {
     // drawing code
 }
-setInterval(draw, 10);
+setInterval(draw, 10); +``` -

得益于 setInterval 的无限性,使得 draw() 函数将每 10 毫秒就会被调用,除非我们停止它。现在,我们来绘制小球吧,在 draw() 函数中添加以下内容:

+得益于 `setInterval` 的无限性,使得 `draw()` 函数将每 10 毫秒就会被调用,除非我们停止它。现在,我们来绘制小球吧,在 `draw()` 函数中添加以下内容: -
ctx.beginPath();
+```js
+ctx.beginPath();
 ctx.arc(50, 50, 10, 0, Math.PI*2);
 ctx.fillStyle = "#0095DD";
 ctx.fill();
 ctx.closePath();
-
+``` -

现在,尝试更新你的代码,球会在每一帧画面被绘制

+现在,尝试更新你的代码,球会在每一帧画面被绘制 -

让球动起来

+## 让球动起来 -

你不会注意到球正在不停地被重新刷,因为它没有移动。让我们改变这种情况。首先,我们不再使用固定位置 (50,50),而是用 x 和 y 的变量来定义画布底部的起始点,然后使用这些变量来定义圆被绘制的位置。

+你不会注意到球正在不停地被重新刷,因为它没有移动。让我们改变这种情况。首先,我们不再使用固定位置 (50,50),而是用 x 和 y 的变量来定义画布底部的起始点,然后使用这些变量来定义圆被绘制的位置。 -

首先,在draw()函数上方添加以下两行,以定义xy

+首先,在`draw()`函数上方添加以下两行,以定义`x`和`y`: -
var x = canvas.width/2;
+```js
+var x = canvas.width/2;
 var y = canvas.height-30;
-
+``` -

接下来更新 draw() 函数,在 arc() 方法中使用 xy 变量,如下面高亮行所示:

+接下来更新 `draw()` 函数,在 `arc() `方法中使用 `x` 和 `y` 变量,如下面高亮行所示: -
function draw() {
+```js
+function draw() {
     ctx.beginPath();
     ctx.arc(x, y, 10, 0, Math.PI*2);
     ctx.fillStyle = "#0095DD";
     ctx.fill();
     ctx.closePath();
 }
-
+``` -

现在到了最重要的部分:我们想要在每一帧都被绘制出来之后,给 xy 添加一个较小的值,让它看起来像是在移动。让我们将这些值定义为 dxdy,并将它们的值分别设为 2-2。在你的 x 和 y 变量声明下方添加以下内容:

+现在到了最重要的部分:我们想要在每一帧都被绘制出来之后,给 `x` 和 `y` 添加一个较小的值,让它看起来像是在移动。让我们将这些值定义为 `dx` 和 `dy`,并将它们的值分别设为 `2` 和 `-2`。在你的 x 和 y 变量声明下方添加以下内容: -
var dx = 2;
+```js
+var dx = 2;
 var dy = -2;
-
+``` -

最后要做的是在每一帧上更新 xy,在每一次更新中,把球画在新的位置上。将下面的两条新线添加到你的 draw() 函数:

+最后要做的是在每一帧上更新 `x` 和 `y`,在每一次更新中,把球画在新的位置上。将下面的两条新线添加到你的 `draw()` 函数: -
function draw() {
+```js
+function draw() {
     ctx.beginPath();
     ctx.arc(x, y, 10, 0, Math.PI*2);
     ctx.fillStyle = "#0095DD";
@@ -79,19 +82,21 @@ var dy = -2;
     ctx.closePath();
     x += dx;
     y += dy;
-}
+} +``` -

再次保存代码,并在浏览器中尝试。很好,尽管看起来球在后面留下了痕迹:

+再次保存代码,并在浏览器中尝试。很好,尽管看起来球在后面留下了痕迹: -

+![](ball-trail.png) -

在每一帧更新之前清空画布

+## 在每一帧更新之前清空画布 -

球移动时留下了轨迹,因为我们在每一帧上都画了一个新的圆,而没有去掉之前的一个圆。不要担心,因为有一个方法来清空画布的内容:clearRect()。该方法有四个参数:矩形左上角的 xy 坐标,以及矩形的右下角的 xy 坐标。这个矩形覆盖的整个区域里,之前所画的任何内容将被清除。

+球移动时留下了轨迹,因为我们在每一帧上都画了一个新的圆,而没有去掉之前的一个圆。不要担心,因为有一个方法来清空画布的内容:[`clearRect()`](/en-US/docs/Web/API/CanvasRenderingContext2D/clearRect)。该方法有四个参数:矩形左上角的 `x` 和 `y` 坐标,以及矩形的右下角的 `x` 和 `y` 坐标。这个矩形覆盖的整个区域里,之前所画的任何内容将被清除。 -

将下列高亮显示行添加到 draw() 函数:

+将下列高亮显示行添加到 `draw()` 函数: -
function draw() {
+```js
+function draw() {
     ctx.clearRect(0, 0, canvas.width, canvas.height);
     ctx.beginPath();
     ctx.arc(x, y, 10, 0, Math.PI*2);
@@ -101,17 +106,18 @@ var dy = -2;
     x += dx;
     y += dy;
 }
-
+``` -

保存您的代码并再次尝试,这次你将看到球移动后没有留下轨迹。每隔 10 毫秒,画布就会被清除,蓝色的圆圈 (我们的球) 将被绘制在一个给定的位置上,而 xy 的值将在下一个帧被更新。

+保存您的代码并再次尝试,这次你将看到球移动后没有留下轨迹。每隔 10 毫秒,画布就会被清除,蓝色的圆圈 (我们的球) 将被绘制在一个给定的位置上,而 `x` 和 `y` 的值将在下一个帧被更新。 -

保持代码整洁

+## 保持代码整洁 -

在接下来的几篇文章中,我们将在 draw() 函数中添加越来越多的命令,因此尽可能保持简单和整洁是很好的。让我们从把绘制球的代码移至一个单独的函数。

+在接下来的几篇文章中,我们将在 `draw()` 函数中添加越来越多的命令,因此尽可能保持简单和整洁是很好的。让我们从把绘制球的代码移至一个单独的函数。 -

用以下两个函数替换现有的 draw() 函数:

+用以下两个函数替换现有的 `draw()` 函数: -
function drawBall() {
+```js
+function drawBall() {
     ctx.beginPath();
     ctx.arc(x, y, 10, 0, Math.PI*2);
     ctx.fillStyle = "#0095DD";
@@ -124,20 +130,19 @@ function draw() {
     drawBall();
     x += dx;
     y += dy;
-}
+} +``` -

比较你的代码

+## 比较你的代码 -

您可以在下面的实时演示中查看本文的代码,并使用它来更好地了解其工作原理:

+您可以在下面的实时演示中查看本文的代码,并使用它来更好地了解其工作原理: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/3x5foxb1/","","415")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/3x5foxb1/","","415")}} -
-

练习:尝试改变移动球的速度,或者移动球的方向。

-
+练习:尝试改变移动球的速度,或者移动球的方向。 -

下一步

+## 下一步 -

我们已经画了我们的球,并将其移动,但它仍然消失在画布的边缘。在第三章中,我们将探讨如何使其 从墙壁上反弹.

+我们已经画了我们的球,并将其移动,但它仍然消失在画布的边缘。在第三章中,我们将探讨如何使其 [从墙壁上反弹](/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Bounce_off_the_walls). -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.md index 4cb904f9ae9f48..c5920bbaef893d 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.md @@ -3,58 +3,63 @@ title: 球板及键盘控制 slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over")}} -
-

这是Gamedev Canvas tutorial中的第四章。完成本课程后,你可以在Gamedev-Canvas-workshop/lesson4.html找到源码。

-
+这是[Gamedev Canvas tutorial](/en-US/docs/Games/Workflows/Breakout_game_from_scratch)中的第四章。完成本课程后,你可以在[Gamedev-Canvas-workshop/lesson4.html](https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson04.html)找到源码。 -

你可以看到球自由的、无限次的在墙壁上反弹,但是没有和我们发生任何交互。如果我们没有对它的控制操作,这仍然不是一个游戏。下面,我们新增一些用户操作:一个可以控制球的球板。

+你可以看到球自由的、无限次的在墙壁上反弹,但是没有和我们发生任何交互。如果我们没有对它的控制操作,这仍然不是一个游戏。下面,我们新增一些用户操作:一个可以控制球的球板。 -

定义一个球板去接球

+## 定义一个球板去接球 -

我们需要添加一个球板去接球:为此需要先定义一些变量。在你的代码的顶部的其它变量下方添加下列代码:

+我们需要添加一个球板去接球:为此需要先定义一些变量。在你的代码的顶部的其它变量下方添加下列代码: -
var paddleHeight = 10;
+```js
+var paddleHeight = 10;
 var paddleWidth = 75;
-var paddleX = (canvas.width-paddleWidth)/2;
+var paddleX = (canvas.width-paddleWidth)/2; +``` -

然后定义球拍的长和宽,以及为了之后的处理同时定义 x 轴上的初始位置。新建一个方法来在页面上描绘球板。把下列代码添加到你的drawBall()方法里去

+然后定义球拍的长和宽,以及为了之后的处理同时定义 x 轴上的初始位置。新建一个方法来在页面上描绘球板。把下列代码添加到你的`drawBall()方法里去`: -
function drawPaddle() {
+```js
+function drawPaddle() {
     ctx.beginPath();
     ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight);
     ctx.fillStyle = "#0095DD";
     ctx.fill();
     ctx.closePath();
-}
+} +``` -

允许用户控制球板

+## 允许用户控制球板 -

我们可以如愿的描绘出球板,也需让它听从用户的控制。是时候实现用键盘控制它了。我们需要:

+我们可以如愿的描绘出球板,也需让它听从用户的控制。是时候实现用键盘控制它了。我们需要: -
    -
  • 两个变量以保存左右方向键是否被按下的信息。
  • -
  • 两个事件监控器来捕捉按键的按下和松开动作。我们需要运行一些代码以在按键被按下时可以控制球拍的移动
  • -
  • 两个用于处理按键被按下或松开后的事件处理方法
  • -
  • 实现左右移动球拍
  • -
+- 两个变量以保存左右方向键是否被按下的信息。 +- 两个事件监控器来捕捉按键的按下和松开动作。我们需要运行一些代码以在按键被按下时可以控制球拍的移动 +- 两个用于处理按键被按下或松开后的事件处理方法 +- 实现左右移动球拍 -

按键可以使用 boolean 变量来初始定义。在你的其它变量附近添加下列代码:

+按键可以使用 boolean 变量来初始定义。在你的其它变量附近添加下列代码: -
var rightPressed = false;
-var leftPressed = false;
+```js +var rightPressed = false; +var leftPressed = false; +``` -

这两个变量的默认值都是 false,因为在开始时按键没有被按下。为了监听按键的按下动作,我们需要添加两个监听器。把下列代码添加到底部的setInterval()的上一列去:

+这两个变量的默认值都是 false,因为在开始时按键没有被按下。为了监听按键的按下动作,我们需要添加两个监听器。把下列代码添加到底部的`setInterval()的上一列去:` -
document.addEventListener("keydown", keyDownHandler, false);
-document.addEventListener("keyup", keyUpHandler, false);
+```js +document.addEventListener("keydown", keyDownHandler, false); +document.addEventListener("keyup", keyUpHandler, false); +``` -

当你按下任何键盘上的按键,按下事件被激活时keyDownHandler()方法会被调用。对于松开时的处理也是类似的:当松开按键时keyUpHandler()方法会被调用。把下列代码添加到addEventListener()下方

+当你按下任何键盘上的按键,按下事件被激活时`keyDownHandler()方法会被调用。对于松开时的处理也是类似的:当松开按键时keyUpHandler()方法会被调用。把下列代码添加到addEventListener()下方`: -
function keyDownHandler(e) {
+```js
+function keyDownHandler(e) {
     if(e.keyCode == 39) {
         rightPressed = true;
     }
@@ -70,53 +75,57 @@ function keyUpHandler(e) {
     else if(e.keyCode == 37) {
         leftPressed = false;
     }
-}
+} +``` -

当按下一个按键,这个信息会被储存在一个变量中。每种情况下的相关变量都设置为true。当松开按键时,对应变量被设置回false

+当按下一个按键,这个信息会被储存在一个变量中。每种情况下的相关变量都设置为`true`。当松开按键时,对应变量被设置回`false`。 -

两个函数都以一个事件作为参数,由e(event) 变量表示。从这里你可以得到有用的信息:keyCode 属性是被按下的键的信息。例如,keyCode 为 37 是左箭头键,而 39 是右箭头键。如果按下左键,那么 leftPressed 变量设置为 true,当松开时,leftPressed 变量设置为 false。右键同理。

+两个函数都以一个事件作为参数,由`e`(event) 变量表示。从这里你可以得到有用的信息:keyCode 属性是被按下的键的信息。例如,keyCode 为 37 是左箭头键,而 39 是右箭头键。如果按下左键,那么 leftPressed 变量设置为 true,当松开时,leftPressed 变量设置为 false。右键同理。 -

球拍移动逻辑

+### 球拍移动逻辑 -

我们现在有用于存储按键,事件监听器和相关功能的信息的变量。现在我们将看到实际的代码来使用这些变量,并在屏幕上移动球拍。在 draw()函数内部,我们将检查每一帧被渲染的同时是否按下左或右键。我们的代码如下:

+我们现在有用于存储按键,事件监听器和相关功能的信息的变量。现在我们将看到实际的代码来使用这些变量,并在屏幕上移动球拍。在 draw()函数内部,我们将检查每一帧被渲染的同时是否按下左或右键。我们的代码如下: -
if(rightPressed) {
+```js
+if(rightPressed) {
     paddleX += 7;
 }
 else if(leftPressed) {
     paddleX -= 7;
-}
+} +``` -

如果按一下左键,球拍将向左移动 7 个像素,如果按一下右键,球拍将向右移动 7 个像素。目前这个功能可以正常工作,但是如果我们按任意一个键的时间太长,球拍就会从画布的边缘消失。我们可以通过改变代码来改善这种情况,并且只能在画布的边界内移动球拍,如下所示:

+如果按一下左键,球拍将向左移动 7 个像素,如果按一下右键,球拍将向右移动 7 个像素。目前这个功能可以正常工作,但是如果我们按任意一个键的时间太长,球拍就会从画布的边缘消失。我们可以通过改变代码来改善这种情况,并且只能在画布的边界内移动球拍,如下所示: -
if(rightPressed && paddleX < canvas.width-paddleWidth) {
+```js
+if(rightPressed && paddleX < canvas.width-paddleWidth) {
     paddleX += 7;
 }
-else if(leftPressed && paddleX > 0) {
+else if(leftPressed && paddleX > 0) {
     paddleX -= 7;
-}
+} +``` -

我们使用在Canvas左侧的 0 和右侧的canvas.width-paddleWidth之间的paddleX位置移动,这会让球拍按预期的要求移动。

+我们使用在`Canvas`左侧的 0 和右侧的`canvas.width-paddleWidth`之间的`paddleX`位置移动,这会让球拍按预期的要求移动。 -

将上面的代码块添加到底部的draw()函数中,在右大括号的上方。

+将上面的代码块添加到底部的`draw()`函数中,在右大括号的上方。 -

现在唯一要做的就是在draw()函数内调用drawPaddle()函数,将其实际渲染在屏幕上。在draw()函数内添加下面一行,就在调用drawBall()的那一行的下面:

+现在唯一要做的就是在`draw()`函数内调用`drawPaddle()`函数,将其实际渲染在屏幕上。在`draw()`函数内添加下面一行,就在调用`drawBall()`的那一行的下面: -
drawPaddle();
-
+```js +drawPaddle(); +``` -

比较你的代码

+## 比较你的代码 -

以下是我们的示例代码,以便与您进行比较:

+以下是我们的示例代码,以便与您进行比较: -

{{JSFiddleEmbed("https://jsfiddle.net/end3r/tgn3zscj/","","320")}}

+{{JSFiddleEmbed("https://jsfiddle.net/end3r/tgn3zscj/","","320")}} -
-

备注: 让球拍变快变慢,或者改变它的大小。

-
+> **备注:** 让球拍变快变慢,或者改变它的大小。 -

下一步

+## 下一步 -

现在我们有一些类似于游戏的东西。唯一的麻烦就是无论如何你都可以继续用球拍击球。这一切都将在第五章中改变,游戏结束时,我们会为游戏添加一个最后的状态。

+现在我们有一些类似于游戏的东西。唯一的麻烦就是无论如何你都可以继续用球拍击球。这一切都将在第五章中改变,[游戏结束](/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Game_over)时,我们会为游戏添加一个最后的状态。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over")}} diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.md b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.md index ec55209b59fafe..90581feabb89ee 100644 --- a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.md +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.md @@ -3,40 +3,43 @@ title: 跟踪得分和获胜 slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}} -
-

本篇为Gamedev Canvas tutorial10 节教程中的第 8 节。在你完成这篇课程之后,你可以在Gamedev-Canvas-workshop/lesson8.html找到我们的源代码。

-
+本篇为[Gamedev Canvas tutorial](/en-US/docs/Games/Workflows/Breakout_game_from_scratch)10 节教程中的**第 8 节。**在你完成这篇课程之后,你可以在[Gamedev-Canvas-workshop/lesson8.html](https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson08.html)找到我们的源代码。 -

破坏砖块真的很酷,但更酷的是,游戏可以给每个用户击破的砖块奖励分数,并保持总分。

+破坏砖块真的很酷,但更酷的是,游戏可以给每个用户击破的砖块奖励分数,并保持总分。 -

计算分数

+## 计算分数 -

如果你能在整个游戏中看到你的分数,最终你会给你的朋友留下深刻印象。你需要一个变量来记录分数。在变量的其余部分之后,将下面的内容添加到 JavaScript 中:

+如果你能在整个游戏中看到你的分数,最终你会给你的朋友留下深刻印象。你需要一个变量来记录分数。在变量的其余部分之后,将下面的内容添加到 JavaScript 中: -
var score = 0;
+```js +var score = 0; +``` -

您还需要一个 drawScore() 函数来创建和更新分数显示。在 collisionDetection() 函数之后添加以下内容:

+您还需要一个 `drawScore()` 函数来创建和更新分数显示。在 `collisionDetection()` 函数之后添加以下内容: -
function drawScore() {
+```js
+function drawScore() {
     ctx.font = "16px Arial";
     ctx.fillStyle = "#0095DD";
     ctx.fillText("Score: "+score, 8, 20);
-}
+} +``` -

在画布上绘制文本类似于绘制形状。字体定义看起来与 CSS 中的字体定义完全一样——可以在{{domxref("CanvasRenderingContext2D.font","font()")}} 方法中设置大小和字体类型。然后使用{{domxref("CanvasRenderingContext2D.fillStyle()","fillStyle()")}} 来设置字体的颜色,{{domxref("CanvasRenderingContext2D.fillText","fillText()")}} 来设置将放置在画布上的实际文本,和其放置位置。第一个参数是文本本身——上面的代码显示当前点的数量——最后两个参数是文本将放置在画布上的坐标。

+在画布上绘制文本类似于绘制形状。字体定义看起来与 CSS 中的字体定义完全一样——可以在{{domxref("CanvasRenderingContext2D.font","font()")}} 方法中设置大小和字体类型。然后使用{{domxref("CanvasRenderingContext2D.fillStyle()","fillStyle()")}} 来设置字体的颜色,{{domxref("CanvasRenderingContext2D.fillText","fillText()")}} 来设置将放置在画布上的实际文本,和其放置位置。第一个参数是文本本身——上面的代码显示当前点的数量——最后两个参数是文本将放置在画布上的坐标。 -

若要在每次击中砖块时评分,则在 collisionDetection()中添加计分规则,以在每次检测到碰撞时增加得分变量的值。将下面突出显示的行添加到代码中:

+若要在每次击中砖块时评分,则在 `collisionDetection()`中添加计分规则,以在每次检测到碰撞时增加得分变量的值。将下面突出显示的行添加到代码中: -
function collisionDetection() {
-    for(var c=0; c<brickColumnCount; c++) {
-        for(var r=0; r<brickRowCount; r++) {
+```js
+function collisionDetection() {
+    for(var c=0; c b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
                     dy = -dy;
                     b.status = 0;
                     score++;
@@ -44,22 +47,26 @@ translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Track_the_score
             }
         }
     }
-}
+} +``` -

draw() 函数调用 drawScore() ,使每一个新帧的分数都保持最新,在 draw()中添加下面的行,在 drawPaddle() 下面调用:

+从 `draw()` 函数调用 `drawScore()` ,使每一个新帧的分数都保持最新,在 `draw()`中添加下面的行,在 `drawPaddle()` 下面调用: -
drawScore();
+```js +drawScore(); +``` -

当所有砖块被破坏时显示获胜消息

+## 当所有砖块被破坏时显示获胜消息 -

收集这些点很有效,但是你不会永远添加它们 - 当所有的砖头都被破坏的时候呢?毕竟这是游戏的主要目的,所以如果收集到所有可用的点,你应该显示一个获胜的消息。将下面突出显示的部分添加到 collisionDetection() 函数中:

+收集这些点很有效,但是你不会永远添加它们 - 当所有的砖头都被破坏的时候呢?毕竟这是游戏的主要目的,所以如果收集到所有可用的点,你应该显示一个获胜的消息。将下面突出显示的部分添加到 `collisionDetection()` 函数中: -
function collisionDetection() {
-    for(var c=0; c<brickColumnCount; c++) {
-        for(var r=0; r<brickRowCount; r++) {
+```js
+function collisionDetection() {
+    for(var c=0; c b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
                     dy = -dy;
                     b.status = 0;
                     score++;
@@ -71,22 +78,21 @@ translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Track_the_score
             }
         }
     }
-}
+} +``` -

谢谢你做的这些,你的用户可以真正赢得游戏时,他们也摧毁了所有的砖块。当用户来到游戏还有一点非常重要,用户一旦点击了警告按钮, document.location.reload()函数将重新加载页面并重新启动游戏。

+谢谢你做的这些,你的用户可以真正赢得游戏时,他们也摧毁了所有的砖块。当用户来到游戏还有一点非常重要,用户一旦点击了警告按钮, `document.location.reload()`函数将重新加载页面并重新启动游戏。 -

比较你的代码

+## 比较你的代码 -

最新的代码是这样(和工程),如果你想比较和对比它与你写的:

+最新的代码是这样(和工程),如果你想比较和对比它与你写的: -

{{JSFiddleEmbed("https://jsfiddle.net/yumetodo/2m74vr9r/1/","","395")}}

+{{JSFiddleEmbed("https://jsfiddle.net/yumetodo/2m74vr9r/1/","","395")}} -
-

备注: 在每一个砖头击破后添加更多的分数,打印出收集到的点数在游戏结束警告框中。

-
+> **备注:** 在每一个砖头击破后添加更多的分数,打印出收集到的点数在游戏结束警告框中。 -

下一节

+## 下一节 -

游戏到这一步看起来相当不错。在下一课中,您将通过添加鼠标控件来扩大游戏的吸引力:Mouse controls.。

+游戏到这一步看起来相当不错。在下一课中,您将通过添加鼠标控件来扩大游戏的吸引力:[Mouse controls](/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Mouse_controls).。 -

{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}}

+{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}} diff --git a/files/zh-cn/games/tutorials/html5_gamedev_phaser_device_orientation/index.md b/files/zh-cn/games/tutorials/html5_gamedev_phaser_device_orientation/index.md index 68a7bc44f48837..2e184d7b902f40 100644 --- a/files/zh-cn/games/tutorials/html5_gamedev_phaser_device_orientation/index.md +++ b/files/zh-cn/games/tutorials/html5_gamedev_phaser_device_orientation/index.md @@ -3,57 +3,52 @@ title: 2D maze game with device orientation slug: Games/Tutorials/HTML5_Gamedev_Phaser_Device_Orientation translation_of: Games/Tutorials/HTML5_Gamedev_Phaser_Device_Orientation --- -
{{GamesSidebar}}
+{{GamesSidebar}} -
-

在本教程中,我们将介绍构建 HTML5 移动游戏的过程。本游戏使用 Device OrientationVibration APIs 来增强游戏玩法,并使用 Phaser 框架构建。为了充分理解本教程建议您先学习基础的 JavaScript 知识。

-
+在本教程中,我们将介绍构建 HTML5 移动游戏的过程。本游戏使用 [Device Orientation](/en-US/Apps/Build/gather_and_modify_data/responding_to_device_orientation_changes) 和 [Vibration ](/en-US/docs/Web/Guide/API/Vibration)**APIs** 来增强游戏玩法,并使用 [Phaser](http://phaser.io/) 框架构建。为了充分理解本教程建议您先学习基础的 JavaScript 知识。 -

Example game

+## Example game -

在本教程结束时,您将有一个功能齐全的游戏 demo:Cyber Orb 。如下所示:

+在本教程结束时,您将有一个功能齐全的游戏 demo:[Cyber Orb ](http://orb.enclavegames.com/)。如下所示: -

A 2D game board featuring a small yellow ball. There is a large black hole for the ball to escape down, and a number of barriers blocking the ball from escaping.

+![A 2D game board featuring a small yellow ball. There is a large black hole for the ball to escape down, and a number of barriers blocking the ball from escaping.](cyber-orb.png) -

Phaser framework

+## Phaser framework -

Phaser 是构建桌面和移动 HTML5 游戏的框架。它非常新,但由于热情的社区参与开发过程它同时也是快速增长的。您能够在 GitHub 查看它的开放源代码,阅读 在线文档 并浏览大量 示例 。Phaser 框架为您提供了一组工具,这些工具将加快开发速度,并帮助处理完成游戏所需的一般任务,因此您可以专注于游戏创意本身。

+[Phaser](http://phaser.io/) 是构建桌面和移动 HTML5 游戏的框架。它非常新,但由于热情的社区参与开发过程它同时也是快速增长的。您能够在[ GitHub ](https://github.com/photonstorm/phaser)查看它的开放源代码,阅读[ 在线文档](http://docs.phaser.io/) 并浏览大量 [示例 ](http://examples.phaser.io/)。Phaser 框架为您提供了一组工具,这些工具将加快开发速度,并帮助处理完成游戏所需的一般任务,因此您可以专注于游戏创意本身。 -

Starting with the project

+## Starting with the project -

您能够在 GitHub 看到它的源代码 Cyber Orb。文件夹结构非常简单:起点是 index.html。我们在该文件中初始化框架并设置 html 元素 {{htmlelement("canvas")}} 以呈现游戏。

+您能够在 GitHub 看到它的源代码 [Cyber Orb](https://github.com/EnclaveGames/Cyber-Orb)。文件夹结构非常简单:起点是 `index.html`。我们在该文件中初始化框架并设置 html 元素 {{htmlelement("canvas")}} 以呈现游戏。 -

Screenshot of the GitHub repository with the Cyber Orb game code, listing the folders and the files in the main structure.

+![Screenshot of the GitHub repository with the Cyber Orb game code, listing the folders and the files in the main structure.](cyber-orb-github.png) +您可以在您最喜爱的浏览器中打开 index 文件以启动并尝试游戏。目录中还有三个文件夹: +- `img`: 我们将在游戏中使用的所有图片。 +- `src`:定义了游戏中所有源代码的 JavaScript 文件。 +- `audio:` 在游戏中使用的声音文件。 -

您可以在您最喜爱的浏览器中打开 index 文件以启动并尝试游戏。目录中还有三个文件夹:

+## Setting up the Canvas -
    -
  • img: 我们将在游戏中使用的所有图片。
  • -
  • src:定义了游戏中所有源代码的 JavaScript 文件。
  • -
  • audio: 在游戏中使用的声音文件。
  • -
+We will be rendering our game on Canvas, but we won't do it manually — this will be taken care of by the framework. Let’s set it up: our starting point is the `index.html` file with the following content. You can create this yourself if you want to follow along: -

Setting up the Canvas

- -

We will be rendering our game on Canvas, but we won't do it manually — this will be taken care of by the framework. Let’s set it up: our starting point is the index.html file with the following content. You can create this yourself if you want to follow along:

- -
<!DOCTYPE html>
-<html>
-<head>
-    <meta charset="utf-8" />
-    <title>Cyber Orb demo</title>
-    <style> body { margin: 0; background: #333; } </style>
-    <script src="src/phaser-arcade-physics.2.2.2.min.js"></script>
-    <script src="src/Boot.js"></script>
-    <script src="src/Preloader.js"></script>
-    <script src="src/MainMenu.js"></script>
-    <script src="src/Howto.js"></script>
-    <script src="src/Game.js"></script>
-</head>
-<body>
-<script>
+```html
+
+
+
+    
+    Cyber Orb demo
+    
+    
+    
+    
+    
+    
+    
+
+
+
+
+
+```
 
-

So far we have a simple HTML website with some basic content in the <head> section: charset, title, CSS styling and the inclusion of the JavaScript files. The <body> contains initialization of the Phaser framework and the definitions of the game states.

+So far we have a simple HTML website with some basic content in the `` section: charset, title, CSS styling and the inclusion of the JavaScript files. The `` contains initialization of the Phaser framework and the definitions of the game states. -
var game = new Phaser.Game(320, 480, Phaser.CANVAS, 'game');
+```js +var game = new Phaser.Game(320, 480, Phaser.CANVAS, 'game'); +``` -

The line above will initialize the Phaser instance — the arguments are the width of the Canvas, height of the Canvas, rendering method (we're using CANVAS, but there are also WEBGL and AUTO options available) and the optional ID of the DOM container we want to put the Canvas in. If there's nothing specified in that last argument or the element is not found, the Canvas will be added to the <body> tag. Without the framework, to add the Canvas element to the page, you would have to write something like this inside the <body> tag:

+The line above will initialize the Phaser instance — the arguments are the width of the Canvas, height of the Canvas, rendering method (we're using `CANVAS`, but there are also `WEBGL` and `AUTO` options available) and the optional ID of the DOM container we want to put the Canvas in. If there's nothing specified in that last argument or the element is not found, the Canvas will be added to the \ tag. Without the framework, to add the Canvas element to the page, you would have to write something like this inside the \ tag: -
<canvas id='game' width='320' height='480'></canvas>
+```html + +``` -

The important thing to remember is that the framework is setting up helpful methods to speed up a lot of things like image manipulation or assets management, which would be a lot harder to do manually.

+The important thing to remember is that the framework is setting up helpful methods to speed up a lot of things like image manipulation or assets management, which would be a lot harder to do manually. -
-

备注: You can read the Building Monster Wants Candy article for the in-depth introduction to the basic Phaser-specific functions and methods.

-
+> **备注:** You can read the [Building Monster Wants Candy](http://gamedevelopment.tutsplus.com/tutorials/getting-started-with-phaser-building-monster-wants-candy--cms-21723) article for the in-depth introduction to the basic Phaser-specific functions and methods. -

Back to game states: the line below is adding a new state called Boot to the game:

+Back to game states: the line below is adding a new state called `Boot` to the game: -
game.state.add('Boot', Ball.Boot);
+```html +game.state.add('Boot', Ball.Boot); +``` -

The first value is the name of the state and the second one is the object we want to assign to it. The start method is starting the given state and making it active. Let's see what the states are actually.

+The first value is the name of the state and the second one is the object we want to assign to it. The `start` method is starting the given state and making it active. Let's see what the states are actually. -

Managing game states

+## Managing game states -

The states in Phaser are separate parts of the game logic; in our case we’re loading them from independent JavaScript files for better maintainability. The basic states used in this game are: Boot, Preloader, MainMenu, Howto and Game. Boot will take care of initializing a few settings, Preloader will load all of the assets like graphics and audio, MainMenu is the menu with the start button, Howto shows the "how to play" instructions and the Game state lets you actually play the game. Let's quickly go though the content of those states.

+The states in Phaser are separate parts of the game logic; in our case we’re loading them from independent JavaScript files for better maintainability. The basic states used in this game are: `Boot`, `Preloader`, `MainMenu`, `Howto` and `Game`. `Boot` will take care of initializing a few settings, `Preloader` will load all of the assets like graphics and audio, `MainMenu` is the menu with the start button, `Howto` shows the "how to play" instructions and the `Game` state lets you actually play the game. Let's quickly go though the content of those states. -

Boot.js

+### Boot.js -

The Boot state is the first one in the game.

+The `Boot` state is the first one in the game. -
var Ball = {
+```js
+var Ball = {
     _WIDTH: 320,
     _HEIGHT: 480
 };
@@ -111,15 +112,17 @@ Ball.Boot.prototype = {
         this.game.scale.pageAlignVertically = true;
         this.game.state.start('Preloader');
     }
-};
+}; +``` -

The main Ball object is defined and we're adding two variables called _WIDTH and _HEIGHT that are the width and the height of the game Canvas — they will help us position the elements on the screen. We're loading two images first that will be used later in the Preload state to show the progress of loading all the other assets. The create function holds some basic configuration: we're setting up the scaling and alignment of the Canvas, and moving on to the Preload state when everything's ready.

+The main `Ball` object is defined and we're adding two variables called `_WIDTH` and `_HEIGHT` that are the width and the height of the game Canvas — they will help us position the elements on the screen. We're loading two images first that will be used later in the `Preload` state to show the progress of loading all the other assets. The `create` function holds some basic configuration: we're setting up the scaling and alignment of the Canvas, and moving on to the `Preload` state when everything's ready. -

Preloader.js

+### Preloader.js -

The Preloader state takes care of loading all the assets:

+The `Preloader` state takes care of loading all the assets: -
Ball.Preloader = function(game) {};
+```js
+Ball.Preloader = function(game) {};
 Ball.Preloader.prototype = {
     preload: function() {
         this.preloadBg = this.add.sprite((Ball._WIDTH-297)*0.5, (Ball._HEIGHT-145)*0.5, 'preloaderBg');
@@ -135,15 +138,17 @@ Ball.Preloader.prototype = {
     create: function() {
         this.game.state.start('MainMenu');
     }
-};
+}; +``` -

There are single images, spritesheets and audio files loaded by the framework. In this state the preloadBar is showing the progress on the screen. That progress of the loaded assets is visualized by the framework with the use of one image. With every asset loaded you can see more of the preloadBar image: from 0% to 100%, updated on every frame. After all the assets are loaded, the MainMenu state is launched.

+There are single images, spritesheets and audio files loaded by the framework. In this state the `preloadBar` is showing the progress on the screen. That progress of the loaded assets is visualized by the framework with the use of one image. With every asset loaded you can see more of the `preloadBar` image: from 0% to 100%, updated on every frame. After all the assets are loaded, the `MainMenu` state is launched. - +### MainMenu.js -

The MainMenu state shows the main menu of the game, where you can start playing by clicking the button.

+The `MainMenu` state shows the main menu of the game, where you can start playing by clicking the button. -
Ball.MainMenu = function(game) {};
+```js
+Ball.MainMenu = function(game) {};
 Ball.MainMenu.prototype = {
     create: function() {
         this.add.sprite(0, 0, 'screen-mainmenu');
@@ -156,28 +161,28 @@ Ball.MainMenu.prototype = {
     startGame: function() {
         this.game.state.start('Howto');
     }
-};
+}; +``` -

To create a new button there's add.button method with the following list of optional arguments:

+To create a new button there's `add.button` method with the following list of optional arguments: -
    -
  • Top absolute position on Canvas in pixels.
  • -
  • Left absolute position on Canvas in pixels.
  • -
  • Name of the image asset the button is using.
  • -
  • Function that will be executed when someone clicks the button.
  • -
  • The execution context.
  • -
  • Frame from the image asset used as the button's "hover" state.
  • -
  • Frame from the image asset used as the button's "normal" or "out" state.
  • -
  • Frame from the image asset used as the button's "click" or "down" state.
  • -
+- Top absolute position on Canvas in pixels. +- Left absolute position on Canvas in pixels. +- Name of the image asset the button is using. +- Function that will be executed when someone clicks the button. +- The execution context. +- Frame from the image asset used as the button's "hover" state. +- Frame from the image asset used as the button's "normal" or "out" state. +- Frame from the image asset used as the button's "click" or "down" state. -

The anchor.set is setting up the anchor point on the button for which all the calculations of the position are applied. In our case it's anchored half the way from the left edge and at the start of the top edge, so it can be easily horizontally centered on the screen without the need to know its width.

+The `anchor.set` is setting up the anchor point on the button for which all the calculations of the position are applied. In our case it's anchored half the way from the left edge and at the start of the top edge, so it can be easily horizontally centered on the screen without the need to know its width. -

When the start button is pressed, instead of jumping directly into the action the game will show the screen with the information on how to play the game.

+When the start button is pressed, instead of jumping directly into the action the game will show the screen with the information on how to play the game. -

Howto.js

+### Howto.js -
Ball.Howto = function(game) {
+```js
+Ball.Howto = function(game) {
 };
 Ball.Howto.prototype = {
     create: function() {
@@ -186,15 +191,17 @@ Ball.Howto.prototype = {
     startGame: function() {
         this.game.state.start('Game');
     }
-};
+}; +``` -

The Howto state shows the gameplay instructions on the screen before starting the game. After clicking the screen the actual game is launched.

+The `Howto` state shows the gameplay instructions on the screen before starting the game. After clicking the screen the actual game is launched. -

Game.js

+### Game.js -

The Game state from the Game.js file is where all the magic happens. All the initialization is in the create() function (launched once at the beginning of the game). After that some functionality will require further code to control — we will write our own functions to handle more complicated tasks. In particular, take note of the update() function (executed at every frame), which updates things such as the ball position.

+The `Game` state from the `Game.js` file is where all the magic happens. All the initialization is in the `create()` function (launched once at the beginning of the game). After that some functionality will require further code to control — we will write our own functions to handle more complicated tasks. In particular, take note of the `update()` function (executed at every frame), which updates things such as the ball position. -
Ball.Game = function(game) {};
+```js
+Ball.Game = function(game) {};
 Ball.Game.prototype = {
     create: function() {},
     initLevels: function() {},
@@ -206,44 +213,48 @@ Ball.Game.prototype = {
     wallCollision: function() {},
     handleOrientation: function(e) {},
     finishLevel: function() {}
-};
+}; +``` -

The create and update functions are framework-specific, while others will be our own creations:

+The `create` and `update` functions are framework-specific, while others will be our own creations: -
    -
  • initLevels initializes the level data.
  • -
  • showLevel prints the level data on the screen.
  • -
  • updateCounter updates the time spent playing each level and records the total time spent playing the game..
  • -
  • managePause pauses and resumes the game.
  • -
  • manageAudio turns the audio on and off.
  • -
  • wallCollision is executed when the ball hits the walls or other objects.
  • -
  • handleOrientation is the function bound to the event responsible for the Device Orientation API, providing the motion controls when the game is running on a mobile device with appropriate hardware.
  • -
  • finishLevel loads a new level when the current level is completed, or finished the game if the final level is completed.
  • -
+- `initLevels` initializes the level data. +- `showLevel` prints the level data on the screen. +- `updateCounter` updates the time spent playing each level and records the total time spent playing the game.. +- `managePause` pauses and resumes the game. +- `manageAudio` turns the audio on and off. +- `wallCollision` is executed when the ball hits the walls or other objects. +- `handleOrientation` is the function bound to the event responsible for the Device Orientation API, providing the motion controls when the game is running on a mobile device with appropriate hardware. +- `finishLevel` loads a new level when the current level is completed, or finished the game if the final level is completed. -

Adding the ball and its motion mechanics

+#### Adding the ball and its motion mechanics -

First, let’s go to the create() function, initialize the ball object itself and assign a few properties to it:

+First, let’s go to the `create()` function, initialize the ball object itself and assign a few properties to it: -
this.ball = this.add.sprite(this.ballStartPos.x, this.ballStartPos.y, 'ball');
+```js
+this.ball = this.add.sprite(this.ballStartPos.x, this.ballStartPos.y, 'ball');
 this.ball.anchor.set(0.5);
 this.physics.enable(this.ball, Phaser.Physics.ARCADE);
 this.ball.body.setSize(18, 18);
-this.ball.body.bounce.set(0.3, 0.3);
+this.ball.body.bounce.set(0.3, 0.3); +``` -

Here we’re adding a sprite at the given place on the screen and using the 'ball' image from the loaded graphic assets. We’re also setting the anchor for any physics calculations to the middle of the ball, enabling the Arcade physics engine (which handles all the physics for the ball movement), and setting the size of the body for the collision detection. The bounce property is used to set the bounciness of the ball when it hits the obstacles.

+Here we’re adding a sprite at the given place on the screen and using the `'ball'` image from the loaded graphic assets. We’re also setting the anchor for any physics calculations to the middle of the ball, enabling the Arcade physics engine (which handles all the physics for the ball movement), and setting the size of the body for the collision detection. The `bounce` property is used to set the bounciness of the ball when it hits the obstacles. -

Controlling the ball

+#### Controlling the ball -

It’s cool to have the ball ready to be thrown around in the play area, but it’s also important to be able to actually move it! Now we will add the ability to control the ball with the keyboard on the desktop devices, and then we will move to the implementation of the Device Orientation API. Let’s focus on the keyboard first by adding the following to the create() function :

+It’s cool to have the ball ready to be thrown around in the play area, but it’s also important to be able to actually move it! Now we will add the ability to control the ball with the keyboard on the desktop devices, and then we will move to the implementation of the Device Orientation API. Let’s focus on the keyboard first by adding the following to the `create()` function : -
this.keys = this.game.input.keyboard.createCursorKeys();
+```js +this.keys = this.game.input.keyboard.createCursorKeys(); +``` -

As you can see there’s a special Phaser function called createCursorKeys(), which will give us an object with event handlers for the four arrow keys to play with: up, down, left and right.

+As you can see there’s a special Phaser function called `createCursorKeys()`, which will give us an object with event handlers for the four arrow keys to play with: up, down, left and right. -

Next we will add the following code to the update() function, so it will be fired on every frame. The this.keys object will be checked against player input, so the ball can react accordingly with the predefined force:

+Next we will add the following code to the `update()` function, so it will be fired on every frame. The `this.keys` object will be checked against player input, so the ball can react accordingly with the predefined force: -
if(this.keys.left.isDown) {
+```js
+if(this.keys.left.isDown) {
     this.ball.body.velocity.x -= this.movementForce;
 }
 else if(this.keys.right.isDown) {
@@ -254,51 +265,57 @@ if(this.keys.up.isDown) {
 }
 else if(this.keys.down.isDown) {
     this.ball.body.velocity.y += this.movementForce;
-}
+} +``` -

That way we can check which key is pressed at the given frame and apply the defined force to the ball, thus increase the velocity in the proper direction.

+That way we can check which key is pressed at the given frame and apply the defined force to the ball, thus increase the velocity in the proper direction. -

Implementing the Device Orientation API

+#### Implementing the Device Orientation API -

Probably the most interesting part of the game is its usage of the Device Orientation API for control on mobile devices. Thanks to this you can play the game by tilting the device in the direction you want the ball to roll. Here’s the code from the create() function responsible for this:

+Probably the most interesting part of the game is its usage of the **Device Orientation API** for control on mobile devices. Thanks to this you can play the game by tilting the device in the direction you want the ball to roll. Here’s the code from the `create()` function responsible for this: -
window.addEventListener("deviceorientation", this.handleOrientation, true);
+```js +window.addEventListener("deviceorientation", this.handleOrientation, true); +``` -

We’re adding an event listener to the "deviceorientation" event and binding the handleOrientation function which looks like this:

+We’re adding an event listener to the `"deviceorientation"` event and binding the `handleOrientation` function which looks like this: -
handleOrientation: function(e) {
+```js
+handleOrientation: function(e) {
     var x = e.gamma;
     var y = e.beta;
     Ball._player.body.velocity.x += x;
     Ball._player.body.velocity.y += y;
-},
+}, +``` -

The more you tilt the device, the more force is applied to the ball, therefore the faster it moves (the velocity is higher).

+The more you tilt the device, the more force is applied to the ball, therefore the faster it moves (the velocity is higher). -

An explanation of the X, Y and Z axes of a Flame mobile device with the Cyber Orb game demo on the screen.

+![An explanation of the X, Y and Z axes of a Flame mobile device with the Cyber Orb game demo on the screen.](cyber-orb-flame-orientation.png) -
-

备注: To find more out about implementing device orientation and what raw code would look like, read Keep it level: responding to device orientation changes.

-
+> **备注:** To find more out about implementing device orientation and what raw code would look like, read [Keep it level: responding to device orientation changes](/en-US/Apps/Build/gather_and_modify_data/responding_to_device_orientation_changes). -

Adding the hole

+#### Adding the hole -

The main objective in the game is to move the ball from the starting position to the ending position: a hole in the ground. Implementation looks very similar to the part where we created the ball, and it's also added in the create() function of our Game state:

+The main objective in the game is to move the ball from the starting position to the ending position: a hole in the ground. Implementation looks very similar to the part where we created the ball, and it's also added in the `create()` function of our `Game` state: -
this.hole = this.add.sprite(Ball._WIDTH*0.5, 90, 'hole');
+```js
+this.hole = this.add.sprite(Ball._WIDTH*0.5, 90, 'hole');
 this.physics.enable(this.hole, Phaser.Physics.ARCADE);
 this.hole.anchor.set(0.5);
-this.hole.body.setSize(2, 2);
+this.hole.body.setSize(2, 2); +``` -

The difference is that our hole’s body will not move when we hit it with the ball and will have the collision detection calculated (which will be discussed later on in this article).

+The difference is that our hole’s body will not move when we hit it with the ball and will have the collision detection calculated (which will be discussed later on in this article). -

Building the block labyrinth

+#### Building the block labyrinth -

To make the game harder and more interesting we will add some obstacles between the ball and the exit. We could use a level editor, but for the sake of this tutorial let's create something on our own.

+To make the game harder and more interesting we will add some obstacles between the ball and the exit. We could use a level editor, but for the sake of this tutorial let's create something on our own. -

To hold the block information we'll use a level data array: for each block we'll store the top and left absolute positions in pixels (x and y) and the type of the block — horizontal or vertical (t with the 'w' value meaning width and 'h' meaning height). Then, to load the level we'll parse the data and show the blocks specific for that level. In the initLevels function we have:

+To hold the block information we'll use a level data array: for each block we'll store the top and left absolute positions in pixels (`x` and `y`) and the type of the block — horizontal or vertical (`t` with the `'w'` value meaning width and `'h'` meaning height). Then, to load the level we'll parse the data and show the blocks specific for that level. In the `initLevels` function we have: -
this.levelData = [
+```js
+this.levelData = [
     [
         { x: 96, y: 224, t: 'w' }
     ],
@@ -308,110 +325,134 @@ this.hole.body.setSize(2, 2);
{ x: 72, y: 150, t: 'w' } ], // ... -];
+]; +``` -

Every array element holds a collection of blocks with an x and y position and t value for each. After levelData, but still in the initLevels function, we're adding the blocks into an array in the for loop using some of the framework-specific methods:

+Every array element holds a collection of blocks with an `x` and `y` position and `t` value for each. After `levelData`, but still in the `initLevels` function, we're adding the blocks into an array in the `for` loop using some of the framework-specific methods: -
for(var i=0; i<this.maxLevels; i++) {
+```js
+for(var i=0; i
+}
+```
 
-

First, add.group() is used to create a new group of items. Then the ARCADE body type is set for that group to enable physics calculations. The newLevel.create method creates new items in the group with starting left and top positions, and its own image. If you don't want to loop through the list of items again to add a property to every single one explicitly, you can use setAll on a group to apply it to all the items in that group.

+First, `add.group()` is used to create a new group of items. Then the `ARCADE` body type is set for that group to enable physics calculations. The `newLevel.create` method creates new items in the group with starting left and top positions, and its own image. If you don't want to loop through the list of items again to add a property to every single one explicitly, you can use `setAll` on a group to apply it to all the items in that group. -

The objects are stored in the this.levels array, which is by default invisible. To load specific levels, we make sure the previous levels are hidden, and show the current one:

+The objects are stored in the `this.levels` array, which is by default invisible. To load specific levels, we make sure the previous levels are hidden, and show the current one: -
showLevel: function(level) {
+```js
+showLevel: function(level) {
     var lvl = level | this.level;
     if(this.levels[lvl-2]) {
         this.levels[lvl-2].visible = false;
     }
     this.levels[lvl-1].visible = true;
-}
+} +``` -

Thanks to that the game gives the player a challenge - now he have to roll the ball across the play area and guide it through the labyrinth built from the blocks. It's just an example of loading the levels, and there are only 5 of them just to showcase the idea, but you can work on expanding that on your own.

+Thanks to that the game gives the player a challenge - now he have to roll the ball across the play area and guide it through the labyrinth built from the blocks. It's just an example of loading the levels, and there are only 5 of them just to showcase the idea, but you can work on expanding that on your own. -

Collision detection

+#### Collision detection -

At this point we've got the ball that is controlled by the player, the hole to reach and the obstacles blocking the way. There’s a problem though — our game doesn’t have any collision detection yet, so nothing happens when the ball hits the blocks — it just goes through. Let’s fix it! The good news is that the framework will take care of calculating the collision detection, we only have to specify the colliding objects in the update() function:

+At this point we've got the ball that is controlled by the player, the hole to reach and the obstacles blocking the way. There’s a problem though — our game doesn’t have any collision detection yet, so nothing happens when the ball hits the blocks — it just goes through. Let’s fix it! The good news is that the framework will take care of calculating the collision detection, we only have to specify the colliding objects in the `update()` function: -
this.physics.arcade.collide(this.ball, this.borderGroup, this.wallCollision, null, this);
-this.physics.arcade.collide(this.ball, this.levels[this.level-1], this.wallCollision, null, this);
+```js +this.physics.arcade.collide(this.ball, this.borderGroup, this.wallCollision, null, this); +this.physics.arcade.collide(this.ball, this.levels[this.level-1], this.wallCollision, null, this); +``` -

This will tell the framework to execute the wallCollision function when the ball hits any of the walls. We can use the wallCollision function to add any functionality we want like playing the bounce sound and implementing the Vibration API.

+This will tell the framework to execute the `wallCollision` function when the ball hits any of the walls. We can use the `wallCollision` function to add any functionality we want like playing the bounce sound and implementing the **Vibration API**. -

Adding the sound

+#### Adding the sound -

Among the preloaded assets there was an audio track (in various formats for browser compatibility), which we can use now. It has to be defined in the create() function first:

+Among the preloaded assets there was an audio track (in various formats for browser compatibility), which we can use now. It has to be defined in the `create()` function first: -
this.bounceSound = this.game.add.audio('audio-bounce');
+```js +this.bounceSound = this.game.add.audio('audio-bounce'); +``` -

If the status of the audio is true (so the sounds in the game are enabled), we can play it in the wallCollision function:

+If the status of the audio is `true` (so the sounds in the game are enabled), we can play it in the `wallCollision` function: -
if(this.audioStatus) {
+```js
+if(this.audioStatus) {
     this.bounceSound.play();
-}
+} +``` -

That's all — loading and playing the sounds is easy with Phaser.

+That's all — loading and playing the sounds is easy with Phaser. -

Implementing the Vibration API

+#### Implementing the Vibration API -

When collision detection works as expected let's add some special effects with the help from the Vibration API.

+When collision detection works as expected let's add some special effects with the help from the Vibration API. -

A visualization of the vibrations of a Flame mobile device with the Cyber Orb game demo on the screen.

+![A visualization of the vibrations of a Flame mobile device with the Cyber Orb game demo on the screen.](cyber-orb-flame-vibration.png) -

The best way to use it in our case is to vibrate the phone every time the ball hits the walls — inside the wallCollision function:

+The best way to use it in our case is to vibrate the phone every time the ball hits the walls — inside the `wallCollision` function: -
if("vibrate" in window.navigator) {
+```js
+if("vibrate" in window.navigator) {
     window.navigator.vibrate(100);
-}
+} +``` -

If the vibrate method is supported by the browser and available in the window.navigator object, vibrate the phone for 100 miliseconds. That's it!

+If the `vibrate` method is supported by the browser and available in the `window.navigator` object, vibrate the phone for 100 miliseconds. That's it! -

Adding the elapsed time

+#### Adding the elapsed time -

To improve replayability and give players the option to compete with each other we will store the elapsed time — players can then try to improve on their best game completion time. To implement this we have to create a variable for storing the actual number of seconds elapsed from the start of the game, and to show it for the player in the game. Let’s define the variables in the create function first:

+To improve replayability and give players the option to compete with each other we will store the elapsed time — players can then try to improve on their best game completion time. To implement this we have to create a variable for storing the actual number of seconds elapsed from the start of the game, and to show it for the player in the game. Let’s define the variables in the `create` function first: -
this.timer = 0; // time elapsed in the current level
-this.totalTimer = 0; // time elapsed in the whole game
+```js +this.timer = 0; // time elapsed in the current level +this.totalTimer = 0; // time elapsed in the whole game +``` -

Then, right after that, we can initialize the necessary text objects to display this information to the user:

+Then, right after that, we can initialize the necessary text objects to display this information to the user: -
this.timerText = this.game.add.text(15, 15, "Time: "+this.timer, this.fontBig);
-this.totalTimeText = this.game.add.text(120, 30, "Total time: "+this.totalTimer, this.fontSmall);
+```js +this.timerText = this.game.add.text(15, 15, "Time: "+this.timer, this.fontBig); +this.totalTimeText = this.game.add.text(120, 30, "Total time: "+this.totalTimer, this.fontSmall); +``` -

We’re defining the top and left positions of the text, the content that will be shown and the styling applied to the text. We have this printed out on the screen, but it would be good to update the values every second:

+We’re defining the top and left positions of the text, the content that will be shown and the styling applied to the text. We have this printed out on the screen, but it would be good to update the values every second: -
this.time.events.loop(Phaser.Timer.SECOND, this.updateCounter, this);
+```js +this.time.events.loop(Phaser.Timer.SECOND, this.updateCounter, this); +``` -

This loop, also in the create function, will execute the updateCounter function every single second from the beginning of the game, so we can apply the changes accordingly. This is how the complete updateCounter function looks:

+This loop, also in the `create` function, will execute the `updateCounter` function every single second from the beginning of the game, so we can apply the changes accordingly. This is how the complete `updateCounter` function looks: -
updateCounter: function() {
+```js
+updateCounter: function() {
     this.timer++;
     this.timerText.setText("Time: "+this.timer);
     this.totalTimeText.setText("Total time: "+(this.totalTimer+this.timer));
-},
+}, +``` -

As you can see we’re incrementing the this.timer variable and updating the content of the text objects with the current values on each iteration, so the player sees the elapsed time.

+As you can see we’re incrementing the `this.timer` variable and updating the content of the text objects with the current values on each iteration, so the player sees the elapsed time. -

Finishing the level and the game

+#### Finishing the level and the game -

The ball is rolling on the screen, the timer is working and we have the hole created that we have to reach. Now let’s set up the possibility to actually finish the level! The following line in the update() function adds a listener that fires when the ball gets to the hole.

+The ball is rolling on the screen, the timer is working and we have the hole created that we have to reach. Now let’s set up the possibility to actually finish the level! The following line in the `update()` function adds a listener that fires when the ball gets to the hole. -
this.physics.arcade.overlap(this.ball, this.hole, this.finishLevel, null, this);
+```js +this.physics.arcade.overlap(this.ball, this.hole, this.finishLevel, null, this); +``` -

This works similarly to the collide method explained earlier. When the ball overlaps with the hole (instead of colliding), the finishLevel function is executed:

+This works similarly to the `collide` method explained earlier. When the ball overlaps with the hole (instead of colliding), the `finishLevel` function is executed: -
finishLevel: function() {
-    if(this.level >= this.maxLevels) {
+```js
+finishLevel: function() {
+    if(this.level >= this.maxLevels) {
         this.totalTimer += this.timer;
         alert('Congratulations, game completed!\nTotal time of play: '+this.totalTimer+' seconds!');
         this.game.state.start('MainMenu');
@@ -430,18 +471,19 @@ this.totalTimeText = this.game.add.text(120, 30, "Total time: "+this.totalTimer,
         this.ball.body.velocity.y = 0;
         this.showLevel();
     }
-},
+}, +``` -

If the current level is equal to the maximum number of levels (in this case 5), then the game is finished — you'll get a congratulations message along with the number of seconds elapsed through the whole game, and a button to press that takes you to the main menu.

+If the current level is equal to the maximum number of levels (in this case 5), then the game is finished — you'll get a congratulations message along with the number of seconds elapsed through the whole game, and a button to press that takes you to the main menu. -

If the current level is lower than 5, all the neccesary variables are reset and the next level is loaded.

+If the current level is lower than 5, all the neccesary variables are reset and the next level is loaded. -

Ideas for new features

+## Ideas for new features -

This is merely a working demo of a game that could have lots of additional features. We can for example add power-ups to collect along the way that will make our ball roll faster, stop the timer for a few seconds or give the ball special powers to go through obstacles. There’s also room for the traps which will slow the ball down or make it more difficult to reach the hole. You can create more levels of increasing difficulty. You can even implement achievements, leaderboards and medals for different actions in the game. There are endless possibilities — they only depend on your imagination.

+This is merely a working demo of a game that could have lots of additional features. We can for example add power-ups to collect along the way that will make our ball roll faster, stop the timer for a few seconds or give the ball special powers to go through obstacles. There’s also room for the traps which will slow the ball down or make it more difficult to reach the hole. You can create more levels of increasing difficulty. You can even implement achievements, leaderboards and medals for different actions in the game. There are endless possibilities — they only depend on your imagination. -

Summary

+## Summary -

I hope this tutorial will help you dive into 2D game development and inspire you to create awesome games on your own. You can play the demo game Cyber Orb and check out its source code on GitHub.

+I hope this tutorial will help you dive into 2D game development and inspire you to create awesome games on your own. You can play the demo game [Cyber Orb](http://orb.enclavegames.com/) and check out its [source code on GitHub](https://github.com/EnclaveGames/Cyber-Orb). -

HTML5 gives us raw tools, the frameworks built on top of it are getting faster and better, so now is a great time get into web game development. In this tutorial we used Phaser, but there are a number of other frameworks worth considering too like ImpactJS, Construct 2 or PlayCanvas — it depends on your preferences, coding skills (or lack thereof), project scale, requirements and other aspects. You should check them all out and decide which one suits your needs best.

+HTML5 gives us raw tools, the frameworks built on top of it are getting faster and better, so now is a great time get into web game development. In this tutorial we used Phaser, but there are a number of [other frameworks](http://html5devstarter.enclavegames.com/#frameworks) worth considering too like [ImpactJS](http://impactjs.com/), [Construct 2](https://www.scirra.com/construct2) or [PlayCanvas](http://playcanvas.com/) — it depends on your preferences, coding skills (or lack thereof), project scale, requirements and other aspects. You should check them all out and decide which one suits your needs best. diff --git a/files/zh-cn/games/tutorials/index.md b/files/zh-cn/games/tutorials/index.md index 073b0ac52a82d2..60c2b4d15fd778 100644 --- a/files/zh-cn/games/tutorials/index.md +++ b/files/zh-cn/games/tutorials/index.md @@ -11,15 +11,13 @@ tags: - Workflows translation_of: Games/Tutorials --- -
{{GamesSidebar}}
+{{GamesSidebar}} -

This page contains multiple tutorial series that highlight different workflows for effectively creating different types of web games.

+This page contains multiple tutorial series that highlight different workflows for effectively creating different types of web games. -
-
2D breakout game using pure JavaScript
-
In this step-by-step tutorial you'll implement a simple breakout clone using pure JavaScript. Along the way you will learn the basics of using the {{htmlelement("canvas")}} element to implement fundamental game mechanics like rendering and moving images, collision detection, control machanisms, and winning and losing states.
-
2D breakout game using Phaser
-
In this step-by-step tutorial you'll implement the same breakout clone as the previous tutorial series, except that this time you'll do it using thePhaser HTML5 game framework. This idea here is to teach some of the fundamentals (and advantages) of working with frameworks, along with fundamental game mechanics.
-
2D maze game with device orientation
-
This tutorial shows how to create a 2D maze game using HTML5, incorporating fundamentals such as collision detection and sprite placement on a {{htmlelement("canvas")}}. This is a mobile game that uses the Device Orientation and Vibration APIs to enhance the gameplay and is built using the Phaser framework.
-
+- [2D breakout game using pure JavaScript](/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript) + - : In this step-by-step tutorial you'll implement a simple breakout clone using pure JavaScript. Along the way you will learn the basics of using the {{htmlelement("canvas")}} element to implement fundamental game mechanics like rendering and moving images, collision detection, control machanisms, and winning and losing states. +- [2D breakout game using Phaser](/en-US/docs/Games/Workflows/2D_breakout_game_Phaser) + - : In this step-by-step tutorial you'll implement the same breakout clone as the previous tutorial series, except that this time you'll do it using the[Phaser](http://phaser.io/) HTML5 game framework. This idea here is to teach some of the fundamentals (and advantages) of working with frameworks, along with fundamental game mechanics. +- [2D maze game with device orientation](/en-US/docs/Games/Workflows/HTML5_Gamedev_Phaser_Device_Orientation) + - : This tutorial shows how to create a 2D maze game using HTML5, incorporating fundamentals such as collision detection and sprite placement on a {{htmlelement("canvas")}}. This is a mobile game that uses the [Device Orientation](/en-US/Apps/Build/gather_and_modify_data/responding_to_device_orientation_changes) and [Vibration](/en-US/docs/Web/Guide/API/Vibration) **APIs** to enhance the gameplay and is built using the [Phaser](http://phaser.io/) framework.