--- title: 实践对象构造 slug: Learn/JavaScript/Objects/Object_building_practice tags: - JavaScript - 初学者 - 学习 - 对象 - 指南 - 画布 translation_of: Learn/JavaScript/Objects/Object_building_practice ---
{{LearnSidebar}}
{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}

在前面的文章中,我们学习了 JavaScript 的面向对象理论和基本的语法知识,为之后的学习建立了良好的基础。这篇文章中我们将进行一次实战演练,通过构造 JavaScript 对象得到生动有趣的成果!

预备知识: 基本的计算机知识,了解HTML与CSS的基本概念,熟悉JavaScript基本知识 (请参阅 入门 和 构建块结构)和面向对象的JavaScript (OOJS) 基础 (请参阅 对象基础)。
目标: 练习使用对象,在真实环境中应用面向对象开发技术。

弹跳吧!小彩球!

本文通过编写一个弹球 demo 来展示 JavaScript 中对象的重要性。我们的小球会在屏幕上弹跳,当它们碰到彼此时会变色。最终会像这样:

{{ EmbedLiveSample('Bouncing_balls', '100%', 480, "", "", "hide-codepen-jsfiddle") }}

这个实例将会利用 Canvas API 来在屏幕上画小球, 还会用到 requestAnimationFrame API 来使整个画面动起来 —— 我们并不要求你事先学习过这些 API 的相关知识,希望你完成这个练习之后会想去探索更多。这个过程中我们会用到一些漂亮的小东西并向你展示一些技巧,比如小球从墙上反弹,检查它们是否撞到了对方 (也就是碰撞检测)。

让我们开始吧

首先下载 bouncing-balls-start.zip,其中包含以下三个文件:index.html、style.css 和 main.js。它们分别包含以下内容:

  1. 一个非常简单的 HTML 文档,包括一个 <h1> 元素、一个{{HTMLElement("canvas")}} 元素来画小球,还有一些元素将 CSS 和 JavaScript 运用到我们的 HTML 中。
  2. 一些非常简单的样式,主要是 <h1> 元素的样式和定位,另外还能使画面填充整个页面从而摆脱滚动条和边缘的空白(这样看起来非常简洁)
  3. 一些 JavaScript 用来设置 <canvas> 元素,并提供我们要用到的基本函数。

脚本的第一部分是这样的:

const canvas = document.querySelector('canvas');

const ctx = canvas.getContext('2d');

const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;

这个脚本使用变量代指了 <canvas> 元素, 然后对其调用 getContext() 从而我们获得一个开始画画的环境。存储以上操作结果的变量(ctx)是一个对象,直接代指画布上的一块允许我们绘制 2D 图形的区域。

接下来,我们设置 widthheight 变量,并且让画布元素的宽和高(分别使用 canvas.widthcanvas.height 表示)等于浏览器的宽和高(也就是网页显示的区域 — 可以从 {{domxref("Window.innerWidth")}} 和 {{domxref("Window.innerHeight")}}参数获得)。

你会看到我们在这里串联了多个赋值表达式在一起,这样能更快地设置变量——这是完全正确的。

原始脚本最后的部分如下:

function random(min,max) {
  return Math.floor(Math.random()*(max-min)) + min;
}

function randomColor() {
  return 'rgb(' +
         random(0, 255) + ', ' +
         random(0, 255) + ', ' +
         random(0, 255) + ')';
}

第一个函数为我们生成一个 minmax 之间的随机整数,第二个函数为我们生成一个随机的颜色值。

为程序中的小球建立模型

我们的项目中会有很多小球在屏幕上跳来跳去。因此这些小球会以相同的方式运作,从而我们可以通过一个对象实例化它们。首先,我们将下面的构造器加入到代码的底部。

function Ball(x, y, velX, velY, color, size) {
  this.x = x;
  this.y = y;
  this.velX = velX;
  this.velY = velY;
  this.color = color;
  this.size = size;
}

这个构造器中定义了每个小球需要的参数:

这里说明了小球的属性,那么方法呢?别忘了我们要让小球动起来。

画小球

首先给小球的原型加上 draw() 方法:

Ball.prototype.draw = function() {
  ctx.beginPath();
  ctx.fillStyle = this.color;
  ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
  ctx.fill();
}

通过使用这个函数,通过使用我们之前定义的 ctx对象 的方法,我们就可以让在屏幕上画出小球了。ctx 的内容区域就像是一张纸,现在我们就可以命令我们的笔画一点东西。

