反射 – 日本語で書くアニメーションプログラム

このシリーズではアニメーションのためのプログラムを日本語に置き換えて解説します。
プログラムとして書かれた数式を日本語にすることで言語の仕様に依存しない「なぜそのように動くか?」という理解の一助となればと思います。

※私がWeb制作を生業にするフロントエンドエンジニアなのでプログラムの箇所はPixiJSで記述しています。

プログラムを日本語に。

オブジェクトが反射するプログラムを日本語で書くと、以下のような書き方で実装出来ます。

X軸移動の方向 = 1
Y軸移動の方向 = 1

アニメーションさせるためのループ処理{
  オブジェクトのX座標 += 5 * X軸移動の方向
  オブジェクトのY座標 += 3 * Y軸移動の方向

 条件分岐( 0 > オブジェクトのX座標 || オブジェクトのX座標 > 描画領域の幅 ){
  X軸移動の方向 = X軸移動の方向 * -1
 }
 条件分岐( 0 > オブジェクトのY座標 || オブジェクトのY座標 > 描画領域の高さ ){
  Y軸移動の方向 = Y軸移動の方向 * -1
 }
}

これを実際のプログラムで書くとこうなります。
※アニメーションに関係ない記述に関しては一部割愛しています。

// 動かすオブジェクトを定義
let obj = new PIXI.Graphics();
obj.beginFill(0xFFFFFF, 1);
obj.drawRoundedRect(0, 0, 100, 100, 16);
obj.endFill();
obj.pivot.x = 50;
obj.pivot.y = 50;

let dx = 1;
let dy = 1;

app.ticker.add((delta) => {
  obj.x += 5 * dx;
  obj.y += 3 * dy;

  if( 0 > obj.x || obj.x > app.screen.width - obj.width){
    dx = dx * -1;
  }
  if( 0 > obj.y || obj.y > app.screen.height - obj.height){
    dy = dy * -1;
  }
});

これを上から順番に日本語にするとこうなります。

オブジェクト名 = オブジェクトの入れ物を作成
オブジェクト.色の塗りつぶし(白,透明度)
オブジェクト.角丸の四角を作成(x座標, y座標, 横幅, 縦幅, 角丸サイズ)
オブジェクト.色の塗りつぶし終了
オブジェクト.中心点x = オブジェクトの幅の半分
オブジェクト.中心点y = オブジェクトの高さの半分

X軸移動の方向 = 1
Y軸移動の方向 = 1

アニメーションさせるためのループ処理{
  オブジェクトのX座標 += 5 * X軸移動の方向
  オブジェクトのY座標 += 3 * Y軸移動の方向

 条件分岐( 0 > オブジェクトのX座標 || オブジェクトのX座標 > 描画領域の幅 ){
  X軸移動の方向 = X軸移動の方向 * -1
 }
 条件分岐( 0 > オブジェクトのY座標 || オブジェクトのY座標 > 描画領域の高さ ){
  Y軸移動の方向 = Y軸移動の方向 * -1
 }
}

反射のプログラムの肝はオブジェクトが移動する方向を反転させる為の変数を用意することです。その変数をX軸の移動に対して掛ければ準備完了です。
そして反射させたい位置にオブジェクトが来た際に、方向の正負を反転させる事で進行方向を逆転させます。

ただ、反射のプログラムに関しては反射の原理よりも描画の仕様に注意が必要です。描画領域自体のゼロの位置、オブジェクトの基点などがプログラムやライブラリによって違うからです。

オブジェクトの基点が左上なら右端にぶつかる時は「描画領域の幅 − オブジェクトの幅」が必要ですし、基点が中心の場合はマイナスする値が「オブジェクトの幅 / 2」になり、左端にぶつかる時は「ゼロ + オブジェクトの幅 / 2」といった値を設定しないと綺麗な位置で反射しません。

または、3D系の場合はオブジェクトの座標がゼロでそれをカメラで撮影しているという描画のため、描画領域の幅ではなく「可視領域の幅」という事になります。

ちなみにオブジェクト同士の衝突による反射に関してはここで解説したものに加えて「当たり判定」というアルゴリズムが必要になってきます。これはライブラリによってはデフォルトであったりなかったりですが、自力で書こうと思うとオブジェクトの形状によってはかなり面倒な部分になります。

とりあえず反射をプログラムに入れておくと、オブジェクトが無限に進み続けるのを防げるので、何かしらアニメーションのテストをする際も入れておくと少し安心かもしれませんね。