diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/games/tutorials | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/zh-cn/games/tutorials')
30 files changed, 3009 insertions, 0 deletions
diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/animations_and_tweens/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/animations_and_tweens/index.html new file mode 100644 index 0000000000..ff5aa23230 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/animations_and_tweens/index.html @@ -0,0 +1,117 @@ +--- +title: Animations and tweens +slug: Games/Tutorials/2D_breakout_game_Phaser/Animations_and_tweens +tags: + - 2D + - Animation + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial + - tween +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Animations_and_tweens +--- +<div>{{GamesSidebar}}</div> + +<div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Extra_lives", "Games/Workflows/2D_Breakout_game_Phaser/Buttons")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第14步</font></font></strong><font><font>。</font><font>您可以在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson14.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson14.html</font></a><font>完成本课程后找到源代码</font><font>。</font></font></p> +</div> + +<p><font>为了使游戏看起来更加多汁和活泼,我们可以使用动画和补间。</font><font>这将导致更好,更有趣的体验。</font><font>让我们来探讨如何在游戏中实现Phaser动画和补间。</font></p> + +<h2 id="动画">动画</h2> + +<p><font><font>在Phaser,动画中,涉及从外部来源获取spritesheet并依次显示sprites。</font><font>作为一个例子,当碰到一些东西时,我们会让球摇摆。</font></font></p> + +<p><font><font>首先,</font></font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/img/wobble.png"><font><font>从Github抓取spritesheet</font></font></a><font><font>并将其保存在您的</font></font><code>/img</code><font><font>目录中。</font></font></p> + +<p><font><font>接下来,我们将加载spritesheet - 将以下行放在</font></font><code>preload()</code><font><font>函数</font><font>的底部</font><font>:</font></font></p> + +<pre class="brush: js">game.load.spritesheet('ball', 'img/wobble.png', 20, 20); +</pre> + +<p><font><font>而不是加载单个图像的球,我们可以加载整个spritesheet - 不同图像的集合。</font><font>我们将按顺序显示精灵,创造动画的幻觉。</font><font>该</font></font><code>spritesheet()</code><font><font>方法的两个额外的表格确定给定spritesheet文件中每个单个框架的宽度和高度,指示程序如何切割以获取单个框架。</font></font></p> + +<h2 id="加载动画"><font><font>加载动画</font></font></h2> + +<p><font><font>接下来,进入你的create()函数,找到加载球精灵的行,下面的调用</font></font><code>animations.add()</code><font><font>如下所示:</font></font></p> + +<pre class="brush: js">ball = game.add.sprite(50, 250, 'ball'); +ball.animations.add('wobble', [0,1,0,2,0,1,0,2,0], 24); +</pre> + +<p><font><font>要向对象添加动画,我们使用该</font></font><code>animations.add()</code><font><font>方法,其中包含以下参数</font></font></p> + +<ul> + <li><font><font>我们为动画选择的名称</font></font></li> + <li><font><font>一个数组,定义在动画过程中显示帧的顺序。</font><font>如果您再次查看</font></font><code>wobble.png</code><font><font>图像,您会看到有三个框架。</font><font>Phaser提取它们并将它们存储在数组中 - 位置0,1和2.上面的数组表示我们显示帧0,然后是1,然后是0等。</font></font></li> + <li><font><font>帧速率,以fps为单位。</font><font>由于我们以24fps运行动画,有9帧,动画每秒将显示三次以下。</font></font></li> +</ul> + +<h2 id="当球击中桨时应用动画"><font><font>当球击中桨时应用动画</font></font></h2> + +<p><font><font>在</font></font><code>arcade.collide()</code><font><font>处理球和桨(第一行内部</font></font><code>update()</code><font><font>,见下文)</font><font>之间的碰撞</font><font>的</font><font>方法调用中,</font><font>我们可以添加一个额外的参数,该参数指定每次发生碰撞时执行的功能,与该</font></font><code>ballHitBrick()</code><font><font>功能</font><font>相同</font><font>。</font><font>更新内部的第一行</font></font><code>update()</code><font><font>,如下所示:</font></font></p> + +<pre class="brush: 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; +} +</pre> + +<p><font><font>然后我们可以创建</font></font><code>ballHitPaddle()</code><font><font>函数(具有</font></font><code>ball</code><font><font>和</font></font><code>paddle</code><font><font>作为默认参数),在调用时播放摆动动画。</font><font>在结束</font></font><code></script></code><font><font>标签</font><font>之前添加以下方法</font><font>:</font></font></p> + +<pre class="brush: js">function ballHitPaddle(ball, paddle) { + ball.animations.play('wobble'); +} +</pre> + +<p><font><font>每次球击中桨时都会播放动画。</font><font>你也可以</font></font><code>animations.play()</code><font><font>在</font></font><code>ballHitBrick()</code><font><font>函数</font><font>内</font><font>添加</font><font>调用</font><font>,如果你觉得它会使游戏看起来更好。</font></font></p> + +<h2 id="补间">补间</h2> + +<p>而动画依次播放外部精灵,补间游戏中物体的属性平滑,如宽度或不透明度。</p> + +<p><font><font>让我们在游戏中增加一个补间,使砖块在被球击中时顺利消失。</font><font>转到您的</font></font><code>ballhitBrick()</code><font><font>功能,找到您的</font></font><code>brick.kill();</code><font><font>行,并将其替换为以下内容:</font></font></p> + +<pre class="brush: 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(); +</pre> + +<p>让我们来看看这里,看看这里发生了什么:</p> + +<ol> + <li><font><font>当定义一个新的补间时,你必须指定哪些属性将被补间 - 在我们的例子中,而不是在被球击中时立即隐藏砖块,我们将把它们的宽度和高度缩放到零,所以它们将很好地消失。</font><font>最后,我们使用该</font></font><code>add.tween()</code><font><font>方法,指定</font></font><code>brick.scale</code><font><font>为参数,因为这是我们想要补间。</font></font></li> + <li><font><font>该</font></font><code>to()</code><font><font>方法定义补间结束时对象的状态。</font><font>它需要一个包含所选参数的期望结束值的对象(比例取尺度值,1为大小的100%,0为大小的0%等),补间的时间(以毫秒为单位)以及使用的宽松类型补间。</font></font></li> + <li><font><font>我们还将添加可选的</font></font><code>onComplete</code><font><font>事件处理程序,该处理程序定义了在补间程序完成时要执行的函数。</font></font></li> + <li><font><font>最后一件事是立即开始补间</font></font><code>start()</code><font><font>。</font></font></li> +</ol> + +<p>这是补间定义的扩展版本,但是我们也可以使用速记语法:</p> + +<pre class="brush: js">game.add.tween(brick.scale).to({x:2,y:2}, 500, Phaser.Easing.Elastic.Out, true, 100); +</pre> + +<p>这个补间将使用弹性宽松在半秒内将砖的比例翻倍,将自动启动,延迟100毫秒。</p> + +<h2 id="比较你的代码">比较你的代码</h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/9o4pakrb/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p><font><font>动画和tweens看起来很不错,但我们可以添加更多的我们的游戏 - 在下一节我们将看看处理</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Buttons"><font><font>按钮</font></font></a><font><font>输入。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Extra_lives", "Games/Workflows/2D_Breakout_game_Phaser/Buttons")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.html new file mode 100644 index 0000000000..2cc91361c6 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/bounce_off_the_walls/index.html @@ -0,0 +1,49 @@ +--- +title: Bounce off the walls +slug: Games/Tutorials/2D_breakout_game_Phaser/Bounce_off_the_walls +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial + - bouncing +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Bounce_off_the_walls +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Physics", "Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font>的</font></font><strong><font><font>第</font></font></strong><font><font> 6 </font><strong><font>步</font></strong><font>。</font><font>在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson06.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson06.html</font></a><font>完成本课后,您可以找到源代码</font><font>。</font></font></p> +</div> + +<p>现在已经介绍了物理引擎,我们可以开始在游戏中实现碰撞检测 - 首先我们来看看墙壁。</p> + +<h2 id="反弹边界"><font><font>反弹边界</font></font></h2> + +<p><font><font>让我们的球从墙壁上弹起的最简单的方法是告诉框架,我们想要将</font></font><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas" title="HTML <canvas>元素可用于通过脚本(通常为JavaScript)绘制图形。 例如,它可以用于绘制图形,制作照片,甚至执行动画。 您可以(并且应该)在<canvas>块内提供备用内容。 该内容将在不支持画布的旧浏览器和禁用JavaScript的浏览器中呈现。"><code><canvas></code></a><font><font>元素</font><font>的边界</font><font>视为墙壁,而不是让球移过它们。</font><font>在Phaser中,可以使用该</font></font><code>collideWorldsBound</code><font><font>属性</font><font>轻松实现</font><font>。</font><font>在现有</font></font><code>game.physics.enable()</code><font><font>方法调用</font><font>之后添加此行</font><font>:</font></font></p> + +<pre class="brush: js">ball.body.collideWorldBounds = true; +</pre> + +<p><font>现在球将停在屏幕的边缘,而不是消失,但它不会弹起。</font><font>为了使这种情况发生,我们必须设置它的bounciness。</font><font>在上一行下面添加以下行:</font></p> + +<pre class="brush: js">ball.body.bounce.set(1); +</pre> + +<p>再次尝试重新加载index.html - 现在您应该看到球从墙壁上弹起并在画布区域内移动。</p> + +<h2 id="比较你的代码"><font><font>比较你的代码</font></font></h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/dcw36opz/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p><font><font>现在开始看起来更像是一个游戏,但是我们无法以任何方式控制它 - 现在是介绍</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls"><font><font>玩家挡板和控制的时候了</font></font></a><font><font>。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Physics", "Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.html new file mode 100644 index 0000000000..981b592469 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/build_the_brick_field/index.html @@ -0,0 +1,164 @@ +--- +title: Build the brick field +slug: Games/Tutorials/2D_breakout_game_Phaser/Build_the_brick_field +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Build_the_brick_field +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Game_over", "Games/Workflows/2D_Breakout_game_Phaser/Collision_detection")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第9步</font></font></strong><font><font>。</font><font>在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson09.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson09.html</font></a><font>完成本课后,您可以找到源代码</font><font>。</font></font></p> +</div> + +<p><font>建立砖块比将单个对象添加到屏幕要复杂一点,尽管使用Phaser还是比纯JavaScript更容易。</font><font>我们来探讨如何创建一组砖块,并使用循环在屏幕上打印。</font></p> + +<h2 id="定义新变量"><font><font>定义新变量</font></font></h2> + +<p>首先,我们定义所需的变量 - 在以前的变量定义中添加以下内容:</p> + +<pre class="brush: js">var bricks; +var newBrick; +var brickInfo; +</pre> + +<p><font><font>该</font></font><code>bricks</code><font><font>变量将用于创建一个组,</font></font><code>newBrick</code><font><font>将在循环的每次迭代中添加到组中的新对象,</font></font><code>brickInfo</code><font><font>并将存储我们需要的所有数据。</font></font></p> + +<h2 id="渲染砖图像"><font><font>渲染砖图像</font></font></h2> + +<p><font><font>接下来,我们加载砖的图像 - </font></font><code>load.image()</code><font><font>在其他地方</font><font>添加以下</font><font>调用:</font></font></p> + +<pre class="brush: js">function preload() { + // ... + game.load.image('brick', 'img/brick.png'); +} +</pre> + +<p><font><font>您还需要</font></font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/img/brick.png"><font><font>从Github抓取砖图像</font></font></a><font><font>并将其保存在您的</font></font><code>/img</code><font><font>目录中。</font></font></p> + +<h2 id="画砖"><font><font>画砖</font></font></h2> + +<p><font><font>我们将将所有用于绘制砖块的代码放在一个</font></font><code>initBricks</code><font><font>函数中,以使其与其余代码分离。</font></font><code>initBricks</code><font><font>在</font></font><code>create()</code><font><font>函数</font><font>末尾</font><font>添加一个调用</font><font>:</font></font></p> + +<pre class="brush: js">function create(){ + // ... + initBricks(); +} +</pre> + +<p><font><font>现在到函数本身。</font></font><code>initBricks()</code><font><font>在我们的游戏代码末尾</font><font>添加</font><font>功能,就在关闭</ script>标签之前,如下所示。</font><font>首先我们已经包括了这个 </font></font><code>brickInfo</code><font><font>对象,因为这很快就会派上用场:</font></font></p> + +<pre class="brush: js">function initBricks() { + brickInfo = { + width: 50, + height: 20, + count: { + row: 7, + col: 3 + }, + offset: { + top: 50, + left: 60 + }, + padding: 10 + }; +} +</pre> + +<p><font><font>这个</font></font><code>brickInfo</code><font><font>对象将包含我们需要的所有信息:单个砖的宽度和高度,我们将在屏幕上看到的砖的行数和列数,顶部和左边的偏移量(画布上我们将开始绘制的位置)砖块)和每一列和砖块之间的填充。</font></font></p> + +<p><font><font>现在,让我们开始创建砖块 - 首先添加一个空组来包含砖块,在</font></font><code>initBricks()</code><font><font>函数</font><font>底部添加以下行</font><font>:</font></font></p> + +<pre class="brush: js">bricks = game.add.group(); +</pre> + +<p>我们可以循环遍历行和列,以便在每次迭代中创建新的砖块 - 在上一行代码下面添加以下嵌套循环:</p> + +<pre class="brush: js">for(c=0; c<brickInfo.count.col; c++) { + for(r=0; r<brickInfo.count.row; r++) { + // create new brick and add it to the group + } +} +</pre> + +<p><font><font>这样我们将创建我们需要的确切数量的砖,并将它们全部包含在一个组中。</font><font>现在我们需要在嵌套循环结构中添加一些代码来绘制每个砖块。</font><font>填写内容如下图所示:</font></font></p> + +<pre class="brush: js">for(c=0; c<brickInfo.count.col; c++) { + for(r=0; r<brickInfo.count.row; r++) { + var brickX = 0; + var brickY = 0; + newBrick = game.add.sprite(brickX, brickY, 'brick'); + game.physics.enable(newBrick, Phaser.Physics.ARCADE); + newBrick.body.immovable = true; + newBrick.anchor.set(0.5); + bricks.add(newBrick); + } +} +</pre> + +<p><font><font>在这里,我们循环遍历行和列,创建新的砖块并将其放在屏幕上。</font><font>新创建的砖块为Arcade物理引擎启用,它的身体被设置为不可移动(所以当球被击中时它不会移动),我们还将锚点放在中间并添加砖到集团。</font></font></p> + +<p><font><font>目前的问题是,我们在一个地方绘制所有的砖,坐标(0,0)。</font><font>我们需要做的是将每个砖块绘制在自己的x和y位置。</font><font>更新</font></font><code>brickX</code><font><font>和</font></font><code>brickY</code><font><font>行如下:</font></font></p> + +<pre class="brush: js">var brickX = (r*(brickInfo.width+brickInfo.padding))+brickInfo.offset.left; +var brickY = (c*(brickInfo.height+brickInfo.padding))+brickInfo.offset.top; +</pre> + +<p><font><font>每个</font></font><code>brickX</code><font><font>位置都是</font></font><code>brickInfo.width</code><font><font>加</font></font><code>brickInfo.padding</code><font><font>号乘以行号</font></font><code>r</code><font><font>,加上</font></font><code>brickInfo.offset.left</code><font><font>; </font><font>用于所述逻辑</font></font><code>brickY</code><font><font>是不同之处在于它使用的值列号相同</font></font><code>c</code><font><font>,</font></font><code>brickInfo.height</code><font><font>和</font></font><code>brickInfo.offset.top</code><font><font>。</font><font>现在每个砖都可以放置在正确的位置,每个砖块之间填充,并从左侧和顶部画布边缘偏移绘制。</font></font></p> + +<h2 id="检查initBricks()代码"><font><font>检查initBricks()代码</font></font></h2> + +<p><font><font>这是功能的完整代码</font></font><code>initBricks()</code><font><font>:</font></font></p> + +<pre class="brush: js">function initBricks() { + brickInfo = { + width: 50, + height: 20, + count: { + row: 7, + col: 3 + }, + offset: { + top: 50, + left: 60 + }, + padding: 10 + } + bricks = game.add.group(); + for(c=0; c<brickInfo.count.col; c++) { + for(r=0; r<brickInfo.count.row; r++) { + var brickX = (r*(brickInfo.width+brickInfo.padding))+brickInfo.offset.left; + var brickY = (c*(brickInfo.height+brickInfo.padding))+brickInfo.offset.top; + newBrick = game.add.sprite(brickX, brickY, 'brick'); + game.physics.enable(newBrick, Phaser.Physics.ARCADE); + newBrick.body.immovable = true; + newBrick.anchor.set(0.5); + bricks.add(newBrick); + } + } +} +</pre> + +<p><font><font>如果您现在重新加载</font></font><code>index.html</code><font><font>,您应该看到在屏幕上打印的砖块彼此相距甚远。</font></font></p> + +<h2 id="比较你的代码"><font><font>比较你的代码</font></font></h2> + +<p><font><font>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</font></font></p> + +<p> </p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/cck2b9e8/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p><font><font>有些东西丢失了 </font><font>球不经停,经过砖块 - 我们需要适当的</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Collision_detection"><font><font>碰撞检测</font></font></a><font><font>。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Game_over", "Games/Workflows/2D_Breakout_game_Phaser/Collision_detection")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/buttons/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/buttons/index.html new file mode 100644 index 0000000000..2b29b39714 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/buttons/index.html @@ -0,0 +1,104 @@ +--- +title: Buttons +slug: Games/Tutorials/2D_breakout_game_Phaser/Buttons +tags: + - 2D + - Beginner + - Buttons + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Buttons +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens", "Games/Workflows/2D_Breakout_game_Phaser/Randomizing_gameplay")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第15步</font></font></strong><font><font>。</font><font>您可以在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson15.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson15.html</font></a><font>完成本课程后找到源代码</font></font></p> +</div> + +<p><font>而不是立即开始游戏,我们可以通过添加他们可以按的开始按钮将该决定留给玩家。</font><font>我们来调查如何做到这一点。</font></p> + +<h2 id="新变量"><font><font>新变量</font></font></h2> + +<p><font>我们需要一个变量来存储表示游戏当前是否正在播放的布尔值,另一个代表我们的按钮。</font><font>将以下行添加到其他变量定义之下:</font></p> + +<pre class="brush: js">var playing = false; +var startButton; +</pre> + +<h2 id="加载按钮spritesheet"><font><font>加载按钮spritesheet</font></font></h2> + +<p><font><font>我们可以加载按钮spritesheet与我们加载球的摆动动画相同的方式。</font><font>将以下内容添加到</font></font><code>preload()</code><font><font>函数</font><font>底部</font><font>:</font></font></p> + +<pre class="brush: js">game.load.spritesheet('button', 'img/button.png', 120, 40); +</pre> + +<p><font><font>单个按钮框架宽120像素,高40像素。</font></font></p> + +<p><font><font>您还需要</font></font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/img/button.png"><font><font>从Github抓取按钮spritesheet</font></font></a><font><font>,并将其保存在您的</font></font><code>/img</code><font><font>目录中。</font></font></p> + +<h2 id="将按钮添加到游戏中"><font><font>将按钮添加到游戏中</font></font></h2> + +<p><font><font>使用该</font></font><code>add.button</code><font><font>方法</font><font>可以将新的按钮添加到游戏中</font><font>。</font><font>将以下行添加到</font></font><code>create()</code><font><font>函数</font><font>的底部</font><font>:</font></font></p> + +<pre class="brush: 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); +</pre> + +<p><font><font>该</font></font><code>button()</code><font><font>方法的参数如下:</font></font></p> + +<ul> + <li><font><font>按钮的x和y坐标</font></font></li> + <li><font><font>要显示按钮的图形资产的名称</font></font></li> + <li><font><font>按下按钮时将执行的回调函数</font></font></li> + <li><code>this</code><font><font>指定执行上下文的</font><font>引用</font></font></li> + <li><font><font>将用于</font></font><em><font><font>过度</font></font></em><font><font>,</font></font><em><font><font>超出</font></font></em><font><font>和</font></font><em><font><font>向下</font></font></em><font><font>事件</font><font>的框架</font><font>。</font></font></li> +</ul> + +<div class="note"> +<p><strong><font><font>注意</font></font></strong><font><font>:超越事件与悬停相同,当指针从按钮中移出时,当按下按钮时,向下移动。</font></font></p> +</div> + +<p><font><font>现在我们需要定义</font></font><code>startGame()</code><font><font>上面代码中引用</font><font>的</font><font>函数:</font></font></p> + +<pre class="brush: js">function startGame() { + startButton.destroy(); + ball.body.velocity.set(150, -150); + playing = true; +} +</pre> + +<p><font><font>当按下按钮时,我们删除按钮,设置球的初始速度并将</font></font><code>playing</code><font><font>变量</font><font>设置</font><font>为</font></font><code>true</code><font><font>。</font></font></p> + +<p><font><font>最后对于这一部分,回到你的</font></font><code>create()</code><font><font>函数,找到</font></font><code>ball.body.velocity.set(150, -150);</code><font><font>一行,并删除它。</font><font>你只需要按下按钮时移动球,而不是之前!</font></font></p> + +<h2 id="在游戏开始之前仍然保持桨"><font><font>在游戏开始之前仍然保持桨</font></font></h2> + +<p><font><font>它按预期工作,但是当游戏尚未开始时,我们仍然可以移动桨,这看起来有点愚蠢。</font><font>为了阻止这一点,我们可以利用</font></font><code>playing</code><font><font>变量,使得桨只有在游戏开始时才能移动。</font><font>要做到这一点,调整</font></font><code>update()</code><font><font>功能如下所示:</font></font></p> + +<pre class="brush: 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; + } +} +</pre> + +<p>这样一来,在所有的装载和准备之后,但在实际游戏开始之前,桨是不可移动的。</p> + +<h2 id="比较你的代码"><font><font>比较你的代码</font></font></h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/1rpj71k4/","","400")}}</p> + +<h2 id="下一步"><font><font>下一步</font></font></h2> + +<p><font><font>在本系列文章中我们将做的最后一件事情是,通过添加一些</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Randomizing_gameplay"><font><font>随机化</font></font></a><font><font>的方式,球从球上弹起来,</font><font>使游戏更有趣</font><font>。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens", "Games/Workflows/2D_Breakout_game_Phaser/Randomizing_gameplay")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/collision_detection/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/collision_detection/index.html new file mode 100644 index 0000000000..1977d93fb9 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/collision_detection/index.html @@ -0,0 +1,59 @@ +--- +title: Collision detection +slug: Games/Tutorials/2D_breakout_game_Phaser/Collision_detection +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial + - collision detection +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Collision_detection +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_Phaser/The_score")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第10步</font></font></strong><font><font>。</font><font>您可以在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson10.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson10.html</font></a><font>完成本课程后找到源代码</font><font>。</font></font></p> +</div> + +<p><font>现在接下来的挑战 - 球和砖块之间的碰撞检测。</font><font>幸运的是,我们可以使用物理引擎来检查单个对象(如球和桨)之间的碰撞,也可以检测对象和组之间的碰撞。</font></p> + +<h2 id="砖球碰撞检测"><font><font>砖/球碰撞检测</font></font></h2> + +<p><font><font>物理引擎使一切都变得更容易 - 我们只需要添加两个简单的代码。</font><font>首先,在你的</font></font><code>update()</code><font><font>函数中</font><font>添加一行</font><font>,检查球和砖之间的碰撞检测,如下所示:</font></font></p> + +<pre class="brush: 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; +} +</pre> + +<p><font><font>球的位置是根据组中所有砖的位置计算的。</font><font>第三个可选参数是发生冲突时执行的功能</font></font><code>ballHitBrick()</code><font><font>。</font><font>创建这个新功能作为代码的底部,就在结束</font></font><code></script></code><font><font>标签</font><font>之前</font><font>,如下所示:</font></font></p> + +<pre class="brush: js">function ballHitBrick(ball, brick) { + brick.kill(); +} +</pre> + +<p><font><font>就是这样!</font><font>重新加载你的代码,你应该看到新的碰撞检测工作正常。</font></font></p> + +<p><font><font>感谢Phaser,有两个参数传递给函数 - 第一个是球,我们在碰撞方法中明确定义,第二个是球碰撞的砖组中的单个砖。</font><font>在功能内部,我们从屏幕上删除所讨论的砖块,只需运行其</font></font><code>kill()</code><font><font>上</font><font>的</font><font>方法即可。</font></font></p> + +<p><font><font>您将期望在使用</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection"><font><font>纯JavaScript</font></font></a><font><font>时编写更多自己的计算机来实现碰撞检测</font><font>。</font><font>这是使用框架的好处 - 您可以为Phaser留下大量无聊的代码,并专注于制作游戏中最有趣和最有趣的部分。</font></font></p> + +<h2 id="比较你的代码"><font><font>比较你的代码</font></font></h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/wwneakwf/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p><font><font>我们可以打砖块并删除它们,这已经是游戏的一个很好的补充。</font><font>结果,更好地计算被毁砖增加</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/The_score"><font><font>得分</font></font></a><font><font>。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_Phaser/The_score")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/extra_lives/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/extra_lives/index.html new file mode 100644 index 0000000000..81143d4c14 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/extra_lives/index.html @@ -0,0 +1,124 @@ +--- +title: Extra lives +slug: Games/Tutorials/2D_breakout_game_Phaser/Extra_lives +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial + - lives +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Extra_lives +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Win_the_game", "Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第13步</font></font></strong><font><font>。</font><font>您可以在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson13.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson13.html</font></a><font>完成本课程后找到源代码</font><font>。</font></font></p> +</div> + +<p><font>我们可以通过增加生活使游戏更愉快。</font><font>在这篇文章中,我们将实施一个生活系统,以便玩家可以继续玩,直到他们失去了三个生命,而不仅仅是一个人。</font></p> + +<h2 id="新变量"><font><font>新变量</font></font></h2> + +<p>在代码中的现有添加下面添加以下新变量:</p> + +<pre class="brush: js">var lives = 3; +var livesText; +var lifeLostText; +</pre> + +<p>这些分别将存储生命数,显示剩余生命数的文本标签,以及当玩家失去生命之后将在屏幕上显示的文本标签。</p> + +<h2 id="定义新的文本标签"><font><font>定义新的文本标签</font></font></h2> + +<p><font><font>定义文本看起来像我们已经在</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/The_score"><font><font>分数</font></font></a><font><font>课上</font><font>已经做</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/The_score"><font>的</font></a><font>。</font></font><code>scoreText</code><font><font>在</font></font><code>create()</code><font><font>函数</font><font>内</font><font>的现有</font><font>定义</font><font>下方添加以下行</font><font>:</font></font></p> + +<pre class="brush: 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; +</pre> + +<p><font><font>在</font></font><code>livesText</code><font><font>与</font></font><code>lifeLostText</code><font><font>物体看起来非常相似的</font></font><code>scoreText</code><font><font>一个-它们定义在屏幕上的位置,显示实际文本和字体样式。</font><font>前者被锚定在其右上边缘上,与屏幕正确对齐,后者位于中心位置,两者均使用</font></font><code>anchor.set()</code><font><font>。</font></font></p> + +<p><font><font>该</font></font><code>lifeLostText</code><font><font>会表示,只有当生命消失,因此其知名度初始设置为</font></font><code>false</code><font><font>。</font></font></p> + +<h3 id="使我们的文字造型干燥"><font><font>使我们的文字造型干燥</font></font></h3> + +<p><font><font>正如你可能已经注意到,我们使用相同的造型为三种文本:</font></font><code>scoreText</code><font><font>,</font></font><code>livesText</code><font><font>和</font></font><code>lifeLostText</code><font><font>。</font><font>如果我们想要更改字体大小或颜色,我们必须在多个地方进行。</font><font>为了使我们更容易维护,将来我们可以创建一个单独的变量来保存我们的样式,让我们</font></font><code>textStyle</code><font><font>将其</font><font>调用</font><font>并放在文本定义之前:</font></font></p> + +<pre class="brush: js">textStyle = { font: '18px Arial', fill: '#0095DD' }; +</pre> + +<p>现在我们可以在使用文本标签的时候使用这个变量 - 更新你的代码,使文本样式的多个实例被替换为变量:</p> + +<pre class="brush: 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; +</pre> + +<p>这样一来,改变一个变量中的字体将会将更改应用于每个使用的地方。</p> + +<h2 id="生活处理代码"><font><font>生活处理代码</font></font></h2> + +<p><font><font>为了在我们的游戏中实现生活,让我们先改变球对</font></font><code>onOutOfBounds</code><font><font>事件的影响。</font><font>而不是执行匿名函数并立即显示警报:</font></font></p> + +<pre class="brush: js"><s>ball.events.onOutOfBounds.add(function(){ + alert('Game over!'); + location.reload(); +}, this);</s> +</pre> + +<p><font><font>我们将分配一个所谓的新功能</font></font><code>ballLeaveScreen</code><font><font>; </font><font>删除以前的事件处理程序(如上所示),并将其替换为以下行:</font></font></p> + +<pre class="brush: js">ball.events.onOutOfBounds.add(ballLeaveScreen, this); +</pre> + +<p><font><font>我们想减少每次球离开帆布的人数。</font></font><code>ballLeaveScreen()</code><font><font>在代码末尾</font><font>添加</font><font>函数定义:</font></font></p> + +<pre class="brush: js">function ballLeaveScreen() { + lives--; + if(lives) { + livesText.setText('Lives: '+lives); + lifeLostText.visible = true; + ball.reset(game.world.width*0.5, game.world.height-25); + paddle.reset(game.world.width*0.5, game.world.height-5); + game.input.onDown.addOnce(function(){ + lifeLostText.visible = false; + ball.body.velocity.set(150, -150); + }, this); + } + else { + alert('You lost, game over!'); + location.reload(); + } +} +</pre> + +<p><font><font>而不是立即打印警报,当你失去了一生,我们首先从当前的数字减去一个生命,并检查它是否是一个非零值。</font><font>如果是,那么玩家还是有一些生命剩下,可以继续玩 - 他们会看到生命中的消息,球和桨的位置将被重置在屏幕上和下一个输入(点击或触摸),消息将被隐藏球将再次开始移动。</font></font></p> + +<p><font><font>当可用生活数量达到零时,游戏结束,并显示游戏过期警报消息。</font></font></p> + +<h2 id="事件">事件</h2> + +<p><font><font>您可能已经注意到了</font></font><code>add()</code><font><font>,并</font></font><code>addOnce()</code><font><font>在上面的两个代码块的方法调用,并想知道它们的区别。</font><font>不同之处在于,该</font></font><code>add()</code><font><font>方法绑定给定的函数,并使其在每次事件发生时执行,同时</font></font><code>addOnce()</code><font><font>当您希望绑定函数只执行一次,然后解除绑定时有用,因此不会再次执行。</font><font>在我们的例子中,每个</font></font><code>outOfBounds</code><font><font>事件</font></font><code>ballLeaveScreen</code><font><font>都将被执行,但当球离开屏幕时,我们只想从屏幕上删除一次消息。</font></font></p> + +<h2 id="比较你的代码">比较你的代码</h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/yk1c5n0b/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p><font><font>生活让游戏更加宽容 - 如果你失去一个生命,你还剩下两个,可以继续玩。</font><font>现在让我们通过添加</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens"><font><font>动画和补间来</font></font></a><font><font>扩展游戏的外观和感觉</font><font>。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Win_the_game", "Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/game_over/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/game_over/index.html new file mode 100644 index 0000000000..d91bcc5e3b --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/game_over/index.html @@ -0,0 +1,53 @@ +--- +title: Game over +slug: Games/Tutorials/2D_breakout_game_Phaser/Game_over +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial + - game over +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Game_over +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls", "Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第8步</font></font></strong><font><font>。</font><font>在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson08.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson08.html</font></a><font>完成本课后,您可以找到源代码</font><font>。</font></font></p> +</div> + +<p>为了使游戏更有趣,我们可以引入失去的能力 - 如果在到达屏幕底部边缘之前没有击球,那么这个游戏将会结束。</p> + +<h2 id="如何输"><font><font>如何输</font></font></h2> + +<p><font><font>为了提供丢失的能力,我们将禁用球与屏幕底部的碰撞。</font><font>在</font></font><code>create()</code><font><font>函数</font><font>内添加下面的代码</font><font>; </font><font>刚刚定义球的属性就好了:</font></font></p> + +<pre class="brush: js">game.physics.arcade.checkCollision.down = false; +</pre> + +<p><font>这将使三个墙壁(顶部,左侧和右侧)弹回球,但是第四个(底部)将消失,如果桨错过,则球从屏幕上脱落。</font><font>我们需要一种方法来检测并相应地采取行动。</font><font>在以前的新的下方添加以下行:</font></p> + +<pre class="brush: js">ball.checkWorldBounds = true; +ball.events.onOutOfBounds.add(function(){ + alert('Game over!'); + location.reload(); +}, this); +</pre> + +<p><font><font>添加这些行将使得球检查世界(在我们的例子中是画布)边界并执行绑定到</font></font><code>onOutOfBounds</code><font><font>事件</font><font>的函数</font><font>。</font><font>当您点击生成的警报时,页面将被重新加载,以便您可以再次播放。</font></font></p> + +<h2 id="比较你的代码"><font><font>比较你的代码</font></font></h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/436bckb7/","","400")}}</p> + +<h2 id="下一步"><font><font>下一步</font></font></h2> + +<p><font><font>现在的基本游戏就是让我们通过引入砖块来更有趣的是 - 现在是</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field"><font><font>建造砖块</font></font></a><font><font>的时候了</font><font>。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls", "Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/index.html new file mode 100644 index 0000000000..9f283f7774 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/index.html @@ -0,0 +1,57 @@ +--- +title: 使用Phaser开发2D breakout game +slug: Games/Tutorials/2D_breakout_game_Phaser +tags: + - Phaser + - 教程 + - 游戏 +translation_of: Games/Tutorials/2D_breakout_game_Phaser +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{Next("Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework")}}</p> + +<p class="summary">在这个手把手的教程中,我们将使用Phaser框架制作一个使用JavaScript构建简单的MDN消除游戏。</p> + +<p>教程的每一步骤都会有可供修改的样品来玩,所以你可以看到开发的每一步中间步骤。 您将学到如何使用Phaser框架来实现基础游戏机制的基本知识,诸如渲染和移动图像,碰撞检测,控制机制,框架特定的帮助器功能,动画和补间,以及获胜和失败状态等。</p> + +<p>为了充分理解这一系列的文章,您应该确保已有基本的中级JavaScript知识。学完本教程,您将有能力用Phaser构建简单的Web游戏。</p> + +<p><img alt="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." src="https://mdn.mozillademos.org/files/11323/mdn-breakout-phaser.png" style="display: block; height: 320px; margin: 0px auto; width: 480px;"></p> + +<h2 id="教学清单">教学清单</h2> + +<p>所有的课程 — 以及我们接下来将一起做的各个版本的 <a href="https://end3r.github.io/Gamedev-Phaser-Content-Kit/demos/lesson16.html">MDN Breakout game</a> 都能在 <a href="https://end3r.github.io/Gamedev-Phaser-Content-Kit/demos/">GitHub</a>上找到</p> + +<ol> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework">初始化框架</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Scaling">缩放</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen">加载资源并在屏幕上打印</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Move_the_ball">移动小球</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Physics">物理</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls">从墙上弹开</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Player_paddle_and_controls">弹块和控制</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Game_over">游戏结束</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Build_the_brick_field">建立砖块</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Collision_detection">碰撞检测</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/The_score">得分</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Win_the_game">胜利</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Extra_lives">额外生命</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Animations_and_tweens">动画与补间</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Buttons">按钮</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Randomizing_gameplay">随机游戏</a></li> +</ol> + +<p>学习路线的小提示 — 最好先熟悉使用原生JavaScript进行网页游戏开发,这样可以打下坚实的基础.如果你还不熟悉原生javascript开发,我们建议你先过一遍这个系列, <a href="/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript">使用原生Javascript开发MDN消除游戏</a>.</p> + +<p>在那之后,你就能随意挑选框架并用在你的项目中;我们选择了Phaser这个稳定优越的框架,它有着好的支持和社区环境以及大量优秀的插件. 框架加速了开发并能帮你管理无趣的部分,让你专注于有意思的事务. 然而, 框架也有不好的地方, 所以当一些意想不到的事情发生了或者想实现一些框架没有提供的功能时,你就将需要原生的JavaScript知识了.</p> + +<div class="note"> +<p><strong>注意</strong>: 本系列文章可用作实际游戏开发的材料。 如果您想要使用Phaser讨论游戏开发,您还可以使用基于本教程的 <a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit">Gamedev Phaser内容套件</a>.</p> +</div> + +<h2 id="Next_steps">Next steps</h2> + +<p>好了,那我们就开始吧!前往系列第一部分 — <a href="/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework">初始化框架</a>.</p> + +<p>{{Next("Games/Workflows/2D_Breakout_game_Phaser/Initialize_the_framework")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.html new file mode 100644 index 0000000000..ed6ef03718 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/initialize_the_framework/index.html @@ -0,0 +1,90 @@ +--- +title: Initialize the framework +slug: Games/Tutorials/2D_breakout_game_Phaser/Initialize_the_framework +tags: + - Canvas + - HTML + - JavaScript + - Phaser + - 二维 + - 入门 + - 教程 + - 游戏 +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Initialize_the_framework +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/zh-CN/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser", "Games/Tutorials/2D_Breakout_game_Phaser/Scaling")}}</p> + +<div class="summary"> +<p>这是<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser">Gamedev Phaser教程</a>系列的第一课. 在课程完成之后,你可以在<a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson01.html">Gamedev-Phaser-Content-Kit/demos/lesson01.html</a>找到源码.</p> +</div> + +<p><span class="seoSummary">在我们开始写游戏的功能之前,我们需要创建一个用来内部渲染游戏的基础架构.使用HTML就能做到 — Parser框架将生成所需的 {{htmlelement("canvas")}} 元素.</span></p> + +<h2 id="游戏的HTML">游戏的HTML</h2> + +<p>HTML文档结构非常的简单,这个游戏将整个被渲染在框架生成的{{htmlelement("canvas")}} 元素上. 拿起你最爱的编辑器,挑一个好目录,创建一个HTML文档,存成index.html,然后写下下面的代码:</p> + +<pre class="brush: 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> + var game = new Phaser.Game(480, 320, Phaser.AUTO, null, { + preload: preload, create: create, update: update + }); + function preload() {} + function create() {} + function update() {} +</script> +</body> +</html> +</pre> + +<h2 id="下载Phaser">下载Phaser</h2> + +<p>下面我们将下载Phaser的代码,并应用到我们的HTML文档中.</p> + +<ol> + <li>进入 <a href="http://phaser.io/download/stable">Phaser 下载页面</a>.</li> + <li>选择最适合你的下载项 — 我们建议选择min.js,因为它最小,而且你不太可能想去看它的源码</li> + <li>将Phaser的源码存到一个和index.html同级的 /js 的目录下</li> + <li>在上面第一个 {{htmlelement("script")}} 标签里写下phaser的路径.</li> +</ol> + +<h2 id="捋一捋我们干了些啥">捋一捋我们干了些啥</h2> + +<p>这个时候我们在 {{htmlelement("header")}} 里定义了 {{htmlelement("charset")}} ,{{htmlelement("title")}} 和一些基础的css来重置默认的margin和padding. 我们也用 {{htmlelement("script")}} 标签向页面引入了 Phaser 源码。{{htmlelement("body ")}} 里也有一个 {{htmlelement("script")}} 标签,我们将在里面写 JavaScript 代码来渲染和控制游戏。</p> + +<p>{{htmlelement("canvas")}} 元素是由框架自动生成的。我们是通过 <code>Phaser.Game </code>创建一个对象并赋给了 game 变量来完成初始化的。参数的含义是:</p> + +<ul> + <li>width 和 height 设置了 {{htmlelement("canvas")}} 宽高.</li> + <li>渲染方式。有三个选项分别是 <code>AUTO<font face="Open Sans, arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">,</span></font></code><code>CANVAS</code> 和 <code>WEBGL</code>。我们可以指定使用 Canvas 还是 WebGL 来渲染,如果使用了 Auto 则优先使用 WebGL,如果浏览器不支持则会选择 Canvas。</li> + <li>{{htmlelement("canvas")}} 的 id。如果该参数有值,则使用该值作为 canvas 标签的 id,我们传入 null,则 phaser 会决定 canvas 的 id 值。</li> + <li>第四个参数指定了 phaser 的三个生命周期所对应的函数。我们使用相同的名字来让程序更清晰 + <ul> + <li><code>preload</code> 进行资源的加载。</li> + <li><code>create</code> 会在资源加载完成后执行一次。</li> + <li><code>update</code> 会一直循环执行来处理每一帧动画。</li> + </ul> + </li> +</ul> + +<h2 id="完整示例">完整示例</h2> + +<p>以下是第一章的完整代码,可以直接在 JSFiddle 中运行:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/h6cwzv2b/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p>现在我们已经完成了一个简单的 HTML 页面,并且学习了如何安装 Phaser, 让我们继续学习第二章: <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Scaling">scaling</a>.</p> + +<p>{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser", "Games/Tutorials/2D_Breakout_game_Phaser/Scaling")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.html new file mode 100644 index 0000000000..135bcee403 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/load_the_assets_and_print_them_on_screen/index.html @@ -0,0 +1,71 @@ +--- +title: Load the assets and print them on screen +slug: >- + Games/Tutorials/2D_breakout_game_Phaser/Load_the_assets_and_print_them_on_screen +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Sprites + - Tutorial +translation_of: >- + Games/Tutorials/2D_breakout_game_Phaser/Load_the_assets_and_print_them_on_screen +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Scaling", "Games/Workflows/2D_Breakout_game_Phaser/Move the ball")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第三步</font></font></strong><font><font>。</font><font>您可以在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson03.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson03.html</font></a><font>完成本课程后找到源代码</font></font></p> +</div> + +<p><font>我们的游戏将围绕屏幕滚动,弹出一个桨,摧毁砖块赚取积分 - 熟悉吗?</font><font>在本文中,我们将介绍如何将sprite添加到我们的gameworld中。</font></p> + +<h2 id="有一个球"><font><font>有一个球</font></font></h2> + +<p><font><font>我们开始创建一个JavaScript变量来表示我们的球 - 在游戏初始化代码(我们的</font></font><code>var game...</code><font><font>块)和</font></font><code>preload()</code><font><font>函数</font><font>之间添加以下行</font><font>:</font></font></p> + +<pre class="brush: js">var ball; +</pre> + +<div class="note"> +<p><strong><font><font>注意</font></font></strong><font><font>:为了本教程,我们将使用全局变量。</font><strong><font>本教程的目的是教导Phaser特定的游戏开发方法,而不是主观的最佳方法。</font></strong></font></p> +</div> + +<h2 id="加载球精灵"><font><font>加载球精灵</font></font></h2> + +<p><font><font>使用Phaser加载图像并将其打印在我们的画布上比使用纯JavaScript容易得多。</font><font>要加载资产,我们将使用</font></font><code>game</code><font><font>由Phaser创建</font><font>的</font><font>对象,执行其</font></font><code>load.image()</code><font><font>方法。</font><font>在</font></font><code>preload()</code><font><font>函数的底部</font><font>添加以下新行</font><font>:</font></font></p> + +<pre class="brush: js">function preload() { + // ... + game.load.image('ball', 'img/ball.png'); +} +</pre> + +<p><font><font>第一个参数是我们要提供资产的名称 - 这将在我们的游戏代码中使用,例如我们的</font></font><code>ball</code><font><font>变量名称,所以我们需要确保它是一样的。</font><font>第二个参数是图形资源的相对路径。</font><font>在我们的情况下,我们将加载我们的球的图像(请注意,文件名不一定是一致的,但我们建议,因为它使一切更容易遵循。)</font></font></p> + +<p><font><font>当然,要加载图像,它需要在我们的代码目录中可用。</font></font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/img/ball.png"><font><font>从Github抓住球图像</font></font></a><font><font>,并将其保存</font></font><code>/img</code><font><font>在与</font></font><code>index.html</code><font><font>文件</font><font>相同位置</font><font>的</font><font>目录中</font><font>。</font></font></p> + +<p><font><font>现在,要在屏幕上显示,我们将使用另一种Phaser方法</font></font><code>add.sprite()</code><font><font>:</font><font>在</font></font><code>create()</code><font><font>函数</font><font>内添加以下新的代码行</font><font>,如图所示:</font></font></p> + +<pre class="brush: js">function create() { + ball = game.add.sprite(50, 50, 'ball'); +} +</pre> + +<p><font><font>这将添加球到游戏,并将其呈现在屏幕上。</font><font>前两个参数是要添加的画布的x和y坐标,第三个是我们之前定义的资产的名称。</font><font>就是这样 - 如果你加载你的</font></font><code>index.html</code><font><font>文件,你会看到已经加载并在画布上渲染的图像!</font></font></p> + +<h2 id="比较你的代码"><font><font>比较你的代码</font></font></h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/98xrv9x5/","","400")}}</p> + +<h2 id="下一步"><font><font>下一步</font></font></h2> + +<p><font><font>打出球很容易; </font><font>接下来我们将尝试</font><font>在屏幕上</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Move_the_ball"><font><font>移动球</font></font></a><font><font>。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Scaling", "Games/Workflows/2D_Breakout_game_Phaser/Move the ball")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.html new file mode 100644 index 0000000000..331d02cfab --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/move_the_ball/index.html @@ -0,0 +1,49 @@ +--- +title: Move the ball +slug: Games/Tutorials/2D_breakout_game_Phaser/Move_the_ball +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial + - moving +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Move_the_ball +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen", "Games/Workflows/2D_Breakout_game_Phaser/Physics")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第4步</font></font></strong><font><font>。</font><font>在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson04.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson04.html</font></a><font>完成本课后,您可以找到源代码</font><font>。</font></font></p> +</div> + +<p><font>我们在屏幕上打印了我们的蓝色球,但它什么都不做,这样做会很酷。</font><font>本文介绍如何做到这一点。</font></p> + +<h2 id="在每个框架上更新球的位置"><font><font>在每个框架上更新球的位置</font></font></h2> + +<p><font><font>记住</font></font><code>update()</code><font><font>功能及其定义?</font><font>其中的代码在每个框架上执行,所以它是一个完美的地方,将代码更新球的位置在屏幕上。</font><font>在里面添加以下新行代码</font></font><code>update()</code><font><font>,如下所示:</font></font></p> + +<pre class="brush: js">function update() { + ball.x += 1; + ball.y += 1; +} +</pre> + +<p><font><font>上面的代码</font><font>在每个框架上为表示画布上的球坐标的属性</font></font><code>x</code><font><font>和</font></font><code>y</code><font><font>属性</font><font>添加</font><font>了一个。</font><font>重新加载index.html,你应该看到球在屏幕上滚动。</font></font></p> + +<h2 id="比较你的代码"><font><font>比较你的代码</font></font></h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/g1cfp0vv/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p><font><font>下一步是添加一些基本的碰撞检测,所以我们的球可以从墙壁反弹。</font><font>这将需要几行代码 - 一个比我们迄今为止看到的更复杂的步骤,特别是如果我们也想添加桨和砖碰撞 - 但是幸运的是Phaser使我们比我们想要使用纯粹的方法更容易做到这一点JavaScript的。</font></font></p> + +<p><font><font>无论如何,在我们做所有的事情之前,我们将首先介绍Phaser的</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Physics"><font><font>物理</font></font></a><font><font>引擎,并做一些设置工作。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen", "Games/Workflows/2D_Breakout_game_Phaser/Physics")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/physics/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/physics/index.html new file mode 100644 index 0000000000..4f908a9bc2 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/physics/index.html @@ -0,0 +1,99 @@ +--- +title: Physics +slug: Games/Tutorials/2D_breakout_game_Phaser/Physics +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial + - physics +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Physics +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Move_the_ball", "Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第5步</font></font></strong><font><font>。</font><font>您可以在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson05.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson05.html</font></a><font>完成本课程后找到源代码</font></font></p> +</div> + +<p><font>为了在我们的游戏中的对象之间进行正确的碰撞检测,我们将需要物理学; </font><font>本文将向您介绍Phaser中的可用内容,以及演示典型的简单设置。</font></p> + +<h2 id="添加物理效果"><font><font>添加物理效果</font></font></h2> + +<p><font><font>Phaser与三个不同的物理引擎(Arcade Physics,P2和Ninja Physics)捆绑在一起,第四个选项Box2D可作为商业插件使用。</font><font>对于像我们这样的简单游戏,我们可以使用Arcade Physics引擎。</font><font>我们不需要任何重的几何计算 - 毕竟只是一个球从墙壁和砖块弹起来。</font></font></p> + +<p><font><font>首先,让我们在游戏中初始化Arcade Physics引擎。</font></font><code>physics.startSystem()</code><font><font>在</font></font><code>create</code><font><font>函数</font><font>开头</font><font>添加</font><font>方法</font><font>(使其成为函数内的第一行),如下所示:</font></font></p> + +<pre class="brush: js">game.physics.startSystem(Phaser.Physics.ARCADE); +</pre> + +<p><font><font>接下来,我们需要为物理系统启用我们的球 - 默认情况下,Phaser对象物理不启用。</font><font>在</font></font><code>create()</code><font><font>函数</font><font>底部添加以下行</font><font>:</font></font></p> + +<pre class="brush: js">game.physics.enable(ball, Phaser.Physics.ARCADE); +</pre> + +<p><font><font>接下来,如果我们要在屏幕上移动我们的球,我们可以设置</font></font><code>velocity</code><font><font>它</font></font><code>body</code><font><font>。</font><font>再次添加以下行</font></font><code>create()</code><font><font>:</font></font></p> + +<pre class="brush: js">ball.body.velocity.set(150, 150); +</pre> + +<h2 id="删除我们以前的更新说明"><font><font>删除我们以前的更新说明</font></font></h2> + +<p><font><font>记得删除添加值的我们的老方法</font></font><code>x</code><font><font>,并</font></font><code>y</code><font><font>从</font></font><code>update()</code><font><font>功能:</font></font></p> + +<pre class="brush: js">function update() { +<s> ball.x += 1;</s> +<s> ball.y += 1;</s> +} +</pre> + +<p>我们正在使用物理引擎正确处理。</p> + +<h2 id="最终代码检查"><font><font>最终代码检查</font></font></h2> + +<p>最新的代码应该如下所示:</p> + +<pre class="brush: js">var ball; + +function preload() { + game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; + game.scale.pageAlignHorizontally = true; + game.scale.pageAlignVertically = true; + game.stage.backgroundColor = '#eee'; + game.load.image('ball', 'img/ball.png'); +} + +function create() { + game.physics.startSystem(Phaser.Physics.ARCADE); + ball = game.add.sprite(50, 50, 'ball'); + game.physics.enable(ball, Phaser.Physics.ARCADE); + ball.body.velocity.set(150, 150); +} + +function update() { +} +</pre> + +<p><font><font>尝试重新加载</font></font><code>index.html</code><font><font>- 球应该在给定的方向上不断移动。</font><font>目前,物理引擎的重力和摩擦力设定为零。</font><font>增加重力将导致球落下,同时摩擦力最终会停止球。</font></font></p> + +<h2 id="物理效果趣味"><font><font>物理效果趣味</font></font></h2> + +<p><font><font>你可以用物理学来做更多的事情,例如添加</font></font><code>ball.body.gravity.y = 100;</code><font><font>你将设置球的垂直重力。</font><font>因此,它将向上发射,但是由于重力的作用而下降。</font></font></p> + +<p><font><font>这种功能只是冰山一角 - 有各种功能和变量可以帮助您操纵物理对象。</font><font>查看官方</font></font><a href="http://phaser.io/docs#physics"><font><font>物理文档,</font></font></a><font><font>并使用</font></font><a href="http://phaser.io/examples/v2/category/arcade-physics"><font><font>Arcade</font></font></a><font><font>和</font></font><a href="http://phaser.io/examples/v2/category/p2-physics"><font><font>P2</font></font></a><font><font>物理系统</font><font>查看大量示例</font><font>。</font></font></p> + +<h2 id="比较你的代码"><font><font>比较你的代码</font></font></h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/bjto9nj8/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p><font><font>现在我们可以转到下一课,看看如何让球</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls"><font><font>从墙上弹起</font></font></a><font><font>。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Move_the_ball", "Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.html new file mode 100644 index 0000000000..07ee9e7ee7 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/player_paddle_and_controls/index.html @@ -0,0 +1,122 @@ +--- +title: Player paddle and controls +slug: Games/Tutorials/2D_breakout_game_Phaser/Player_paddle_and_controls +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Player_paddle_and_controls +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_Phaser/Game_over")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第7步</font></font></strong><font><font>。</font><font>您可以在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson07.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson07.html</font></a><font>完成本课程后找到源代码</font><font>。</font></font></p> +</div> + +<p><font>我们有球从墙上移动并弹跳,但它很快变得无聊 - 没有互动!</font><font>我们需要一种介绍游戏的方法,所以在这篇文章中,我们将创建一个桨来移动并击中球。</font></p> + +<h2 id="渲染桨"><font><font>渲染桨</font></font></h2> + +<p>从框架的角度看,桨非常类似于球 - 我们需要添加一个变量来表示它,加载相关的图像资源,然后做出魔法。</p> + +<h3 id="装载桨"><font><font>装载桨</font></font></h3> + +<p><font><font>首先,添加</font></font><code>paddle</code><font><font>我们将在我们的游戏中使用的</font></font><code>ball</code><font><font>变量</font><font>,就在</font><font>变量之后:</font></font></p> + +<pre class="brush: js">var paddle; +</pre> + +<p><font><font>然后,在该</font></font><code>preload</code><font><font>功能中,</font></font><code>paddle</code><font><font>通过添加以下新</font></font><code>load.image()</code><font><font>调用来</font><font>加载</font><font>图像</font><font>:</font></font></p> + +<pre class="brush: js">function preload() { + // ... + game.load.image('ball', 'img/ball.png'); + game.load.image('paddle', 'img/paddle.png'); +} +</pre> + +<h3 id="添加桨图形"><font><font>添加桨图形</font></font></h3> + +<p><font><font>所以我们不要忘记,在这一点上,你应该</font><font>从Github </font><font>抓住这个</font></font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/img/paddle.png"><font><font>图形</font></font></a><font><font>,并保存在你的</font></font><code>/img</code><font><font>文件夹中。</font></font></p> + +<h3 id="渲染桨用物理引擎"><font><font>渲染桨用物理引擎</font></font></h3> + +<p><font><font>接下来,我们将通过</font></font><code>add.sprite()</code><font><font>在</font></font><code>create()</code><font><font>函数中添加</font><font>以下</font><font>调用</font><font>来初始化我们的桨,将其</font><font>添加到底部:</font></font></p> + +<pre class="brush: js">paddle = game.add.sprite(game.world.width*0.5, game.world.height-5, 'paddle'); +</pre> + +<p><font><font>我们可以使用</font></font><code>world.width</code><font><font>和</font></font><code>world.height</code><font><font>值来将桨定位到我们想要的位置:</font></font><code>game.world.width*0.5</code><font><font>将在屏幕中间。</font><font>在我们这个例子中,世界和画布是一样的,但是对于其他类型的游戏,例如侧滚滚,这个世界会变大,你可以修改它来创造有趣的效果。</font></font></p> + +<p><font><font>你会注意到,如果你</font></font><code>index.html</code><font><font>在这一点上</font><font>重新加载</font><font>,那么桨是目前不完全在中间的。</font><font>为什么?</font><font>因为计算位置的锚总是从对象的左上角开始。</font><font>我们可以改变它,使锚在桨的宽度的中间和它的高度的底部,所以更容易将其定位在底部边缘。</font><font>添加以下新行以下的行:</font></font></p> + +<pre class="brush: js">paddle.anchor.set(0.5,1); +</pre> + +<p><font><font>桨现在位于我们想要的地方。</font><font>现在,为了使它与球碰撞,我们必须为桨提供物理效果。</font><font>继续添加以下新行,再次在</font></font><code>create()</code><font><font>函数</font><font>的底部</font><font>:</font></font></p> + +<pre class="brush: js">game.physics.enable(paddle, Phaser.Physics.ARCADE); +</pre> + +<p><font><font>现在,魔法可以开始发生 - 该框架可以在每个框架上检查碰撞检测。</font><font>要启用桨和球之间的碰撞检测,请将</font></font><code>collide()</code><font><font>方法</font><font>添加</font><font>到如下</font></font><code>update()</code><font><font>功能中:</font></font></p> + +<pre class="brush: js">function update() { + game.physics.arcade.collide(ball, paddle); +} +</pre> + +<p><font><font>第一个参数是我们感兴趣的对象之一 - 球 - 第二个是另一个,桨。</font><font>这有效,但不如我们预期的那样 - 当球击中桨时,桨从屏幕上掉下来!</font><font>我们想要的就是球从跳板上跳起来,而桨子停在同一个地方。</font><font>我们可以将</font></font><code>body</code><font><font>桨</font><font>设置成</font></font><code>immovable</code><font><font>球,所以当球击中它时不会移动。</font><font>为此,请在</font></font><code>create()</code><font><font>函数</font><font>底部添加以下行</font><font>:</font></font></p> + +<pre class="brush: js">paddle.body.immovable = true; +</pre> + +<p>现在它按预期工作。</p> + +<h2 id="控制桨"><font><font>控制桨</font></font></h2> + +<p><font><font>接下来的问题是我们不能移动桨。</font><font>要做到这一点,我们可以使用系统的默认输入(鼠标或触摸,取决于平台),并将桨位置设置到位置的</font></font><code>input</code><font><font>位置。</font><font>将以下新行添加到</font></font><code>update()</code><font><font>函数中,如下所示:</font></font></p> + +<pre class="brush: js">function update() { + game.physics.arcade.collide(ball, paddle); + paddle.x = game.input.x; +} +</pre> + +<p><font><font>现在在每个新的一帧上,桨的</font></font><code>x</code><font><font>位置将根据输入的</font></font><code>x</code><font><font>位置进行</font><font>调整</font><font>,但是当我们开始游戏时,桨的位置不在中间。</font><font>这是因为输入位置尚未定义。</font><font>要修复,我们可以将默认位置(如果输入位置尚未定义)设置为屏幕中间。</font><font>更新上一行如下:</font></font></p> + +<pre class="brush: js">paddle.x = game.input.x || game.world.width*0.5; +</pre> + +<p><font><font>如果您还没有这样做,请重新加载</font></font><code>index.html</code><font><font>并尝试!</font></font></p> + +<h2 id="定位球"><font><font>定位球</font></font></h2> + +<p><font><font>我们有桨按预期工作,所以我们把球放在上面。</font><font>它非常类似于定位桨 - 我们需要将其放置在屏幕中间水平和垂直的底部,与底部有一点偏移。</font><font>要按照我们想要的方式放置它,我们将把锚定位到球的正中间。</font><font>找到现有的</font><font>行,并将其替换为以下两行:</font></font><code>ball = game.add.</code><code>sprite( ... )</code></p> + +<pre class="brush: js">ball = game.add.sprite(game.world.width*0.5, game.world.height-25, 'ball'); +ball.anchor.set(0.5);</pre> + +<p><font><font>速度保持不变 - 我们只是将第二个参数的值从150改为-150,所以球将通过向上移动而不是下降来开始游戏。</font><font>查找现有</font></font><code>ball.body.velocity.set( ... )</code><font><font>行并将其更新为以下内容:</font></font></p> + +<pre class="brush: js">ball.body.velocity.set(150, -150); +</pre> + +<p>现在球将从桨的中间开始。</p> + +<h2 id="比较你的代码"><font><font>比较你的代码</font></font></h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/ogqza0ye/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p><font><font>我们可以移动桨,并将球反弹,但是如果球从屏幕的底部边缘反弹,那又有什么意义?</font><font>我们来介绍丢失的可能性 - 也称为</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Game_over"><font><font>游戏</font></font></a><font><font>逻辑。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_Phaser/Game_over")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/randomizing_gameplay/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/randomizing_gameplay/index.html new file mode 100644 index 0000000000..8642ed4eb7 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/randomizing_gameplay/index.html @@ -0,0 +1,61 @@ +--- +title: Randomizing gameplay +slug: Games/Tutorials/2D_breakout_game_Phaser/Randomizing_gameplay +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Randomizing_gameplay +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{Previous("Games/Workflows/2D_Breakout_game_Phaser/Buttons")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16中的</font><font>第</font></font><strong><font><font>16步</font></font></strong><font><font>。</font><font>您可以在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson16.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson16.html</font></a><font>完成本课程后找到源代码</font><font>。</font></font></p> +</div> + +<p><font>我们的游戏似乎已经完成了,但是如果你看起来足够近,你会发现球在整个游戏中都以相同的角度从桨上弹起。</font><font>这意味着每个游戏都非常相似。</font><font>为了解决这个问题,提高可玩性,我们应该使反弹角度更加随机,在本文中我们将介绍一下如何。</font></p> + +<h2 id="让篮板更随机"><font><font>让篮板更随机</font></font></h2> + +<p><font><font>我们可以根据撞击桨的确切位置来改变球的速度,通过</font><font>使用沿着下方的线路运行功能</font><font>来修改</font></font><code>x</code><font><font>速度</font></font><code>ballHitPaddle()</code><font><font>。</font><font>现在添加这一行到您的代码,并尝试。</font></font></p> + +<pre class="brush: js">function ballHitPaddle(ball, paddle) { + ball.animations.play('wobble'); + ball.body.velocity.x = -1*5*(paddle.x-ball.x); +}</pre> + +<p><font>这有点魔法 - 新的速度越高,桨的中心和球撞到的地方之间的距离就越大。</font><font>此外,方向(左或右)由该值确定 - 如果球击中桨的左侧,则其将向左反弹,而击球右侧将向右反弹。</font><font>最终这样做是因为对某些值进行了一些实验,您可以进行自己的实验,看看会发生什么。</font><font>这当然不是完全随机的,但它确实使游戏玩法变得更加不可预测,因此更有趣。</font></p> + +<h2 id="比较你的代码"><font><font>比较你的代码</font></font></h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/3yds5ege/","","400")}}</p> + +<h2 id="概要"><font><font>概要</font></font></h2> + +<p><font>你已经完成了所有的课程 - 恭喜你!</font><font>在这一点上,您将了解到Phaser的基础知识和简单2D游戏背后的逻辑。</font></p> + +<h3 id="练习跟随"><font><font>练习跟随</font></font></h3> + +<p><font><font>你可以在游戏中做更多的事情 - 添加任何你觉得最好的东西,使它更有趣和有趣。</font><font>Phaser提供的无数有用的方法的基本介绍。</font><font>以下是关于如何扩展我们的小游戏的一些建议,让您开始:</font></font></p> + +<ul> + <li><font><font>添加第二个球或桨。</font></font></li> + <li><font><font>改变每次命中背景的颜色。</font></font></li> + <li><font><font>更改图像并使用自己的图像。</font></font></li> + <li><font><font>如果砖块被迅速摧毁,并排排列(或您选择的其他奖金),则可获得额外的奖励积分。</font></font></li> + <li><font><font>创建不同砖块布局的水平。</font></font></li> +</ul> + +<p><font><font>一定要检查越来越多的</font></font><a href="http://examples.phaser.io/"><font><font>示例</font></font></a><font><font>列表</font><font>和</font></font><a href="http://docs.phaser.io/"><font><font>官方文档</font></font></a><font><font>,</font><font>如果您需要任何帮助</font><font>,请访问</font></font><a href="http://www.html5gamedevs.com/forum/14-phaser/"><font><font>HTML5 Gamedevs论坛</font></font></a><font><font>。</font></font></p> + +<p><font><font>您也可以返回</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_breakout_game_Phaser"><font><font>本教程系列的索引页</font></font></a><font><font>。</font></font></p> + +<p>{{Previous("Games/Workflows/2D_Breakout_game_Phaser/Buttons")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/scaling/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/scaling/index.html new file mode 100644 index 0000000000..063f95aba9 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/scaling/index.html @@ -0,0 +1,64 @@ +--- +title: Scaling +slug: Games/Tutorials/2D_breakout_game_Phaser/Scaling +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Scaling +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/zh-CN/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser/Initialize_the_framework", "Games/Tutorials/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen")}}</p> + +<div class="summary"> +<p>这是<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser">Gamedev Phaser教程</a>系列的第二课. 在课程完成之后,你可以在<a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson01.html">Gamedev-Phaser-Content-Kit/demos/lesson02.html</a>找到源码.</p> +</div> + +<p><font>缩放是指游戏画布如何在不同的屏幕尺寸上进行显示。</font><font>我们可以在预加载阶段自动使游戏规模适合任何屏幕尺寸,之后就可以不用再担心屏幕尺寸的问题了。</font></p> + +<h2 id="Phaser中scale对象">Phaser中scale对象</h2> + +<p><font><font>Phaser中</font><font>有一个特殊的</font><font>对象:</font></font><code>scale</code>,<font><font>它包含一些特别的方法和属性。</font><font>让我们来更改一下上一节中创建的的</font></font><code>preload()</code>函数<font><font>:</font></font></p> + +<pre class="brush: js">function preload() { + game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; + game.scale.pageAlignHorizontally = true; + game.scale.pageAlignVertically = true; +} +</pre> + +<p><code>scaleMode</code><font><font> 有几个不同的选项来指定 Canvas 应该如何缩放:</font></font></p> + +<ul> + <li><code>NO_SCALE</code> — 不进行任何缩放。</li> + <li><code>EXACT_FIT</code> — 拉伸,填充屏幕,不保留长宽比。</li> + <li><code>SHOW_ALL</code> — 等比缩放,填充屏幕,保留长宽比,剩余空间用黑色填充<font>。</font></li> + <li><code>RESIZE</code> — 动态,每次都会根据屏幕生成画布,所以你需要在游戏运行时动态的放置游戏元素。这是一种进阶的模式<font>。</font></li> + <li><code>USER_SCALE</code> — 自定义<font>,允许您自己计算大小和比例。这也是一种进阶的模式。</font></li> +</ul> + +<p><code>preload()</code><font><font>中的其他两行代码</font></font><font><font>负责水平和垂直居中画布,所以它始终以屏幕为中心,无论大小如何。</font></font></p> + +<h2 id="设置背景颜色"><font><font>设置背景颜色</font></font></h2> + +<p><font><font>我们还可以给画布设置背景颜色来替代磨人的黑色背景。</font><font>通过更改</font></font><code>stage</code><font><font>对象的</font></font><code>backgroundColor</code><font><font>属性来添加,我们可以使用CSS颜色定义语法进行设置。</font><font>我们在刚才的代码下面添加以下代码:</font></font></p> + +<pre class="brush: js">game.stage.backgroundColor = '#eee'; +</pre> + +<h2 id="完整的代码">完整的代码</h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/6a64vecL/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p><font><font>现在我们设置了我们游戏的缩放比例,让我们继续第三课,并设计出如何</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen"><font><font>加载资源并将其显示在屏幕上</font></font></a><font><font>。</font></font></p> + +<p>{{PreviousNext("Games/Tutorials/2D_Breakout_game_Phaser/Initialize_the_framework", "Games/Tutorials/2D_Breakout_game_Phaser/Load_the_assets_and_print_them_on_screen")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/the_score/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/the_score/index.html new file mode 100644 index 0000000000..f71ded071f --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/the_score/index.html @@ -0,0 +1,76 @@ +--- +title: The score +slug: Games/Tutorials/2D_breakout_game_Phaser/The_score +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial + - scoring +translation_of: Games/Tutorials/2D_breakout_game_Phaser/The_score +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Collision_detection", "Games/Workflows/2D_Breakout_game_Phaser/Win_the_game")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第11步</font></font></strong><font><font>。</font><font>您可以在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson11.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson11.html</font></a><font>完成本课程后找到源代码</font><font>。</font></font></p> +</div> + +<p><font>得分也可以使游戏更有趣 - 你可以尝试击败自己的高分,或者你的朋友。</font><font>在这篇文章中,我们将为我们的游戏添加一个评分系统。</font></p> + +<p><font><font>我们将使用一个单独的变量来存储分数和Phaser的</font></font><code>text()</code><font><font>方法将其打印到屏幕上。</font></font></p> + +<h2 id="新变量">新变量</h2> + +<p><font><font>在以前定义的之后添加两个新变量:</font></font></p> + +<pre class="brush: js">// ... +var scoreText; +var score = 0; +</pre> + +<h2 id="将得分文字添加到游戏显示"><font><font>将得分文字添加到游戏显示</font></font></h2> + +<p><font><font>现在在</font></font><code>create()</code><font><font>函数</font><font>末尾添加这一行</font><font>:</font></font></p> + +<pre class="brush: js">scoreText = game.add.text(5, 5, 'Points: 0', { font: '18px Arial', fill: '#0095DD' }); +</pre> + +<p><font><font>该</font></font><code>text()</code><font><font>方法可以采用四个参数:</font></font></p> + +<ul> + <li><font><font>x和y坐标来绘制文本。</font></font></li> + <li><font><font>将呈现的实际文本。</font></font></li> + <li><font><font>用于呈现文本的字体样式。</font></font></li> +</ul> + +<p><font><font>最后一个参数与CSS样式非常相似。</font><font>在我们的例子中,乐谱文字将为蓝色,大小为18像素,并使用Arial字体。</font></font></p> + +<h2 id="当砖块被破坏时更新分数"><font><font>当砖块被破坏时更新分数</font></font></h2> + +<p><font><font>每当球击中砖块时,我们将增加点数,更新</font></font><code>scoreText</code><font><font>显示当前得分。</font><font>这可以使用</font></font><code>setText()</code><font><font>方法 - 添加以下两行新</font></font><code>ballHitBrick()</code><font><font>功能:</font></font></p> + +<pre class="brush: js">function ballHitBrick(ball, brick) { + brick.kill(); + score += 10; + scoreText.setText('Points: '+score); +} +</pre> + +<p><font><font>这是现在 - 重新加载你的,</font></font><code>index.html</code><font><font>并检查得分更新每个砖击。</font></font></p> + +<h2 id="比较你的代码">比较你的代码</h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/n8o6rhrf/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p><font><font>我们现在有一个得分系统,但是如果你不能赢得,那么玩和保持分数是多少?</font><font>让我们看看我们如何能够增加胜利的状态,让我们</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Win_the_game"><font><font>赢得比赛</font></font></a><font><font>。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/Collision_detection", "Games/Workflows/2D_Breakout_game_Phaser/Win_the_game")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_phaser/win_the_game/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/win_the_game/index.html new file mode 100644 index 0000000000..acdcc8fba9 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_phaser/win_the_game/index.html @@ -0,0 +1,59 @@ +--- +title: Win the game +slug: Games/Tutorials/2D_breakout_game_Phaser/Win_the_game +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Phaser + - Tutorial + - winning +translation_of: Games/Tutorials/2D_breakout_game_Phaser/Win_the_game +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/The_score", "Games/Workflows/2D_Breakout_game_Phaser/Extra_lives")}}</p> + +<div class="summary"> +<p><font><font>这是</font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser"><font>Gamedev Phaser教程</font></a><font> 16 </font><font>的</font></font><strong><font><font>第12步</font></font></strong><font><font>。</font><font>您可以在</font><a href="https://github.com/end3r/Gamedev-Phaser-Content-Kit/blob/gh-pages/demos/lesson12.html"><font>Gamedev-Phaser-Content-Kit / demos / lesson12.html</font></a><font>完成本课程后找到源代码</font><font>。</font></font></p> +</div> + +<p>在我们的游戏中实现获胜是相当容易的:如果你碰巧摧毁所有的砖块,那么你赢了。</p> + +<h2 id="如何取胜?"><font><font>如何取胜?</font></font></h2> + +<p><font><font>将以下新代码添加到您的</font></font><code>ballHitBrick()</code><font><font>函数中:</font></font></p> + +<pre class="brush: 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++) { + if (bricks.children[i].alive == true) { + count_alive++; + } + } + if (count_alive == 0) { + alert('You won the game, congratulations!'); + location.reload(); + } +} +</pre> + +<p><font><font>我们循环使用组中的砖块</font></font><code>bricks.children</code><font><font>,检查每个砖块的</font></font><code>.alive() </code><font><font>方法</font><font>的活力</font><font>。</font><font>如果没有更多的砖块活着,那么我们会显示一个获胜的消息,一旦警报被关闭,重新启动游戏。</font></font></p> + +<h2 id="比较你的代码">比较你的代码</h2> + +<p>您可以在下面的现场演示中查看本课程的完成代码,并使用它来更好地了解它的工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/u8waa4Lx/1/","","400")}}</p> + +<h2 id="下一步">下一步</h2> + +<p><font><font>失败和获胜都是实施的,所以我们的游戏的核心游戏就完成了。</font><font>现在让我们添加一些额外的东西-我们会给玩家将3个</font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_Phaser/Extra_lives"><font><font>生活</font></font></a><font><font>的,而不是一个。</font></font></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_Phaser/The_score", "Games/Workflows/2D_Breakout_game_Phaser/Extra_lives")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.html new file mode 100644 index 0000000000..afbfbc1908 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/bounce_off_the_walls/index.html @@ -0,0 +1,99 @@ +--- +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 +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls")}}</p> + +<div class="summary"> +<p>本篇是 <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch">Gamedev Canvas tutorial</a> 10节教程中的第三节。如果你完成了本篇教程之后,你可以从 <a href="https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson03.html">Gamedev-Canvas-workshop/lesson3.html</a> 看到源码。</p> +</div> + +<p><span class="seoSummary">看到我们的球动起来很惊讶吧,但是它很快就从屏幕上消失了,当然我们是可以控制它的。我们会实现一些非常简单的碰撞检测(详细后面解释),使球在画布的四周反弹回来。</span></p> + +<h2 id="简单的碰撞">简单的碰撞</h2> + +<p>我们将检查球体是否与边缘接触,如果有接触我们将相应的改变它的运动方向。</p> + +<p>为了运算方便我们定义一个名为 ballRadius 的变量,来存储球的半径。向代码中添加一下内容:</p> + +<pre class="brush: js">var ballRadius = 10;</pre> + +<p>现在更新绘制球的 drawBall() 函数:</p> + +<pre class="brush: js">ctx.arc(x, y, ballRadius, 0, Math.PI*2);</pre> + +<h3 id="从顶部和底部弹起">从顶部和底部弹起</h3> + +<p>有四面墙壁可以让它反弹回来,我们先来看上面的那面墙。我们需要判断球运动的每一帧,球体是否与画布的顶部边缘接触。如果有接触,我们将会改变球体的运动方向,使它向相反的方向移动,并保证它在画布的可见范围之内。记住坐标系统的左上角,让我们开始并加以下代码:</p> + +<pre class="brush: js">if(y + dy < 0) { + dy = -dy; +}</pre> + +<p>如果球的纵坐标(y轴)值小于零,我们将在球体原有的运动方向上逆转。如果球体向上移动的速度是2像素/帧,现在就是向上移动速度是-2像素。这相当于此时向下移动的速度是2像素/帧。</p> + +<p>上面的代码将处理球与画布顶部边缘的反射,现在让我们思考一下底部边缘如何处理:</p> + +<pre class="brush: js">if(y + dy > canvas.height) { + dy = -dy; +}</pre> + +<p>如果球的y位置大于<code>canvas</code>的高度(记住,我们从左上角计算y值,所以顶部边缘从0开始,底部边缘在480像素),然后通过像以前那样反转y轴运动而离开底部边缘。</p> + +<p>我们可以将这两句冗长的代码合二为一:</p> + +<pre class="brush: js">if(y + dy > canvas.height || y + dy < 0) { + dy = -dy; +}</pre> + +<p>如果其中一个判断为 <code>true</code>, 则反转球的运动。</p> + +<h3 id="从左边和右边反弹">从左边和右边反弹</h3> + +<p>我们有顶部和底部的边缘,所以我们来考虑一下左边和右边的边缘。 实际上非常相似,你所要做的就是颠倒<code>x</code>而不是<code>y</code>:</p> + +<pre class="brush: js">if(x + dx > canvas.width || x + dx < 0) { + dx = -dx; +} + +if(y + dy > canvas.height || y + dy < 0) { + dy = -dy; +}</pre> + +<p>你应该把上面的代码块插入到draw()函数中,就在大括号之前。</p> + +<h3 id="球部分消失在墙上!">球部分消失在墙上!</h3> + +<p>测试你的代码,你会看到我们的球碰到任一边缘都会反弹!然而,我们还发现了一个问题,当球碰撞到边缘,反弹之前:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10432/ball-in-wall.png" style="display: block; height: 320px; margin: 0px auto; width: 480px;"></p> + +<p>这是因为我们正在计算墙和球的中心碰撞点,而我们应该围绕它的周长来做。 如果碰到墙壁,球应该会弹起来,而不是陷入墙壁一半时,所以让我们来调整一下我们的判断条件。 更新你之前添加的代码:</p> + +<pre class="brush: js">if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) { + dx = -dx; +} +if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) { + dy = -dy; +}</pre> + +<p>当球的中心到墙的边缘之间的距离与球的半径完全相同时,它将改变运动的方向。</p> + +<h2 id="比较你的代码">比较你的代码</h2> + +<p>让我们再次检查这个部分的代码与你之间有何差异:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/redj37dc/","","370")}}</p> + +<div class="note"> +<p><strong>练习</strong>: 尝试修改你的代码,在每次碰到墙壁时都要把球的颜色改成随机的颜色。</p> +</div> + +<h2 id="下一步">下一步</h2> + +<p>现在我们已经到了我们的球正在移动和留在游戏板上的阶段。 在第四章中,我们将看看如何实现一个可控制的paddle - 参见<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Paddle_and_keyboard_controls">paddle和键盘控制</a>。</p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.html new file mode 100644 index 0000000000..e91072bc68 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/build_the_brick_field/index.html @@ -0,0 +1,106 @@ +--- +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 +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection")}}</p> + +<div class="summary"> +<p>这是 <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch">Gamedev Canvas tutorial</a>教程10节的第6节。您可以在完成本课程后在这里<a href="https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson06.html">Gamedev-Canvas-workshop/lesson6.html</a>找到源代码。</p> +</div> + +<p><span class="seoSummary">在修改游戏机制后,我们可以输了 — 这样这游戏看起来终于像是一个游戏了,这真是太好了。但是,如果你总是让球与墙、板碰撞的话,很快就会感到无聊的。 好游戏需要的是让球消灭砖,这就是我们即将要做的!</span></p> + +<h2 id="设置砖变量">设置砖变量</h2> + +<p>本课题的总体目标是使用一个二维数组嵌套的循环,给出砖的几行代码。首先我们需要设置一些变量定义的砖,如宽度和高度信息, 行和列,等。在之前的变量声明处加入以下几行代码。</p> + +<pre class="brush: js">var brickRowCount = 3; +var brickColumnCount = 5; +var brickWidth = 75; +var brickHeight = 20; +var brickPadding = 10; +var brickOffsetTop = 30; +var brickOffsetLeft = 30;</pre> + +<p>在这里,我们定义了砖的行数和列,宽度和高度,砖块之间的填充物,这样它们就不会互相接触;有一个上、左偏移量,所以它们不会从画布的边缘开始绘制。 </p> + +<p>我们将在一个二维数组容纳我们所有的砖。它将包含砖列(c),砖行(R),每一个包含一个对象,其中包含x和y位置,让每个砖显示在屏幕上。在变量下面添加以下代码:</p> + +<pre class="brush: js">var bricks = []; +for(c=0; c<brickColumnCount; c++) { + bricks[c] = []; + for(r=0; r<brickRowCount; r++) { + bricks[c][r] = { x: 0, y: 0 }; + } +}</pre> + +<p>上面的代码将通过行和列的循环和创造新砖。注意,砖块对象稍后也将用于碰撞检测。</p> + +<h2 id="画砖的逻辑">画砖的逻辑</h2> + +<p>现在让我们创建一个函数来遍历数组中的所有砖块并在屏幕上绘制它们。. 代码如下:</p> + +<pre class="brush: js">function drawBricks() { + for(c=0; c<brickColumnCount; c++) { + for(r=0; r<brickRowCount; r++) { + bricks[c][r].x = 0; + bricks[c][r].y = 0; + ctx.beginPath(); + ctx.rect(0, 0, brickWidth, brickHeight); + ctx.fillStyle = "#0095DD"; + ctx.fill(); + ctx.closePath(); + } + } +}</pre> + +<p>再次,我们遍历的行和列,给每一块砖的位置设置<code>X</code>和<code>Y</code>,我们也画布上画砖,---<code>brickwidth</code> X <code>brickheight</code> 。问题是我们都画在一个地方坐标<code>(0,0)</code>处。我们需要做的是增加一些计算,计算每个循环迭代后的砖块的x和y位置:</p> + +<pre class="brush: js">var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft; +var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;</pre> + +<p>每个<code>brickX</code>位置是<code> brickWidth + brickPadding</code>,乘以列数<code>C</code>,再加上<code>brickOffsetLeft</code>;对于砖<code>brickY</code>的逻辑相同,除了名称不同,使用行数<code>R</code>,<code>brickHeight</code>,和<code>brickOffsetTop</code>。现在,每一块砖都可以放在正确的地方,排成一排,每一块砖之间都有填充物,从左上角和顶部的帆布边缘偏移。</p> + +<p>在设置<code>brickX</code>和<code>brickY</code>作为对应砖的坐标之后,形成了 <code>drawBricks()</code>函数的最终版本。将以下代码加在<code>drawPaddle()</code>函数后面:</p> + +<pre class="brush: js">function drawBricks() { + for(c=0; c<brickColumnCount; c++) { + for(r=0; r<brickRowCount; r++) { + var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft; + var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop; + bricks[c][r].x = brickX; + bricks[c][r].y = brickY; + ctx.beginPath(); + ctx.rect(brickX, brickY, brickWidth, brickHeight); + ctx.fillStyle = "#0095DD"; + ctx.fill(); + ctx.closePath(); + } + } +}</pre> + +<h2 id="到了展现真正画砖的时候了">到了展现真正画砖的时候了</h2> + +<p>最后一件事就是在<code>draw()</code>中调用<code>drawBricks()</code>, 位置最好在函数开始处,在清除画布和画球之间。直接将下面代码加在<code>drawBall()</code> 处:</p> + +<pre class="brush: js">drawBricks(); +</pre> + +<h2 id="比较你的代码"> 比较你的代码</h2> + +<p>这样,游戏变得更有趣了 :</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/kundan333/myd4vbwg/2/","","320")}}</p> + +<div class="note"> +<p>练习:尝试在行或列上改变砖块数量,或者它们的位置。</p> +</div> + +<h2 id="下一节">下一节</h2> + +<p>现在,我们有砖啦!但是球根本就没有和它们互动 —— 接下来的第七章我们将让球和砖产生碰撞: <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Collision_detection">碰撞检测</a>。</p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.html new file mode 100644 index 0000000000..fe3769ee79 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/collision_detection/index.html @@ -0,0 +1,126 @@ +--- +title: 撞击处理 +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Collision_detection +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Collision_detection +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win")}}</p> + +<div class="summary"> +<p>本篇为<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch">Gamedev Canvas tutorial</a>10节教程中的<strong>第7节。</strong>在你完成这篇课程之后,你可以在<a href="https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson07.html">Gamedev-Canvas-workshop/lesson7.html</a>.找到我们的源代码。</p> +</div> + +<p><span class="seoSummary">我们已经在屏幕上画出了砖块,但游戏仍然没有那么有趣,因为球通过它们。我们需要考虑增加碰撞检测,这样球就可以弹击砖块并打破它们。</span></p> + +<p>当然,这是我们的决定如何实现的,但是计算球是否触及矩形是很困难的,因为在画布中没有辅助函数。为了这个教程,我们将尽可能地做到这一点。我们将检查球的中心是否与任何给定的砖块碰撞。这不会每次都给出一个完美的结果,而且有很多更复杂的方法来进行碰撞检测,但是这对指导你的基本概念很有效。</p> + +<h2 id="撞击侦测函数"><strong>撞击侦测函数</strong></h2> + +<p>踢掉这一切,我们想创建一个碰撞检测功能,将循环通过所有砖块,并比较每一个砖的位置与球的坐标,因为每个帧绘制。为了更好地理解代码,我们将定义用于在碰撞检测的每个循环中存储砖块对象的B变量:</p> + +<pre class="brush: js">function collisionDetection() { + for(c=0; c<brickColumnCount; c++) { + for(r=0; r<brickRowCount; r++) { + var b = bricks[c][r]; + // calculations + } + } +}</pre> + +<p>如果球的中心在我们的一块砖块的坐标内,我们将改变球的方向。对于球的中心在砖块内,以下四个陈述都必须是正确的:</p> + +<ul> + <li>球的X位置大于砖的X位置。</li> + <li>球的X位置小于砖的X位置加上它的宽度。</li> + <li>球的Y位置大于砖的Y位置。</li> + <li>球的Y位置小于砖块的Y位置加上它的高度。</li> +</ul> + +<p>让我们在代码中写下:</p> + +<pre class="brush: js">function collisionDetection() { + for(c=0; c<brickColumnCount; c++) { + for(r=0; r<brickRowCount; r++) { + var b = bricks[c][r]; + if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) { + dy = -dy; + } + } + } +}</pre> + +<p>将上面的块添加到代码中,在 <code>keyUpHandler()</code> 函数下面。</p> + +<h2 id="让砖块在被撞击之后消失">让砖块在被撞击之后消失</h2> + +<p>上述代码将按需要工作,球改变其方向。问题是砖块留在原地。我们必须想出一个办法来摆脱那些我们已经用球打中的砖。我们可以通过添加一个额外的参数来指示我们是否想在屏幕上画每个砖块。在初始化砖块的代码的一部分中,让我们为每个砖块对象添加一个状态属性。更新代码的下面部分,如突出显示的行所示:</p> + +<pre class="brush: js; highlight:[5]">var bricks = []; +for(c=0; c<brickColumnCount; c++) { + bricks[c] = []; + for(r=0; r<brickRowCount; r++) { + bricks[c][r] = { x: 0, y: 0, status: 1 }; + } +}</pre> + +<p>接下来,我们将在绘制之前在 <code>drawBricks()</code> 中检查每个砖块的 <code>status</code>属性的值-如果 <code>status</code>是 <code>1</code>,然后画它,但是如果它是 <code>0</code>,那么它被球击中,我们不再希望它在屏幕上。更新您的 <code>drawBricks()</code> 函数如下:</p> + +<pre class="brush: js; highlight:[4,5,6,7,8,9,10,11,12,13,14]">function drawBricks() { + for(c=0; c<brickColumnCount; c++) { + for(r=0; r<brickRowCount; r++) { + if(bricks[c][r].status == 1) { + var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft; + var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop; + bricks[c][r].x = brickX; + bricks[c][r].y = brickY; + ctx.beginPath(); + ctx.rect(brickX, brickY, brickWidth, brickHeight); + ctx.fillStyle = "#0095DD"; + ctx.fill(); + ctx.closePath(); + } + } + } +}</pre> + +<h2 id="跟踪并更新在撞击侦测函数中的状态">跟踪并更新在撞击侦测函数中的状态</h2> + +<p>现在我们需要将砖块 <code>status</code> 属性包含在 <code>collisionDetection()</code>函数中:如果砖块是活动的(它的状态是 <code>1</code>),我们将检查碰撞是否发生;如果发生碰撞,我们将给定砖块的状态设置为 <code>0</code>,这样它就不会被绘制在屏幕上。更新您的 <code>collisionDetection()</code> 函数,如下所示:</p> + +<pre class="brush: js; highlight:[5,6,7,8,9,10]">function collisionDetection() { + for(c=0; c<brickColumnCount; c++) { + for(r=0; r<brickRowCount; r++) { + var b = bricks[c][r]; + if(b.status == 1) { + if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) { + dy = -dy; + b.status = 0; + } + } + } + } +}</pre> + +<h2 id="调用我们的撞击侦测函数">调用我们的撞击侦测函数</h2> + +<p>最后要做的是向 <code>collisionDetection()</code> 函数添加一个调用到我们的主要<code>draw()</code> 函数。将下面的行添加到 <code>draw()</code> 函数中,就在<code>drawPaddle()</code> 调用的下面:</p> + +<pre class="brush: js">collisionDetection(); +</pre> + +<h2 id="对比你的代码">对比你的代码</h2> + +<p>现在,在每一帧,每一块砖上都检查了球的碰撞检测。现在我们可以毁掉砖头:-!</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/kundan333/myd4vbwg/5/","","320")}}</p> + +<div class="note"> +<p>练习:当球碰到砖头时,改变球的颜色。</p> +</div> + +<h2 id="下一节">下一节</h2> + +<p>我们现在肯定到了,继续前进吧!在第八章中,我们将探讨如何跟踪得分和获胜。<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Track_the_score_and_win">Track the score and win</a>.</p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.html new file mode 100644 index 0000000000..59b0b70392 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/create_the_canvas_and_draw_on_it/index.html @@ -0,0 +1,114 @@ +--- +title: 创建、绘制画布 +slug: >- + Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it +translation_of: >- + Games/Tutorials/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it +--- +<div>{{GamesSidebar}}</div> + +<div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball")}}</p> + +<div class="summary"> +<p>本篇是 <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch">Gamedev Canvas tutorial</a> 10节教程中的第一节。如果你完成了本篇教程之后,你可以从 <a href="https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson01.html">Gamedev-Canvas-workshop/lesson1.html</a> 看到源码。</p> +</div> + +<p><span class="seoSummary">在我们开始编写游戏功能之前,我们可以通过HTML的canvas标签创建支撑游戏的基本结构。</span></p> + +<h2 id="页面部分">页面部分</h2> + +<p>HTML文档的结构是非常简单的,我们的游戏将完全呈现在这个HTML的canvas标签中。你可以选择一款你最喜欢的文本编辑器,创建一个HTML文件,保存到你理想的位置,名称为index.html。并添加以下代码:</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> +<head> + <meta charset="utf-8" /> + <title>Gamedev Canvas Workshop</title> + <style> + * { padding: 0; margin: 0; } + canvas { background: #eee; display: block; margin: 0 auto; } + </style> +</head> +<body> + +<canvas id="myCanvas" width="480" height="320"></canvas> + +<script> + // JavaScript code goes here +</script> + +</body> +</html> +</pre> + +<p>在 <span style="color: #990055;">head</span> 标签中我们需要定义字符集(charset),标题(title)和一些基本的样式。在 <span style="color: #990055;">body </span>标签中包含<span style="color: #990055;"> canvas </span>标签和 <span style="color: #990055;">javascript</span> 标签,我们将在 <span style="color: #990055;">javascript </span>标签中使用 JavaScript 代码来控制 <span style="color: #990055;">canvas</span> 标签中的内容展现。在 <span style="color: #990055;">canvas</span> 标签有一个名为 myCanvas 的 Id,根据这个属性我们可以很容易的获取到这个元素并设置他的宽为 480 像素,高为 320 像素。 之后我们会将所有的 JavaScript 代码全部写到 <span style="color: #990055;">javascript</span> 标签中(<script>...</script>)。</p> + +<h2 id="画布的基本属性">画布的基本属性</h2> + +<p>要想在 <span style="color: #990055;">canvas</span> 标签中呈现图像内容,我们必须在 JavaScript 代码中获取到这个元素。在 <span style="color: #990055;">javascript </span>标签中添加以下代码;</p> + +<pre class="brush: js">var canvas = document.getElementById("myCanvas"); +var ctx = canvas.getContext("2d");</pre> + +<p>在这里我们可以声明一个变量保存 <span style="color: #990055;">canvas</span> 标签,然后我们需要创建变量 ctx, 这个变量可用来存储 2d 的渲染上下文,我们实际上就用它在 <span style="color: #990055;">canvas</span> 标签上绘制内容。 </p> + +<p>让我们来看一个例子,打印在画布上的红色正方形。添加以下代码到你的 JavaScript 里,然后在浏览器中打开 index.html 来看看效果。</p> + +<pre class="brush: js">ctx.beginPath(); +ctx.rect(20, 40, 50, 50); +ctx.fillStyle = "#FF0000"; +ctx.fill(); +ctx.closePath();</pre> + +<p>把全部指令放到 <span style="color: #0077aa;">ctx.beginPath()</span> 方法 和 <span style="color: #0077aa;">ctx.closePath() </span>方法之间。我们使用 <span style="color: #0077aa;">ctx.rect()</span> 方法创建了一个矩形。这个方法的第一组参数(20,40)是确定这个矩形的左上角在画布上的坐标,第二组参数(50, 50)是指定矩形的宽度和高度。例子中矩形左上角的 x 坐标为20像素,y 坐标为40像素;宽和高各为50像素,这样画出一个完美的正方形。<span style="color: #0077aa;">ctx.fillStyle </span>属性是用于填充绘画的颜色,这里填充的颜色为红色。<span style="color: #0077aa;">ctx.fill()</span> 方法是填充路径的内容区域生成实心的图形。</p> + +<p>我们不局限于绘制矩形 — 下面这段代码会绘制出一个绿色的圆;尝试添加到 JavaScript 代码的底部,保存并刷新:</p> + +<pre><code>ctx.beginPath(); +ctx.arc(240, 160, 20, 0, Math.PI*2, false); +ctx.fillStyle = "green"; +ctx.fill(); +ctx.closePath();</code></pre> + +<p>正如你所见,我们再一次使用了 <span style="color: #0077aa;">ctx.beginPath()</span> 方法 和 <span style="color: #0077aa;">ctx.closePath() </span>方法;在这两个方法中间,最重要的部分是 <span style="color: #0077aa;">ctx.arc() </span>方法。它需要六个参数:</p> + +<ul> + <li><code>圆心的 x</code> 和 <code>y</code> 轴坐标</li> + <li>半径</li> + <li>起始角度,结束角度。以弧度计(弧的圆形的三点钟位置是 0 度)</li> + <li>规定应该逆时针还是顺时针绘图。false = 顺时针,true = 逆时针。(可选)</li> +</ul> + +<p><span style="color: #0077aa;">ctx.fillStyle</span> 属性的值看起来和之前不大一样。这是因为它与 CSS 一样,颜色可以指定为十六进制值也可以指定为 rgba() 函数,或者任何其他可用的颜色值函数。</p> + +<p>当然我们也可以不使用 <span style="color: #0077aa;">ctx.fill()</span> 函数来填充图形和颜色,用 <span style="color: #0077aa;">ctx.stroke() </span>函数来绘制定义图形的路径。试着将这段代码添加到您的JavaScript:</p> + +<pre class="brush: js">ctx.beginPath(); +ctx.rect(160, 10, 100, 40); +ctx.strokeStyle = "rgba(0, 0, 255, 0.5)"; +ctx.stroke(); +ctx.closePath();</pre> + +<p>上面的代码绘制出一个蓝色边框的空心矩形。由于 <span style="color: #0077aa;">rgba() </span> 函数的特性,边框为蓝色半透明的状态。</p> + +<h2 id="比对你的代码">比对你的代码</h2> + +<p>以上是第一节的全部代码,可以运行在JSFiddle(在线JS代码调试工具)上:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/x62h15e2/","","370")}}</p> + +<div class="note"> +<p>练习:尝试改变给定几何图形的大小和颜色。</p> +</div> + +<h2 id="下一节">下一节</h2> + +<p>现在我们已经创建了基本的HTML和关于画布的基本知识。我们继续第二节,如何让球在游戏中动起来 — <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Move_the_ball">让球动起来</a>。</p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball")}}</p> + +<p> + <audio style="display: none;"> </audio> +</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.html new file mode 100644 index 0000000000..5256e9b632 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/game_over/index.html @@ -0,0 +1,81 @@ +--- +title: 游戏结束 +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Game_over +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Game_over +--- +<div>{{GamesSidebar}}</div> + +<div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field")}}</p> + +<div class="summary"> +<p>这是 <a href="/en-US/docs/Games/Workflows/Breakout_game_from_scratch">Gamedev Canvas tutorial</a>教程的第五章。您可以在完成本课程后在这里<a href="https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson05.html">Gamedev-Canvas-workshop/lesson5.html</a>找到源代码。</p> +</div> + +<p><span class="seoSummary">看球从墙上反弹,并能够移动球盘是很有趣的。但除此之外,游戏什么都不做,也没有任何进展或最终目标。 从游戏的角度来看,我们需要一个game over。 失败的逻辑很简单。 如果你的球拍错过了球,并且球到达屏幕的底部边缘,那么游戏就结束了。</span></p> + +<h2 id="实现游戏失败">实现游戏失败</h2> + +<p>让我们在代码中实现,下面是第三章里的一段代码,让球从墙上反弹:</p> + +<pre class="brush: js notranslate">if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) { + dx = -dx; +} + +if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) { + dy = -dy; +}</pre> + +<p>我们不需要让球从四面墙上反弹,应该只允许三个 - 左,上,右。 击中底部墙将结束游戏。 我们将编辑第二个if代码块,这是一个if else块,当球碰撞到画布的底部边缘时,它会触发我们的“游戏结束”状态。 现在我们将保持简单,显示一条警告消息,并通过重新加载页面重新开始游戏。</p> + +<p>第一步,把您最开始使用的 <code>setInterval()</code> 函数</p> + +<pre class="brush: js notranslate">setInterval(draw, 10);</pre> + +<p>替换成:</p> + +<pre class="brush: js notranslate">var interval = setInterval(draw, 10);</pre> + +<p>然后将第二个if块替换为以下内容:</p> + +<pre class="brush: js notranslate">if(y + dy < ballRadius) { + dy = -dy; +} else if(y + dy > canvas.height-ballRadius) { + alert("GAME OVER"); + document.location.reload(); +}</pre> + +<h2 id="让球拍接住球">让球拍接住球</h2> + +<p>本课中最后要做的是在球和球拍之间创建一些碰撞检测,以便它可以反弹并返回到游戏区域。 最简单的方法是检查球的中心是否在球拍的左边和右边之间。 再次更新您修改的代码的最后一位(第二个if块),如下所示:</p> + +<pre class="brush: js notranslate">if(y + dy < ballRadius) { + dy = -dy; +} else if(y + dy > canvas.height-ballRadius) { + if(x > paddleX && x < paddleX + paddleWidth) { + dy = -dy; + } + else { + alert("GAME OVER"); + document.location.reload(); + } +}</pre> + +<p>如果球击中画布的底部边缘,我们需要检查它是否碰到球拍。 如果是的话,就像你所期望的那样反弹。 如果没有,那么游戏就像以前一样结束。</p> + +<h2 id="代码对比">代码对比</h2> + +<p>这里是完整例子,对比一下代码吧!</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/z4zy79fo/","","320")}}</p> + +<div class="note"> +<p><strong>练习</strong>: 当球碰到球拍时,让球移动得更快</p> +</div> + +<h2 id="下一步">下一步</h2> + +<p>到目前为止,我们的表现相当不错,游戏变得更有趣,并且现在你可以输了! 但它仍然缺少一些东西。 让我们继续前进到第六章 - <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Build_the_brick_field">建造砖块</a> - 并创造一些砖块来消灭它们。</p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/index.html new file mode 100644 index 0000000000..68a7f25df9 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/index.html @@ -0,0 +1,60 @@ +--- +title: 2D breakout game using pure JavaScript +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - NeedsTranslation + - TopicStub + - Tutorial +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{Next("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it")}}</p> + +<p class="summary">在这里我们将完全使用JavaScript语言基于HTML5的canvas标签,一步一步的绘制一个简单的MDN消除游戏。</p> + +<p>过程中的每一步都会有例子可供体验,让你更清晰的了解他的制作过程。你将学习到如何使用canvas标签的基本语法去实现简单游戏的渲染、动画、碰撞、控制胜负。</p> + +<p>为了更快速高效的学习本系列教程,你需要掌握 <a href="/en-US/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript</a> 的一些基础知识。学习完本教程之后你就可以创建自己的网页小游戏了。</p> + +<p><img alt="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." src="https://mdn.mozillademos.org/files/10383/mdn-breakout-gameplay.png" style="display: block; height: 320px; margin: 0px auto; width: 480px;"></p> + +<h2 id="教程详情">教程详情</h2> + +<p> </p> + +<p>全部教程 — <a href="http://breakout.enclavegames.com/lesson10.html">MDN 消除小游戏</a> 的各个版本我们正一起管理并托管到 <a href="https://github.com/end3r/Canvas-gamedev-workshop">GitHub</a> 上:</p> + +<ol> + <li><a href="https://developer.mozilla.org/zh-CN/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it">创建、绘制画布</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Move_the_ball">让球动起来</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls">反弹的墙</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Paddle_and_keyboard_controls">键盘操作</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over">游戏结束</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Build_the_brick_field">创建砖块</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection">撞击处理</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win">统计得分、获得胜利</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls">鼠标控制</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up">完成</a></li> +</ol> + +<p>对于实现一个网页游戏而言,最好的方式是从纯 JavaScirpt 着手,那样可以让我们建立更坚实的基础。之后你可以在你的项目中选择你喜欢的框架。框架也只是用JavaScript语言实现的工具;如果你想要在项目中使用框架,你必须先了解语言本身。框架可以帮你提高开发效率并生成一些基础的内容;但是如果没有达到你的预期,你只能慢慢调试或者使用原生JavaScript去实现解决方案。 </p> + +<div class="note"> +<p><span style="font-size: 14px;"><strong>说明</strong></span>: 如果你对使用第三方游戏资源库开发2d网页游戏感兴趣,可以参考本系列教程的 <a href="/en-US/docs/Games/Workflows/2D_breakout_game_Phaser">2D breakout game using Phaser</a>.</p> +</div> + +<div class="note"> +<p><span style="font-size: 14px;"><strong>说明</strong></span>: 本系列教程可以用作游戏开发工作室的素材资源。如果你想探讨普通的游戏开发,你可以利用<a href="https://github.com/end3r/Gamedev-Canvas-Content-Kit">Gamedev Canvas Content Kit</a>以及本教程的内容。</p> +</div> + +<h2 id="下一步">下一步</h2> + +<p>好,让我们开始吧。第一步 — <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it">创建、绘制画布</a></p> + +<p>{{Next("Games/Workflows/2D_Breakout_game_pure_JavaScript/Create_the_Canvas_and_draw_on_it")}} </p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.html new file mode 100644 index 0000000000..e035a28838 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/move_the_ball/index.html @@ -0,0 +1,143 @@ +--- +title: 让球动起来 +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball +tags: + - 2D + - Beginner + - Canvas + - Games + - JavaScript + - Loop + - Tutorial + - movement +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Move_the_ball +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<div>{{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")}}</div> + +<div class="summary"> +<p>本篇是 <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch">Gamedev Canvas tutorial</a> 10节教程中的第二节。如果你完成了本篇教程之后,你可以从 <a href="https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson02.html">Gamedev-Canvas-workshop/lesson2.html</a> 看到源码。</p> +</div> + +<p><span class="seoSummary">从上一节中你已经知道如何去绘制一个球。现在让我们使它动起来。从技术上讲,我们将在画布上绘制一个球,之后让它消失,然后在一个稍微不用的位置上再绘制一个一样的球。就想电影里的每一帧动起来的感觉。</span></p> + +<p>我们需要定义一个绘图函数,每次使用一组不同的变量改变球体的位置;循环调用以保持画布上每一帧不断更新。你可以使用JavaScript时间函数 {{domxref("WindowTimers.setInterval()", "setInterval()")}} 或者 {{domxref("window.requestAnimationFrame()")}}。 </p> + +<p>在你的HTML文件只保留前两行,删除其他所有的JavaScript代码并在 draw() 函数中添加以下内容保证每10毫秒执行一次 draw() 函数:</p> + +<pre class="brush: js">function draw() { + // drawing code +} +setInterval(draw, 10);</pre> + +<p>得益于 <code>setInterval</code> 的无限性,使得 <code>draw()</code> 函数将每10毫秒就会被调用,除非我们停止它。现在,我们来绘制小球吧,在 <code>draw()</code> 函数中添加以下内容:</p> + +<pre class="brush: js">ctx.beginPath(); +ctx.arc(50, 50, 10, 0, Math.PI*2); +ctx.fillStyle = "#0095DD"; +ctx.fill(); +ctx.closePath(); +</pre> + +<p>现在,尝试更新你的代码,球会在每一帧画面被绘制</p> + +<h2 id="让球动起来">让球动起来</h2> + +<p>你不会注意到球正在不停地被重新刷,因为它没有移动。让我们改变这种情况。首先,我们不再使用固定位置(50,50),而是用x和y的变量来定义画布底部的起始点,然后使用这些变量来定义圆被绘制的位置。</p> + +<p><font><font>首先,在</font></font><code>draw()</code><font><font>函数</font><font>上方添加以下两行</font><font>,以定义</font></font><code>x</code><font><font>和</font></font><code>y</code><font><font>:</font></font></p> + +<pre class="brush: js">var x = canvas.width/2; +var y = canvas.height-30; +</pre> + +<p><font><font>接下来更新</font></font> <code>draw()</code> <font><font>函数,在 </font></font><code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc" title="Canvas 2D API的CanvasRenderingContext2D.arc()方法将以弧度为中心的(x,y)位置的弧线添加一个圆弧,半径r从startAngle开始,并以endAngle的顺时针方向(默认为顺时针方向)终止, 。">arc()</a> </code><font><font>方法中使用 <code>x</code> 和 <code>y</code> 变量,如下面高亮行所示:</font></font></p> + +<pre class="brush: js; highlight:[3]">function draw() { + ctx.beginPath(); + ctx.arc(x, y, 10, 0, Math.PI*2); + ctx.fillStyle = "#0095DD"; + ctx.fill(); + ctx.closePath(); +} +</pre> + +<p>现在到了最重要的部分:我们想要在每一帧都被绘制出来之后,给 <code>x</code> 和 <code>y</code> 添加一个较小的值,让它看起来像是在移动。让我们将这些值定义为 <code>dx</code> 和 <code>dy</code>,并将它们的值分别设为 <code>2</code> 和 <code>-2</code>。在你的 x 和 y 变量声明下方添加以下内容:</p> + +<pre class="brush: js">var dx = 2; +var dy = -2; +</pre> + +<p>最后要做的是在每一帧上更新 <code>x</code> 和 <code>y</code>,在每一次更新中,把球画在新的位置上。将下面的两条新线添加到你的 <code>draw()</code> 函数:</p> + +<pre class="brush: js; highlight:[7,8]">function draw() { + ctx.beginPath(); + ctx.arc(x, y, 10, 0, Math.PI*2); + ctx.fillStyle = "#0095DD"; + ctx.fill(); + ctx.closePath(); + x += dx; + y += dy; +}</pre> + +<p>再次保存代码,并在浏览器中尝试。很好,尽管看起来球在后面留下了痕迹:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10430/ball-trail.png" style="display: block; height: 320px; margin: 0px auto; width: 480px;"></p> + +<h2 id="在每一帧更新之前清空画布">在每一帧更新之前清空画布</h2> + +<p>球移动时留下了轨迹,因为我们在每一帧上都画了一个新的圆,而没有去掉之前的一个圆。不要担心,因为有一个方法来清空画布的内容:<code><a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clearRect" title="Canvas 2D API的CanvasRenderingContext2D.clearRect()方法将由起点(x,y)和大小(宽,高)定义的矩形中的所有像素设置为透明黑色,擦除任何先前绘制的内容。">clearRect()</a></code>。该方法有四个参数:矩形左上角的 <code>x</code> 和 <code>y</code> 坐标,以及矩形的右下角的 <code>x</code> 和 <code>y</code> 坐标。这个矩形覆盖的整个区域里,之前所画的任何内容将被清除。</p> + +<p>将下列高亮显示行添加到 <code>draw()</code> 函数:</p> + +<pre class="brush: js; highlight:[2]">function draw() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.beginPath(); + ctx.arc(x, y, 10, 0, Math.PI*2); + ctx.fillStyle = "#0095DD"; + ctx.fill(); + ctx.closePath(); + x += dx; + y += dy; +} +</pre> + +<p>保存您的代码并再次尝试,这次你将看到球移动后没有留下轨迹。每隔10毫秒,画布就会被清除,蓝色的圆圈(我们的球)将被绘制在一个给定的位置上,而 <code>x</code> 和 <code>y</code> 的值将在下一个帧被更新。</p> + +<h2 id="保持代码整洁">保持代码整洁</h2> + +<p>在接下来的几篇文章中,我们将在 <code>draw()</code> 函数中添加越来越多的命令,因此尽可能保持简单和整洁是很好的。让我们从把绘制球的代码移至一个单独的函数。</p> + +<p>用以下两个函数替换现有的 <code>draw()</code> 函数:</p> + +<pre class="brush: js">function drawBall() { + ctx.beginPath(); + ctx.arc(x, y, 10, 0, Math.PI*2); + ctx.fillStyle = "#0095DD"; + ctx.fill(); + ctx.closePath(); +} + +function draw() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + drawBall(); + x += dx; + y += dy; +}</pre> + +<h2 id="比较你的代码">比较你的代码</h2> + +<p>您可以在下面的实时演示中查看本文的代码,并使用它来更好地了解其工作原理:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/3x5foxb1/","","415")}}</p> + +<div class="summary"> +<p>练习:尝试改变移动球的速度,或者移动球的方向。</p> +</div> + +<h2 id="下一步"><font><font>下一步</font></font></h2> + +<p><font><font>我们已经画了我们的球,并将其移动,但它仍然消失在画布的边缘。</font><font>在第三章中,我们将探讨如何使其 </font></font><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Bounce_off_the_walls">从墙壁上反弹</a>.</p> + +<p>{{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")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.html new file mode 100644 index 0000000000..6cd024799d --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/paddle_and_keyboard_controls/index.html @@ -0,0 +1,122 @@ +--- +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 +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over")}}</p> + +<div class="summary"> +<p>这是<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch">Gamedev Canvas tutorial</a>中的第四章。完成本课程后,你可以在<a href="https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson04.html">Gamedev-Canvas-workshop/lesson4.html</a>找到源码.</p> +</div> + +<p>你可以看到球自由的、无限次的在墙壁上反弹,但是没有和我们发生任何交互。如果我们没有对它的控制操作,这仍然不是一个游戏。下面,我们新增一些用户操作:一个可以控制球的球板。</p> + +<h2 id="定义一个球板去接球">定义一个球板去接球</h2> + +<p>我们需要添加一个球板去接球:为此需要先定义一些变量。在你的代码的顶部的其它变量下方添加下列代码:</p> + +<pre class="brush: js">var paddleHeight = 10; +var paddleWidth = 75; +var paddleX = (canvas.width-paddleWidth)/2;</pre> + +<p>然后定义球拍的长和宽,以及为了之后的处理同时定义x轴上的初始位置。新建一个方法来在页面上描绘球板。把下列代码添加到你的<code>drawBall()方法里去</code>:</p> + +<pre class="brush: js">function drawPaddle() { + ctx.beginPath(); + ctx.rect(paddleX, canvas.height-paddleHeight, paddleWidth, paddleHeight); + ctx.fillStyle = "#0095DD"; + ctx.fill(); + ctx.closePath(); +}</pre> + +<h2 id="允许用户控制球板">允许用户控制球板</h2> + +<p>我们可以如愿的描绘出球板,也需让它听从用户的控制。是时候实现用键盘控制它了。我们需要:</p> + +<ul> + <li>两个变量以保存左右方向键是否被按下的信息。</li> + <li>两个事件监控器来捕捉按键的按下和松开动作。我们需要运行一些代码以在按键被按下时可以控制球拍的移动</li> + <li>两个用于处理按键被按下或松开后的事件处理方法</li> + <li>实现左右移动球拍</li> +</ul> + +<p>按键可以使用boolean变量来初始定义。在你的其它变量附近添加下列代码:</p> + +<pre class="brush: js">var rightPressed = false; +var leftPressed = false;</pre> + +<p>这两个变量的默认值都是false,因为在开始时按键没有被按下。为了监听按键的按下动作,我们需要添加两个监听器。把下列代码添加到底部的<code>setInterval()的上一列去:</code></p> + +<pre class="brush: js">document.addEventListener("keydown", keyDownHandler, false); +document.addEventListener("keyup", keyUpHandler, false);</pre> + +<p>当你按下任何键盘上的按键,按下事件被激活时<code>keyDownHandler()方法会被调用。对于松开时的处理也是类似的:当松开按键时keyUpHandler()方法会被调用。把下列代码添加到addEventListener()下方</code>:</p> + +<pre class="brush: js">function keyDownHandler(e) { + if(e.keyCode == 39) { + rightPressed = true; + } + else if(e.keyCode == 37) { + leftPressed = true; + } +} + +function keyUpHandler(e) { + if(e.keyCode == 39) { + rightPressed = false; + } + else if(e.keyCode == 37) { + leftPressed = false; + } +}</pre> + +<p>当按下一个按键,这个信息会被储存在一个变量中。每种情况下的相关变量都设置为<code>true</code>。 当松开按键时,对应变量被设置回<code>false</code>。</p> + +<p>两个函数都以一个事件作为参数,由<code>e</code>(event)变量表示。 从这里你可以得到有用的信息:keyCode属性是被按下的键的信息。 例如,keyCode为37是左箭头键,而39是右箭头键。 如果按下左键,那么leftPressed变量设置为true,当松开时,leftPressed变量设置为false。右键同理。</p> + +<h3 id="球拍移动逻辑">球拍移动逻辑</h3> + +<p>我们现在有用于存储按键,事件监听器和相关功能的信息的变量。 现在我们将看到实际的代码来使用这些变量,并在屏幕上移动球拍。 在draw()函数内部,我们将检查每一帧被渲染的同时是否按下左或右键。 我们的代码如下:</p> + +<pre class="brush: js">if(rightPressed) { + paddleX += 7; +} +else if(leftPressed) { + paddleX -= 7; +}</pre> + +<p>如果按一下左键,球拍将向左移动7个像素,如果按一下右键,球拍将向右移动7个像素。 目前这个功能可以正常工作,但是如果我们按任意一个键的时间太长,球拍就会从画布的边缘消失。 我们可以通过改变代码来改善这种情况,并且只能在画布的边界内移动球拍,如下所示:</p> + +<pre class="brush: js">if(rightPressed && paddleX < canvas.width-paddleWidth) { + paddleX += 7; +} +else if(leftPressed && paddleX > 0) { + paddleX -= 7; +}</pre> + +<p>我们使用在<code>Canvas</code>左侧的0和右侧的<code>canvas.width-paddleWidth</code>之间的<code>paddleX</code>位置移动,这会让球拍按预期的要求移动。</p> + +<p>将上面的代码块添加到底部的<code>draw()</code>函数中,在右大括号的上方。</p> + +<p>现在唯一要做的就是在<code>draw()</code>函数内调用<code>drawPaddle()</code>函数,将其实际渲染在屏幕上。 在<code>draw()</code>函数内添加下面一行,就在调用<code>drawBall()</code>的那一行的下面:</p> + +<pre class="brush: js">drawPaddle(); +</pre> + +<h2 id="比较你的代码">比较你的代码</h2> + +<p>以下是我们的示例代码,以便与您进行比较:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/end3r/tgn3zscj/","","320")}}</p> + +<div class="note"> +<p><strong>练习</strong>: 让球拍变快变慢,或者改变它的大小。</p> +</div> + +<h2 id="下一步">下一步</h2> + +<p>现在我们有一些类似于游戏的东西。 唯一的麻烦就是无论如何你都可以继续用球拍击球。 这一切都将在第五章中改变,<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Game_over">游戏结束</a>时,我们会为游戏添加一个最后的状态。</p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Bounce_off_the_walls", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Game_over")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.html new file mode 100644 index 0000000000..fc39385f02 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/track_the_score_and_win/index.html @@ -0,0 +1,92 @@ +--- +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 +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}}</p> + +<div class="summary"> +<p>本篇为<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch">Gamedev Canvas tutorial</a>10节教程中的<strong>第8节。</strong>在你完成这篇课程之后,你可以在<a href="https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson08.html">Gamedev-Canvas-workshop/lesson8.html</a>找到我们的源代码。</p> +</div> + +<p><span class="seoSummary">破坏砖块真的很酷,但更酷的是,游戏可以给每个用户击破的砖块奖励分数,并保持总分。</span></p> + +<h2 id="计算分数">计算分数</h2> + +<p>如果你能在整个游戏中看到你的分数,最终你会给你的朋友留下深刻印象。你需要一个变量来记录分数。在变量的其余部分之后,将下面的内容添加到JavaScript中:</p> + +<pre class="brush: js">var score = 0;</pre> + +<p>您还需要一个 <code>drawScore()</code> 函数来创建和更新分数显示。在 <code>collisionDetection()</code> 函数之后添加以下内容:</p> + +<pre class="brush: js">function drawScore() { + ctx.font = "16px Arial"; + ctx.fillStyle = "#0095DD"; + ctx.fillText("Score: "+score, 8, 20); +}</pre> + +<p>在画布上绘制文本类似于绘制形状。字体定义看起来与CSS中的字体定义完全一样——可以在{{domxref("CanvasRenderingContext2D.font","font()")}} 方法中设置大小和字体类型。然后使用{{domxref("CanvasRenderingContext2D.fillStyle()","fillStyle()")}} 来设置字体的颜色,{{domxref("CanvasRenderingContext2D.fillText","fillText()")}} 来设置将放置在画布上的实际文本,和其放置位置。第一个参数是文本本身——上面的代码显示当前点的数量——最后两个参数是文本将放置在画布上的坐标。</p> + +<p>若要在每次击中砖块时评分,则在 <code>collisionDetection()</code>中添加计分规则,以在每次检测到碰撞时增加得分变量的值。将下面突出显示的行添加到代码中:</p> + +<pre class="brush: js; highlight:[9]">function collisionDetection() { + for(var c=0; c<brickColumnCount; c++) { + for(var r=0; r<brickRowCount; r++) { + var b = bricks[c][r]; + if(b.status == 1) { + if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) { + dy = -dy; + b.status = 0; + score++; + } + } + } + } +}</pre> + +<p>从 <code>draw()</code> 函数调用 <code>drawScore()</code> ,使每一个新帧的分数都保持最新,在 <code>draw()</code>中添加下面的行,在 <code>drawPaddle()</code> 下面调用:</p> + +<pre class="brush: js">drawScore();</pre> + +<h2 id="当所有砖块被破坏时显示获胜消息">当所有砖块被破坏时显示获胜消息</h2> + +<p>收集这些点很有效,但是你不会永远添加它们-当所有的砖头都被破坏的时候呢?毕竟这是游戏的主要目的,所以如果收集到所有可用的点,你应该显示一个获胜的消息。将下面突出显示的部分添加到 <code>collisionDetection()</code> 函数中:</p> + +<pre class="brush: js; highlight:[10,11,12,13]">function collisionDetection() { + for(var c=0; c<brickColumnCount; c++) { + for(var r=0; r<brickRowCount; r++) { + var b = bricks[c][r]; + if(b.status == 1) { + if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) { + dy = -dy; + b.status = 0; + score++; + if(score == brickRowCount*brickColumnCount) { + alert("YOU WIN, CONGRATULATIONS!"); + document.location.reload(); + } + } + } + } + } +}</pre> + +<p>谢谢你做的这些,你的用户可以真正赢得游戏时,他们也摧毁了所有的砖块。当用户来到游戏还有一点非常重要,用户一旦点击了警告按钮, <code>document.location.reload()</code>函数将重新加载页面并重新启动游戏。</p> + +<h2 id="比较你的代码">比较你的代码</h2> + +<p>最新的代码是这样(和工程),如果你想比较和对比它与你写的:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/yumetodo/2m74vr9r/1/","","395")}}</p> + +<div class="note"> +<p><strong>练习:在每一个砖头击破后添加更多的分数,打印出收集到的点数在游戏结束警告框中。</strong></p> +</div> + +<h2 id="下一节">下一节</h2> + +<p>游戏到这一步看起来相当不错。在下一课中,您将通过添加鼠标控件来扩大游戏的吸引力:<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Mouse_controls">Mouse controls</a>.。</p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Collision_detection", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/收尾工作/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/收尾工作/index.html new file mode 100644 index 0000000000..baa5a514fc --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/收尾工作/index.html @@ -0,0 +1,113 @@ +--- +title: 收尾工作 +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/收尾工作 +tags: + - Canvas + - JavaScript + - requestAnimationFrame + - 入门 + - 教程 + - 游戏 + - 生命 +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Finishing_up +--- +<div>{{GamesSidebar}}</div> + +<div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{Previous("Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}}</p> + +<div class="summary"> +<p>本篇为 <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch">Gamedev Canvas tutorial </a>10节教程中的<strong>第10节也是最后一节。</strong>完成这篇课程后,你可以在 <a href="https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson10.html">Gamedev-Canvas-workshop/lesson10.html</a> 找到我们的源代码。</p> +</div> + +<p><span class="seoSummary">不管我们做什么游戏,它总是存在优化的空间。例如,我们可以为玩家多提供几条命,让他们能在发生一两次失误的情况下顺利完成游戏。或者,我们也可以在渲染代码上下工夫。</span></p> + +<h2 id="加入生命机制">加入生命机制</h2> + +<p>在游戏中实现生命机制的思路很直接。让我们先新增一个变量,用来存储其生命值。把下面这行代码和我们声明其它变量的代码放在一起:</p> + +<pre class="brush: js">var lives = 3;</pre> + +<p>在 canvas 上绘制生命值计数的做法几乎和绘制分数一样——把下面的函数添加到<code>drawScore()</code> 函数后面:</p> + +<pre class="brush: js">function drawLives() { + ctx.font = "16px Arial"; + ctx.fillStyle = "#0095DD"; + ctx.fillText("Lives: "+lives, canvas.width-65, 20); +}</pre> + +<p>当玩家失误时,我们不立即结束游戏,而是减少生命计数,直到为零。在玩家用掉一条命后,我们也可以重置小球和球板位置。那么,在函数 <code>draw()</code> 中将下面三行:</p> + +<pre class="brush: js">alert("GAME OVER"); +document.location.reload(); +clearInterval(interval); // Needed for Chrome to end game +</pre> + + + + + +<p>替换为下面的代码,注意到我们加入了一点点逻辑控制:</p> + +<pre class="brush: js">lives--; +if(!lives) { + alert("GAME OVER"); + document.location.reload(); + clearInterval(interval); // Needed for Chrome to end game +} +else { + x = canvas.width/2; + y = canvas.height-30; + dx = 2; + dy = -2; + paddleX = (canvas.width-paddleWidth)/2; +}</pre> + +<p>现在,当小球碰到屏幕底边时,我们让变量<code>lives</code> 的值减一。如果生命用尽,游戏就宣告结束;否则就重置小球与球板的位置,以及小球的速度。</p> + +<h3 id="渲染生命值">渲染生命值</h3> + +<p>现在只需在 <code>draw()</code> 函数内调用<code>drawLives()</code> 即可。让我们把它加到<code>drawScore()</code> 的下一行:</p> + +<pre class="brush: js">drawLives(); +</pre> + +<h2 id="用_requestAnimationFrame_优化渲染">用 requestAnimationFrame() 优化渲染</h2> + +<p>现在让我们处理一些与游戏机制无关,但与画面渲染相关的东西。和我们目前使用{{domxref("windowTimers.setInterval()", "setInterval()")}} 实现的固定帧率渲染相比,{{domxref("window.requestAnimationFrame", "requestAnimationFrame")}} 能让浏览器更好地渲染画面。让我们把下面这行代码:</p> + +<pre class="brush: js">var interval = setInterval(draw, 10);</pre> + +<p>替换为:</p> + +<pre class="brush: js">draw();</pre> + +<p>再把代码中的每一处</p> + +<pre class="brush: js">clearInterval(interval); // Needed for Chrome to end game +</pre> + +<p>删除。然后,在 <code>draw()</code> 函数的最下方(右花括号之前)加入下面这行代码。 它的作用是使 <code>draw()</code> 函数递归调用自身:</p> + +<pre class="brush: js">requestAnimationFrame(draw);</pre> + +<p>现在 <code>draw()</code> 函数在 <code>requestAnimationFrame()</code> 的循环中被反复调用,之先前做法最大的不同是,我们将帧率的控制权交给浏览器,而不是固定的 10 毫秒。浏览器会在适当的时机同步帧率,并且只在必要的时候才刷新渲染的图形。这使得我们的动画比之前的 <code>setInterval()</code> 方法更加流畅且高效.</p> + +<h2 id="比较你的代码">比较你的代码</h2> + +<p>我们的游戏的最终版本已经完成!以上。</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/raymondjplante/dfh2tpu1/","","395")}}</p> + +<div class="note"> +<p><strong>练习:</strong>试着改变生命的数目和球从球板上反弹的角度。</p> +</div> + +<h2 id="游戏结束——暂时看来!">游戏结束——暂时看来!</h2> + +<p>祝贺你——你完成了本教程的所有小节!现在,你应该已经掌握 canvas 操纵的基础和 2D 游戏背后的逻辑了。是时候去学习一些框架,继续你的游戏开发之旅了!你可以看看本系列的姊妹篇:<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/2D_breakout_game_Phaser">用 Phaser 制作 2D 打砖块游戏</a> 或者 <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/HTML5_Gamedev_Phaser_Device_Orientation">Cyber Orb built in Phaser</a> 。或者,你也可以在 <a href="https://developer.mozilla.org/en/docs/Games">MDN 游戏区</a> 中获得灵感和更多知识。</p> + +<p>你也可以回到<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch">本教程的目录页</a>。祝编程愉快!</p> + +<p>{{Previous("Games/Workflows/2D_Breakout_game_pure_JavaScript/Mouse_controls")}}</p> diff --git a/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/鼠标控制/index.html b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/鼠标控制/index.html new file mode 100644 index 0000000000..cb90cb8773 --- /dev/null +++ b/files/zh-cn/games/tutorials/2d_breakout_game_pure_javascript/鼠标控制/index.html @@ -0,0 +1,61 @@ +--- +title: 鼠标控制 +slug: Games/Tutorials/2D_Breakout_game_pure_JavaScript/鼠标控制 +tags: + - Canvas + - JavaScript + - 入门 + - 操作控制 + - 教程 + - 游戏 + - 鼠标 +translation_of: Games/Tutorials/2D_Breakout_game_pure_JavaScript/Mouse_controls +--- +<div>{{GamesSidebar}}</div> + +<div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up")}}</p> + +<div class="summary"> +<p>本篇为 <a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch">Gamedev Canvas tutorial</a> 10节教程中的<strong>第9节</strong>。在你完成这篇课程之后,你可以在 <a href="https://github.com/end3r/Gamedev-Canvas-workshop/blob/gh-pages/lesson09.html">Gamedev-Canvas-workshop/lesson9.html</a> 找到我们的源代码。</p> +</div> + +<p><span class="seoSummary">这个游戏实际已经完成,现在让我们着手去润色。我们已经添加过键盘控制,而加入鼠标控制也同样简单。</span></p> + +<h2 id="监听鼠标移动">监听鼠标移动</h2> + +<p>监听鼠标移动甚至比监听按键更简单:只需监听 {{event("mousemove")}} 这个事件即可。把下面这行代码和其它事件监听代码放在一起,在 <code>keyup event</code> 的下一行:</p> + +<pre class="brush: js">document.addEventListener("mousemove", mouseMoveHandler, false);</pre> + +<h2 id="将球板移动绑定到鼠标移动">将球板移动绑定到鼠标移动</h2> + +<p>我们可以根据鼠标光标位置来更新球板位置——下面这个函数正是做这件事的。把这个函数加到你的代码中,接在你刚刚加入的那行后面:</p> + +<pre class="brush: js">function mouseMoveHandler(e) { + var relativeX = e.clientX - canvas.offsetLeft; + if(relativeX > 0 && relativeX < canvas.width) { + paddleX = relativeX - paddleWidth/2; + } +}</pre> + +<p>在这个函数中,我们首先计算 <code>relativeX</code> 的值,它等于鼠标在视窗中的水平位置 (<code>e.clientX</code>) 减去 canvas 元素左边框到视窗左边框的距离 (<code>canvas.offsetLeft</code>) —— 这就得到了 canvas 元素左边框到鼠标的距离。若这个值大于零,且小于 canvas 的宽度,说明鼠标指针落在 canvas 边界内,这时就把 <code>paddleX</code> (等于球板左边缘的坐标)设为 <code>relativeX</code> 减速去球板宽度的一半。这样就确保位移是相对于球板中心进行的。</p> + +<p>现在球板将跟随鼠标指针。不过由于我们将球板移动限制在 canvas 大小范围内,它不会从两边完全消失。</p> + +<h2 id="比较你的代码">比较你的代码</h2> + +<p>以下是我们的示例代码,以便与您进行比较:</p> + +<p>{{JSFiddleEmbed("https://jsfiddle.net/raymondjplante/vt7y5hcp/","","395")}}</p> + +<div class="summary"> +<p>练习:调整球板移动的范围,使得整个球板总是可见,而不是在移动到边缘时被遮住一半。</p> +</div> + +<h2 id="下一步">下一步</h2> + +<p>现在我们已经拥有一个完整的游戏。我们的系列教程将以一些细节上的调整作为<a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/Breakout_game_from_scratch/Finishing_up">结束。</a></p> + +<p>{{PreviousNext("Games/Workflows/2D_Breakout_game_pure_JavaScript/Track_the_score_and_win", "Games/Workflows/2D_Breakout_game_pure_JavaScript/Finishing_up")}}</p> diff --git a/files/zh-cn/games/tutorials/html5_gamedev_phaser_device_orientation/index.html b/files/zh-cn/games/tutorials/html5_gamedev_phaser_device_orientation/index.html new file mode 100644 index 0000000000..e5af242f12 --- /dev/null +++ b/files/zh-cn/games/tutorials/html5_gamedev_phaser_device_orientation/index.html @@ -0,0 +1,449 @@ +--- +title: 2D maze game with device orientation +slug: Games/Tutorials/HTML5_Gamedev_Phaser_Device_Orientation +translation_of: Games/Tutorials/HTML5_Gamedev_Phaser_Device_Orientation +--- +<div>{{GamesSidebar}}</div> + +<div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<div class="summary"> +<p>在本教程中,我们将介绍构建 HTML5 移动游戏的过程。 本游戏使用 <a href="https://developer.mozilla.org/en-US/Apps/Build/gather_and_modify_data/responding_to_device_orientation_changes">Device Orientation</a> 和 <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/API/Vibration">Vibration </a><strong>APIs</strong> 来增强游戏玩法,并使用 <a class="external external-icon" href="http://phaser.io/">Phaser</a> 框架构建。 为了充分理解本教程建议您先学习基础的JavaScript 知识。</p> +</div> + +<h2 id="Example_game">Example game</h2> + +<p>在本教程结束时,您将有一个功能齐全的游戏demo:<a href="http://orb.enclavegames.com/">Cyber Orb </a>。如下所示:</p> + +<p><img alt="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." src="https://mdn.mozillademos.org/files/10297/cyber-orb.png" style="display: block; height: 450px; margin: 0px auto; width: 300px;"></p> + +<h2 id="Phaser_framework">Phaser framework</h2> + +<p><a href="http://phaser.io/">Phaser</a> 是构建桌面和移动 HTML5 游戏的框架。它非常新,但由于热情的社区参与开发过程它同时也是快速增长的。您能够在<a href="https://github.com/photonstorm/phaser"> GitHub </a>查看它的开放源代码,阅读<a href="http://docs.phaser.io/"> 在线文档</a> 并浏览大量 <a href="http://examples.phaser.io/">示例 </a>。Phaser 框架为您提供了一组工具,这些工具将加快开发速度,并帮助处理完成游戏所需的一般任务,因此您可以专注于游戏创意本身。</p> + +<h2 id="Starting_with_the_project">Starting with the project</h2> + +<p>您能够在GitHub看到它的源代码 <a href="https://github.com/EnclaveGames/Cyber-Orb">Cyber Orb</a>。文件夹结构非常简单:起点是 <code>index.html</code>。 我们在该文件中初始化框架并设置 html 元素 {{htmlelement("canvas")}} 以呈现游戏。</p> + +<p><img alt="Screenshot of the GitHub repository with the Cyber Orb game code, listing the folders and the files in the main structure." src="https://mdn.mozillademos.org/files/10357/cyber-orb-github.png" style="height: 423px; width: 620px;"></p> + + + +<p>您可以在您最喜爱的浏览器中打开index文件以启动并尝试游戏。目录中还有三个文件夹:</p> + +<ul> + <li><code>img</code>: 我们将在游戏中使用的所有图片。</li> + <li><code>src</code>:定义了游戏中所有源代码的 JavaScript文件。</li> + <li><code>audio:</code> 在游戏中使用的声音文件。</li> +</ul> + +<h2 id="Setting_up_the_Canvas">Setting up the Canvas</h2> + +<p>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 <code>index.html</code> file with the following content. You can create this yourself if you want to follow along:</p> + +<pre class="brush: html"><!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> +(function() { + var game = new Phaser.Game(320, 480, Phaser.CANVAS, 'game'); + game.state.add('Boot', Ball.Boot); + game.state.add('Preloader', Ball.Preloader); + game.state.add('MainMenu', Ball.MainMenu); + game.state.add('Howto', Ball.Howto); + game.state.add('Game', Ball.Game); + game.state.start('Boot'); +})(); +</script> +</body> +</html></pre> + +<p>So far we have a simple HTML website with some basic content in the <code><head></code> section: charset, title, CSS styling and the inclusion of the JavaScript files. The <code><body></code> contains initialization of the Phaser framework and the definitions of the game states.</p> + +<pre class="brush: js">var game = new Phaser.Game(320, 480, Phaser.CANVAS, 'game');</pre> + +<p>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 <code>CANVAS</code>, but there are also <code>WEBGL</code> and <code>AUTO</code> 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:</p> + +<pre class="brush: html"><canvas id='game' width='320' height='480'></canvas></pre> + +<p>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.</p> + +<div class="note"> +<p><strong>Note</strong>: You can read the <a href="http://gamedevelopment.tutsplus.com/tutorials/getting-started-with-phaser-building-monster-wants-candy--cms-21723">Building Monster Wants Candy</a> article for the in-depth introduction to the basic Phaser-specific functions and methods.</p> +</div> + +<p>Back to game states: the line below is adding a new state called <code>Boot</code> to the game:</p> + +<pre class="brush: html">game.state.add('Boot', Ball.Boot);</pre> + +<p>The first value is the name of the state and the second one is the object we want to assign to it. The <code>start</code> method is starting the given state and making it active. Let's see what the states are actually.</p> + +<h2 id="Managing_game_states">Managing game states</h2> + +<p>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: <code>Boot</code>, <code>Preloader</code>, <code>MainMenu</code>, <code>Howto</code> and <code>Game</code>. <code>Boot</code> will take care of initializing a few settings, <code>Preloader</code> will load all of the assets like graphics and audio, <code>MainMenu</code> is the menu with the start button, <code>Howto</code> shows the "how to play" instructions and the <code>Game</code> state lets you actually play the game. Let's quickly go though the content of those states.</p> + +<h3 id="Boot.js">Boot.js</h3> + +<p>The <code>Boot</code> state is the first one in the game.</p> + +<pre class="brush: js">var Ball = { + _WIDTH: 320, + _HEIGHT: 480 +}; +Ball.Boot = function(game) {}; +Ball.Boot.prototype = { + preload: function() { + this.load.image('preloaderBg', 'img/loading-bg.png'); + this.load.image('preloaderBar', 'img/loading-bar.png'); + }, + create: function() { + this.game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; + this.game.scale.pageAlignHorizontally = true; + this.game.scale.pageAlignVertically = true; + this.game.state.start('Preloader'); + } +};</pre> + +<p>The main <code>Ball</code> object is defined and we're adding two variables called <code>_WIDTH</code> and <code>_HEIGHT</code> 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 <code>Preload</code> state to show the progress of loading all the other assets. The <code>create</code> function holds some basic configuration: we're setting up the scaling and alignment of the Canvas, and moving on to the <code>Preload</code> state when everything's ready.</p> + +<h3 id="Preloader.js">Preloader.js</h3> + +<p>The <code>Preloader</code> state takes care of loading all the assets:</p> + +<pre class="brush: 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'); + this.preloadBar = this.add.sprite((Ball._WIDTH-158)*0.5, (Ball._HEIGHT-50)*0.5, 'preloaderBar'); + this.load.setPreloadSprite(this.preloadBar); + + this.load.image('ball', 'img/ball.png'); + // ... + this.load.spritesheet('button-start', 'img/button-start.png', 146, 51); + // ... + this.load.audio('audio-bounce', ['audio/bounce.ogg', 'audio/bounce.mp3', 'audio/bounce.m4a']); + }, + create: function() { + this.game.state.start('MainMenu'); + } +};</pre> + +<p>There are single images, spritesheets and audio files loaded by the framework. In this state the <code>preloadBar</code> 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 <code>preloadBar</code> image: from 0% to 100%, updated on every frame. After all the assets are loaded, the <code>MainMenu</code> state is launched.</p> + +<h3 id="MainMenu.js">MainMenu.js</h3> + +<p>The <code>MainMenu</code> state shows the main menu of the game, where you can start playing by clicking the button.</p> + +<pre class="brush: js">Ball.MainMenu = function(game) {}; +Ball.MainMenu.prototype = { + create: function() { + this.add.sprite(0, 0, 'screen-mainmenu'); + this.gameTitle = this.add.sprite(Ball._WIDTH*0.5, 40, 'title'); + this.gameTitle.anchor.set(0.5,0); + this.startButton = this.add.button(Ball._WIDTH*0.5, 200, 'button-start', this.startGame, this, 2, 0, 1); + this.startButton.anchor.set(0.5,0); + this.startButton.input.useHandCursor = true; + }, + startGame: function() { + this.game.state.start('Howto'); + } +};</pre> + +<p>To create a new button there's <code>add.button</code> method with the following list of optional arguments:</p> + +<ul> + <li>Top absolute position on Canvas in pixels.</li> + <li>Left absolute position on Canvas in pixels.</li> + <li>Name of the image asset the button is using.</li> + <li>Function that will be executed when someone clicks the button.</li> + <li>The execution context.</li> + <li>Frame from the image asset used as the button's "hover" state.</li> + <li>Frame from the image asset used as the button's "normal" or "out" state.</li> + <li>Frame from the image asset used as the button's "click" or "down" state.</li> +</ul> + +<p>The <code>anchor.set</code> 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.</p> + +<p>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.</p> + +<h3 id="Howto.js">Howto.js</h3> + +<pre class="brush: js">Ball.Howto = function(game) { +}; +Ball.Howto.prototype = { + create: function() { + this.buttonContinue = this.add.button(0, 0, 'screen-howtoplay', this.startGame, this); + }, + startGame: function() { + this.game.state.start('Game'); + } +};</pre> + +<p>The <code>Howto</code> state shows the gameplay instructions on the screen before starting the game. After clicking the screen the actual game is launched.</p> + +<h3 id="Game.js">Game.js</h3> + +<p>The <code>Game</code> state from the <code>Game.js</code> file is where all the magic happens. All the initialization is in the <code>create()</code> 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 <code>update()</code> function (executed at every frame), which updates things such as the ball position.</p> + +<pre class="brush: js">Ball.Game = function(game) {}; +Ball.Game.prototype = { + create: function() {}, + initLevels: function() {}, + showLevel: function(level) {}, + updateCounter: function() {}, + managePause: function() {}, + manageAudio: function() {}, + update: function() {}, + wallCollision: function() {}, + handleOrientation: function(e) {}, + finishLevel: function() {} +};</pre> + +<p>The <code>create</code> and <code>update</code> functions are framework-specific, while others will be our own creations:</p> + +<ul> + <li><code>initLevels</code> initializes the level data.</li> + <li><code>showLevel</code> prints the level data on the screen.</li> + <li><code>updateCounter</code> updates the time spent playing each level and records the total time spent playing the game..</li> + <li><code>managePause</code> pauses and resumes the game.</li> + <li><code>manageAudio</code> turns the audio on and off.</li> + <li><code>wallCollision</code> is executed when the ball hits the walls or other objects.</li> + <li><code>handleOrientation</code> 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.</li> + <li><code>finishLevel</code> loads a new level when the current level is completed, or finished the game if the final level is completed.</li> +</ul> + +<h4 id="Adding_the_ball_and_its_motion_mechanics">Adding the ball and its motion mechanics</h4> + +<p>First, let’s go to the <code>create()</code> function, initialize the ball object itself and assign a few properties to it:</p> + +<pre class="brush: 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);</pre> + +<p>Here we’re adding a sprite at the given place on the screen and using the <code>'ball'</code> 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 <code>bounce</code> property is used to set the bounciness of the ball when it hits the obstacles.</p> + +<h4 id="Controlling_the_ball">Controlling the ball</h4> + +<p>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 <code>create()</code> function :</p> + +<pre class="brush: js">this.keys = this.game.input.keyboard.createCursorKeys();</pre> + +<p>As you can see there’s a special Phaser function called <code>createCursorKeys()</code>, which will give us an object with event handlers for the four arrow keys to play with: up, down, left and right.</p> + +<p>Next we will add the following code to the <code>update()</code> function, so it will be fired on every frame. The <code>this.keys</code> object will be checked against player input, so the ball can react accordingly with the predefined force:</p> + +<pre class="brush: js">if(this.keys.left.isDown) { + this.ball.body.velocity.x -= this.movementForce; +} +else if(this.keys.right.isDown) { + this.ball.body.velocity.x += this.movementForce; +} +if(this.keys.up.isDown) { + this.ball.body.velocity.y -= this.movementForce; +} +else if(this.keys.down.isDown) { + this.ball.body.velocity.y += this.movementForce; +}</pre> + +<p>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.</p> + +<h4 id="Implementing_the_Device_Orientation_API">Implementing the Device Orientation API</h4> + +<p>Probably the most interesting part of the game is its usage of the <strong>Device Orientation API</strong> 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 <code>create()</code> function responsible for this:</p> + +<pre class="brush: js">window.addEventListener("deviceorientation", this.handleOrientation, true);</pre> + +<p>We’re adding an event listener to the <code>"deviceorientation"</code> event and binding the <code>handleOrientation</code> function which looks like this:</p> + +<pre class="brush: js">handleOrientation: function(e) { + var x = e.gamma; + var y = e.beta; + Ball._player.body.velocity.x += x; + Ball._player.body.velocity.y += y; +},</pre> + +<p>The more you tilt the device, the more force is applied to the ball, therefore the faster it moves (the velocity is higher).</p> + +<p><img alt="An explanation of the X, Y and Z axes of a Flame mobile device with the Cyber Orb game demo on the screen." src="https://mdn.mozillademos.org/files/10369/cyber-orb-flame-orientation.png" style="height: 480px; width: 620px;"></p> + +<div class="note"> +<p><strong>Note</strong>: To find more out about implementing device orientation and what raw code would look like, read <a href="/en-US/Apps/Build/gather_and_modify_data/responding_to_device_orientation_changes">Keep it level: responding to device orientation changes</a>.</p> +</div> + +<h4 id="Adding_the_hole">Adding the hole</h4> + +<p>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 <code>create()</code> function of our <code>Game</code> state:</p> + +<pre class="brush: 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);</pre> + +<p>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).</p> + +<h4 id="Building_the_block_labyrinth">Building the block labyrinth</h4> + +<p>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.</p> + +<p>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 (<code>x</code> and <code>y</code>) and the type of the block — horizontal or vertical (<code>t</code> with the <code>'w'</code> value meaning width and <code>'h'</code> meaning height). Then, to load the level we'll parse the data and show the blocks specific for that level. In the <code>initLevels</code> function we have:</p> + +<pre class="brush: js">this.levelData = [ + [ + { x: 96, y: 224, t: 'w' } + ], + [ + { x: 72, y: 320, t: 'w' }, + { x: 200, y: 320, t: 'h' }, + { x: 72, y: 150, t: 'w' } + ], + // ... +];</pre> + +<p>Every array element holds a collection of blocks with an <code>x</code> and <code>y</code> position and <code>t</code> value for each. After <code>levelData</code>, but still in the <code>initLevels</code> function, we're adding the blocks into an array in the <code>for</code> loop using some of the framework-specific methods:</p> + +<pre class="brush: js">for(var i=0; i<this.maxLevels; i++) { + var newLevel = this.add.group(); + newLevel.enableBody = true; + newLevel.physicsBodyType = Phaser.Physics.ARCADE; + for(var e=0; e<this.levelData[i].length; e++) { + var item = this.levelData[i][e]; + newLevel.create(item.x, item.y, 'element-'+item.t); + } + newLevel.setAll('body.immovable', true); + newLevel.visible = false; + this.levels.push(newLevel); +}</pre> + +<p>First, <code>add.group()</code> is used to create a new group of items. Then the <code>ARCADE</code> body type is set for that group to enable physics calculations. The <code>newLevel.create</code> 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 <code>setAll</code> on a group to apply it to all the items in that group.</p> + +<p>The objects are stored in the <code>this.levels</code> array, which is by default invisible. To load specific levels, we make sure the previous levels are hidden, and show the current one:</p> + +<pre class="brush: 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; +}</pre> + +<p>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.</p> + +<h4 id="Collision_detection">Collision detection</h4> + +<p>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 <code>update()</code> function:</p> + +<pre class="brush: 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);</pre> + +<p>This will tell the framework to execute the <code>wallCollision</code> function when the ball hits any of the walls. We can use the <code>wallCollision</code> function to add any functionality we want like playing the bounce sound and implementing the <strong>Vibration API</strong>.</p> + +<h4 id="Adding_the_sound">Adding the sound</h4> + +<p>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 <code>create()</code> function first:</p> + +<pre class="brush: js">this.bounceSound = this.game.add.audio('audio-bounce');</pre> + +<p>If the status of the audio is <code>true</code> (so the sounds in the game are enabled), we can play it in the <code>wallCollision</code> function:</p> + +<pre class="brush: js">if(this.audioStatus) { + this.bounceSound.play(); +}</pre> + +<p>That's all — loading and playing the sounds is easy with Phaser.</p> + +<h4 id="Implementing_the_Vibration_API">Implementing the Vibration API</h4> + +<p>When collision detection works as expected let's add some special effects with the help from the Vibration API.</p> + +<p><img alt="A visualization of the vibrations of a Flame mobile device with the Cyber Orb game demo on the screen." src="https://mdn.mozillademos.org/files/10371/cyber-orb-flame-vibration.png" style="height: 480px; width: 620px;"></p> + +<p>The best way to use it in our case is to vibrate the phone every time the ball hits the walls — inside the <code>wallCollision</code> function:</p> + +<pre class="brush: js">if("vibrate" in window.navigator) { + window.navigator.vibrate(100); +}</pre> + +<p>If the <code>vibrate</code> method is supported by the browser and available in the <code>window.navigator</code> object, vibrate the phone for 100 miliseconds. That's it!</p> + +<h4 id="Adding_the_elapsed_time">Adding the elapsed time</h4> + +<p>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 <code>create</code> function first:</p> + +<pre class="brush: js">this.timer = 0; // time elapsed in the current level +this.totalTimer = 0; // time elapsed in the whole game</pre> + +<p>Then, right after that, we can initialize the necessary text objects to display this information to the user:</p> + +<pre class="brush: 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);</pre> + +<p>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:</p> + +<pre class="brush: js">this.time.events.loop(Phaser.Timer.SECOND, this.updateCounter, this);</pre> + +<p>This loop, also in the <code>create</code> function, will execute the <code>updateCounter</code> function every single second from the beginning of the game, so we can apply the changes accordingly. This is how the complete <code>updateCounter</code> function looks:</p> + +<pre class="brush: js">updateCounter: function() { + this.timer++; + this.timerText.setText("Time: "+this.timer); + this.totalTimeText.setText("Total time: "+(this.totalTimer+this.timer)); +},</pre> + +<p>As you can see we’re incrementing the <code>this.timer</code> variable and updating the content of the text objects with the current values on each iteration, so the player sees the elapsed time.</p> + +<h4 id="Finishing_the_level_and_the_game">Finishing the level and the game</h4> + +<p>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 <code>update()</code> function adds a listener that fires when the ball gets to the hole.</p> + +<pre class="brush: js">this.physics.arcade.overlap(this.ball, this.hole, this.finishLevel, null, this);</pre> + +<p>This works similarly to the <code>collide</code> method explained earlier. When the ball overlaps with the hole (instead of colliding), the <code>finishLevel</code> function is executed:</p> + +<pre class="brush: 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'); + } + else { + alert('Congratulations, level '+this.level+' completed!'); + this.totalTimer += this.timer; + this.timer = 0; + this.level++; + this.timerText.setText("Time: "+this.timer); + this.totalTimeText.setText("Total time: "+this.totalTimer); + this.levelText.setText("Level: "+this.level+" / "+this.maxLevels); + this.ball.body.x = this.ballStartPos.x; + this.ball.body.y = this.ballStartPos.y; + this.ball.body.velocity.x = 0; + this.ball.body.velocity.y = 0; + this.showLevel(); + } +},</pre> + +<p>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.</p> + +<p>If the current level is lower than 5, all the neccesary variables are reset and the next level is loaded.</p> + +<h2 id="Ideas_for_new_features">Ideas for new features</h2> + +<p>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.</p> + +<h2 id="Summary">Summary</h2> + +<p>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 <a href="http://orb.enclavegames.com/">Cyber Orb</a> and check out its <a href="https://github.com/EnclaveGames/Cyber-Orb">source code on GitHub</a>.</p> + +<p>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 <a href="http://html5devstarter.enclavegames.com/#frameworks">other frameworks</a> worth considering too like <a href="http://impactjs.com/">ImpactJS</a>, <a href="https://www.scirra.com/construct2">Construct 2</a> or <a href="http://playcanvas.com/">PlayCanvas</a> — 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.</p> diff --git a/files/zh-cn/games/tutorials/index.html b/files/zh-cn/games/tutorials/index.html new file mode 100644 index 0000000000..63b38fa324 --- /dev/null +++ b/files/zh-cn/games/tutorials/index.html @@ -0,0 +1,25 @@ +--- +title: Tutorials +slug: Games/Tutorials +tags: + - Canvas + - Games + - JavaScript + - NeedsTranslation + - TopicStub + - Web + - Workflows +translation_of: Games/Tutorials +--- +<div>{{GamesSidebar}}</div><div>{{IncludeSubnav("/en-US/docs/Games")}}</div> + +<p>This page contains multiple tutorial series that highlight different workflows for effectively creating different types of web games.</p> + +<dl> + <dt><a href="/en-US/docs/Games/Workflows/2D_Breakout_game_pure_JavaScript">2D breakout game using pure JavaScript</a></dt> + <dd>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.</dd> + <dt><a href="/en-US/docs/Games/Workflows/2D_breakout_game_Phaser">2D breakout game using Phaser</a></dt> + <dd>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<a class="external external-icon" href="http://phaser.io/">Phaser</a> HTML5 game framework. This idea here is to teach some of the fundamentals (and advantages) of working with frameworks, along with fundamental game mechanics.</dd> + <dt><a href="https://developer.mozilla.org/en-US/docs/Games/Workflows/HTML5_Gamedev_Phaser_Device_Orientation">2D maze game with device orientation</a></dt> + <dd>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 <a href="/en-US/Apps/Build/gather_and_modify_data/responding_to_device_orientation_changes">Device Orientation</a> and <a href="/en-US/docs/Web/Guide/API/Vibration">Vibration</a><strong> APIs</strong> to enhance the gameplay and is built using the <a href="http://phaser.io/">Phaser</a> framework.</dd> +</dl> |