现在你已经可以测试你的对象了。

  1. 保存代码,将 HTML 加载到浏览器中。
  2. 打开浏览器中的 JavaScript 控制台,刷新页面,从而画布可以根据可视的区域调整自己的大小。
  3. 通过下面的代码创建一个小球实例。
    let testBall = new Ball(50, 100, 4, 4, 'blue', 10);
  4. 你可以调用实例的这些属性。
    testBall.x
    testBall.size
    testBall.color
    testBall.draw()
  5. 当你键入最后一行的时候,你会在你的画布上看到一个小球被画出来了。

更新小球的数据

我们可以在一个固定位置画出小球,但是他们不会动,我们需要一个函数来更新一些东西。在 JavaScript 文件底部加上下面的代码,也就是给小球原型加上一个 update() 方法。

Ball.prototype.update = function() {
  if ((this.x + this.size) >= width) {
    this.velX = -(this.velX);
  }

  if ((this.x - this.size) <= 0) {
    this.velX = -(this.velX);
  }

  if ((this.y + this.size) >= height) {
    this.velY = -(this.velY);
  }

  if ((this.y - this.size) <= 0) {
    this.velY = -(this.velY);
  }

  this.x += this.velX;
  this.y += this.velY;
}

函数的前四个部分用来检查小球是否碰到画布的边缘。如果碰到,我们反转小球的速度方向来让它向反方向移动。就比如说,如果小球正向上移动 (正 velY),然后垂直速度发生改变,小球就向下移动 (负 velY)。

在这四部分中,我们:

在每种情况下,我们都会加上小球的半径,因为 x/y 坐标是小球中心的坐标,我们希望小球在其边界接触浏览器窗口的边界时反弹,而不是小球的一部分都不见了再返回。

最后两行,我们将 velX 的值加到 x 的坐标上,将 velY 的值加到 y 坐标上 —— 每次调用这个方法的时候小球就移动这么多。

暂时先这样做; 让我们继续做一些动画!

让球动起来 

现在就变得非常有趣了。我们在画布上加上一些小球,并且让他们动起来。

  1. 首先我们需要一个地方储存小球,下面的数组会干这件事 —— 现在将它添加到你的代码底部:
    let balls = [];
    
    while (balls.length < 25) {
        let size = random(10, 20);
        let ball = new Ball(
          // 为避免绘制错误,球至少离画布边缘球本身一倍宽度的距离
          random(0 + size, width - size),
          random(0 + size, height - size),
          random(-7, 7),
          random(-7, 7),
          randomColor(),
          size
        );
        balls.push(ball);
      }
    
  2. 几乎所有的动画效果都会用到一个运动循环,也就是每一帧都自动更新视图。这是大多数游戏或者其他类似项目的基础。

  3. 现在将它添加到你的代码底部:
    function loop() {
      ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
      ctx.fillRect(0, 0, width, height);
    
      for (let i = 0; i < balls.length; i++) {
        balls[i].draw();
        balls[i].update();
      }
    
      requestAnimationFrame(loop);
    }

    loop() 函数做了下面的事情:

  4. 最后但是非常重要的是,加上下面这一行 —— 让动画开始运行的话我们需要调用这个函数。
    loop();

完成这些基础的之后在浏览器打开测试一下!

添加碰撞检测

现在会更加有趣,给我们的项目加上碰撞检测,从而小球会知道他们正在撞击其他的球。

  1. 首先在 update() 方法后添加以下方法 (即 Ball.prototype.update 的下面)。
    Ball.prototype.collisionDetect = function() {
      for (let j = 0; j < balls.length; j++) {
        if (this !== balls[j]) {
          const dx = this.x - balls[j].x;
          const dy = this.y - balls[j].y;
          const distance = Math.sqrt(dx * dx + dy * dy);
    
          if (distance < this.size + balls[j].size) {
            balls[j].color = this.color = randomColor();
          }
        }
      }
    }

    这个方法有一点点复杂,如果不理解的话不必过分担心,下面是对它的解释:

  2. 我们也需要在每一帧动画中都调用这个函数,因此在 balls[i].update() 加上下面的代码:
    balls[i].collisionDetect();
  3. 保存文件,刷新浏览器,你就会看到小球在撞击时会变色!

注:如果示例无法顺利执行,可参考我们的 最终版本,或者 在线试用

概要

我们希望你玩得开心,编写出你自己的随机弹跳球的例子,在整个程序中使用各种对象和面向对象的技术! 在你实际运用对象中能提供一些有用的帮助。

对象文章就到这里了。现在剩下的就是在下一节的对象评估中测试你的技能。

另请参阅

{{PreviousMenuNext("Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects/Adding_bouncing_balls_features", "Learn/JavaScript/Objects")}}

本章目录