このシリーズのパート1では、再利用可能なオブジェクトをキャンバスにレンダリングし、GUIを使用してより直感的なコントロールを行い、アニメーションループで基本的な動きの錯覚を作成する基本について説明しました。 このパートでは、キャンバスの境界に当たると色が変わる単純なボールを使用して、衝突効果を作成することに慣れます。

ボイラープレート

ほとんどのアニメーションの開始点として、Part 1のプロジェクトを使用できます。

index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <meta http-equiv="X-UA-Compatible" content="ie=edge"/>
    <title>HTML Canvas</title>
  </head>
  <body>

    <canvas></canvas>

  </body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
  <script src="./canvas.js"></script>
</html>
canvas.js
// Get canvas element
const canvas = document.querySelector('canvas');
const c = canvas.getContext('2d');

// Make canvas fullscreen
canvas.width = innerWidth;
canvas.height = innerHeight;
addEventListener('resize', () => {
  canvas.width = innerWidth;
  canvas.height = innerHeight;
});

// Control Panel
const gui = new dat.GUI();

const controls = {
  dx: 0,
  dy: 0,
};

gui.add(controls, 'dx', 0, 10);
gui.add(controls, 'dy', 0, 10);

// New Object
class Ball {
  constructor(x, y, radius, color) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.color = color;
  }
}

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

Ball.prototype.update = function () {
  this.x += controls.dx;
  this.y += -controls.dy;
  this.draw();
};

const ball = new Ball(innerWidth / 2, innerHeight / 2, 50, 'red');

// Render new instances
const init = () => ball.draw();

// Handle changes
const animate = () => {
  requestAnimationFrame(animate);

  c.clearRect(0, 0, canvas.width, canvas.height);

  ball.update();
};

init();
animate();

バウンサー

最終結果はここでプレビューできます。

衝突時の動作を変更するには、updateメソッドに条件を追加するだけで、ボールが境界に当たるたびに、この場合は方向を逆にして、ボールの動作を変更します。 ブラウザはオブジェクトの中心でその位置を確認しているため、常に半径を計算に含める必要があることに注意してください。

canvas.js
Ball.prototype.update = function() {
  if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {
    controls.dy = -controls.dy;
  }
  this.y -= controls.dy;

  if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {
    controls.dx = -controls.dx;
  }
  this.x += controls.dx;

  this.draw();
};

次に、ボールの色を変更するなど、何かを打ったときのさらに興味深い動作を追加しましょう。 まず、選択する色の配列と、ランダムに選択する関数が必要です。 境界線にぶつかったときはいつでも、色の値を新しいランダムな値に再割り当てできます。

Kuler をチェックして、独自のカラーパレットを作成することをお勧めします。

// Returns a color between 0 and the length of our color array
const randomColor = colors => colors[Math.floor(Math.random() * colors.length)];

const colors = [
  '#e53935',
  '#d81b60',
  '#8e24aa',
  '#5e35b1',
  '#3949ab',
  '#1e88e5',
  '#039be5',
  '#00acc1',
  '#00897b',
  '#43a047',
  '#ffeb3b',
  '#ef6c00'
];

// Re-assign color on contact
Ball.prototype.update = function () {
  if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {
    this.color = randomColor(colors);
    controls.dy = -controls.dy;
  };
  this.y -= controls.dy;

  if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {
    this.color = randomColor(colors);
    controls.dx = -controls.dx;
  };
  this.x += controls.dx;

  this.draw();
};

// Make it start with a random color
const newBall = new Ball(innerWidth / 2, innerHeight / 2, 50, randomColor(colors));

しっぽ

基本的な機能が整ったので、後ろに続く色付きの尻尾を追加することで、視覚的にもう少し面白くすることができます。 これを行うには、clearRectを削除し、キャンバス全体を暗いRGBA値で塗りつぶします。 これにより、通過するものすべてから「残留物」効果が作成され、背景の不透明度で残留物の強度を制御できます。

const animate = () => {
  requestAnimationFrame(animate);

  c.fillStyle = `rgba(33, 33, 33, ${-controls.tail / 10})`; // Lower opacity creates a longer tail
  c.fillRect(0, 0, canvas.width, canvas.height);

  newBall.update();
};

// We also need to update our controls with some default values
const controls = {
  dx: 5,
  dy: 5,
  tail: -5
};

gui.add(controls, 'dx', 0, 10);
gui.add(controls, 'dy', 0, 10);
gui.add(controls, 'tail', -10, 0);

結論

ちょうどそのように、私たちは今、いくつかの特殊効果を備えた非常に基本的な衝突システムを持っています。 このシリーズの次のパート3では、ここで説明する概念を使用して、この動的な雨のアニメーションを作成します。

それに続いて問題が発生した場合は、Codepenで実用的な例を利用できます。 気軽にフォークして、作ったものを共有してください。