SVGの基本図形:circle要素

前回は、rect要素を生成してパドル(バー)を出現させました。今回は、ブロックにぶつけるボールを生成するのに、circle要素を使います。生成してからボールを動かしてみて、壁にぶつかったら反射するところまで作ってみたいと思います。

初期設定ファイルにボールの初期値を格納

またまた前回作成したblock-breaking-init.jsにボールの初期値を格納する変数を書き足します。

〜略〜
  paddle : {
    x : 250,
    y : 450,
    w : 60,
    h : 10,
    fill: '#000'
  },
  ball : {
    r : 5,
    cx: 250,
    cy: 400,
    dx: 3,
    dy: -3,
    fill: '#00f'
  }
〜略〜

9〜16行目が追加した内容です。それぞれの変数の値は以下の通り。

  • game.ball.r – ボールの半径
  • game.ball.cx – ボールのx座標
  • game.ball.cy – ボールのy座標
  • game.ball.dx – ボールのx座標への移動量
  • game.ball.dy – ボールのy座標への移動量
  • game.ball.fill – ボールの色

この値を元にcircle要素を生成します。

ボールのクラスを定義

パドルのときと同様にボールのインスタンスを生成するために、ボールのクラスを定義します。クラスのメソッドとして、ボールの初期値を受取る処理とその値を使用して描画する処理を定義します。それに加えて、ボールの位置を決める処理と動作処理を定義しようと思います。

ボールの基本クラス定義

Ballという名前でクラスを定義します。新しくblock-breaking-ball.jsというファイルを作成して、以下のように記述します。基本はパドルと一緒。

function Ball() {
  this.initialize.apply(this, arguments);
}

パドルのときと同様に、applyの引数に自分自身(this)とargumentsを渡します。argumentsはBallクラスのインスタンスを作成する時に渡される引数をオブジェクトで保持してくれます。

ボールの初期化処理の定義

こちらもパドルの時と同様に処理を書きます。セットする変数名が違うだけです。

Ball.prototype.initialize = function(option) {
  this.ball = option.ball;
  this.r  = option.r;
  this.cx = option.cx;
  this.cy = option.cy;
  this.dx = option.dx;
  this.dy = option.dy;
  this.fill = option.fill;
};

ボールの描画処理の定義

こちらもパドルの時と同様にdrawというメソッドを定義。

Ball.prototype.draw = function() {
  this.ball.setAttribute('r',  String(this.r));
  this.ball.setAttribute('cx', String(this.cx));
  this.ball.setAttribute('cy', String(this.cy));
  this.ball.setAttribute('fill', this.fill);
  game.stage.base.appendChild(this.ball);
};

this.ball変数にcircleオブジェクトをインスタンス化する時に渡します。そのcircleオブジェクトの属性値をそれぞれセットして、 appendChildメソッドでステージの子要素とします。

ボールの座標セット処理の定義

ここからがパドルにはなかった処理。positionというメソッドを定義して現在位置(cx, cy)に移動量(dx, dy)を足した値を返すようにします。

Ball.prototype.position = function() {
  return {
    cx: this.cx + this.dx,
    cy: this.cy + this.dy
  };
};

ボールの移動処理の定義

moveというメソッドを定義します。先程のpositionメソッドで座標計算した値を元にステージの壁に当たったら反射させる処理を書きます。

Ball.prototype.move = function() {
  var pos = this.position();

  if (pos.cx < this.r || pos.cx > game.stage.w - this.r) {
    this.dx *= -1;
  }
  if (pos.cy < this.r || pos.cy > game.stage.h + this.r) {
    this.dy *= -1;
  }

  this.cx += this.dx;
  this.cy += this.dy;
  this.ball.setAttribute('cx', String(this.cx));
  this.ball.setAttribute('cy', String(this.cy));
};

2行目で先程の座標計算メソッドを呼び出し座標位置を決定します。それから、x座標は左の壁の座標(0)と右の壁の座標(ステージの幅)からはみ出したら反転させています。y座標も同様に上の壁の座標(0)と下の壁の座標(ステージの高さ)からはみ出したら反転させています。

その値を座標に再セットして、circle要素の属性に設定しています。これでボールのクラス設定は完了。

ボールクラスからインスタンス作成

クラスが定義できたところで、パドル同様このクラスを元にインスタンスを生成して描画をします。描画後に動作させてみます。

インスタンスを生成

これもパドルと同様に、block-breaking-main.jsファイルの中にコードを書きます。

var ball = new Ball({
  ball: document.createElementNS(game.stage.svgns, 'circle'),
  r : game.ball.r,
  cx: game.ball.cx,
  cy: game.ball.cy,
  dx: game.ball.dx,
  dy: game.ball.dy,
  fill: game.ball.fill
});

パドルとの違いは生成するインスタンの要素がcircleというところ。

描画メソッド(draw)と動作メソッド(move)のコール

インスタンスが生成されたので、最後に描画メソッド(draw)をコールします。その後に動作メソッド(move)をコールするのですが、これは1回だけでなく繰り返しコールして動作しているように見せるのでsetIntervalで10ミリ秒毎にコールするようにします。

function main() {
  paddle.draw();
  ball.draw();

  setInterval(function() {
    ball.move();
  }, 10);
}

main();

できた!\(^o^)/
ボールのスピード(10ミリ秒)はリテラル値でなく変数に持たせて初期設定で変えられるようにしておいたほうがいいな。

GitHub
※step03フォルダに今回の記事のソースコードが入っています。