WEB技術& Tips紹介サイト はなプロ!

2020-07-31 2020-08-01

CreateJSで雪が降る様子を表現する

HTML5 Canvasでリッチコンテンツを表現するためのJavaScriptライブラリ群であるCreateJS。今回はそのCreateJSを使用して、雪が降る様子を表現するサンプルをご紹介します。

サンプルはこちら
サンプルコード(GitHub)はこちら

ライブラリの読み込みとクラス設計

まずCreateJSのライブラリを読み込みます。今回はCDNを利用します。


head内にscriptタグを用意しておきます。
また今回はオブジェクト指向の練習も兼ねて、クラスを利用して設計していきます。

// 雪のクラス
class Snow extends createjs.Shape {
  constructor() {
    super();

    this.positionX = Math.random() * 600;
    this.positionY = -10;
    this.speed = 1 + Math.random() * 2; // 雪が降るスピード
    this.size = 1 + Math.random() * 5; // 雪のサイズ
    this.angle = Math.random() * 3; // 雪の揺れの計算角度
    this.angleSpeed = 0.02 + Math.random() * 0.08; // 揺れの変化スピードをランダムにする
    this.swingWidth = 12 + Math.random() * 15; // 揺れの大きさ
    this.drift = -1 + Math.random(); // X軸の向きへの加算
	this.life = 1; // 生存フラグ

    // 円を描画する
    this.graphics
      .beginFill("#fff")
      .drawCircle(this.positionX, this.positionY, this.size);
  }
  
  // 雪が落下する動き
  move() {
    this.y += this.speed;
    this.angle += this.angleSpeed;
    // 少しづつ斜めに落ちる
    this.positionX += this.drift;
    // 横に揺れながら落下する
    this.x = this.positionX + Math.sin(this.angle) * this.swingWidth;

    if (this.y > stage.canvas.height) {
      // canvasより下に落ちるとlifeを0にする
      this.life = 0;
    }
  }
}

createjs.Shapeを継承したクラスを定義し、constructorメソッド内で雪一粒ごとのプロパティを設定し、drawCircleで円を描画します。
一粒ごとに大きさや動きのスピードを変化させたいため、Math.random関数でランダムな値をセットします。

雪が落下するmove関数では、Math.sin関数を使用してふわふわと横に揺れる動きをつけています。またY座標がcanvasの高さよりも大きくなると (canvasより下に落ちると)位置をリセットするために一旦ライフを0にします。

イベントリスナーを設定し、画面を更新する

window.addEventListener('load', init);
let snows = [];
let stage = null;

function init() {
  // Stageオブジェクトを作成
  stage = new createjs.Stage('snowCanvas');
  stage.autoClear = false;
  
  // 背景画像
  let background = new createjs.Bitmap('./img/snow_bg.png');
  stage.addChild(background);

  // 雪を降らす
  let snowTimer = setInterval(addSnow, 300);
  function addSnow() {
    let snow = new Snow();
    snows.push(snow);
    stage.addChild(snow);
    
    if (snows.length >= 100) {
      clearInterval(snowTimer);
    }
  }

  // 自動的に画面更新する
  createjs.Ticker.addEventListener('tick', render);
  
}


// 画面を更新する
function render() {
  stage.update();
  for (let i=0; i<snows.length; i++) {
    // canvas内に存在していれば落下を実行
    if (snows[i].life === 1) {
      snows[i].move();
    }
    else {
      // canvas外にいると位置をリセット
      snows[i].x = Math.random() * 600;
      snows[i].y = -10;
      snows[i].life = 1;
    } 
  }
}

ページの読み込みが完了したらinit関数を呼び出すイベントリスナーを設定しておきます。
init関数内ではStageオブジェクトを作成し、背景画像を追加します。
そして先ほど設計した雪クラスのインスタンスを作成し、用意しておいたsnows配列に追加するとともにstageに追加します。
このとき、一気に雪が発生しないようにsetInterval関数を使用して、300ミリ秒ごとに一つ発生するようにタイマーを設定します。そして100個以上に なるとタイマーを停止させ、これ以上雪を発生させないようにします。

あとはcreatejs.Tickerクラスにイベントリスナーを設定し、tickイベントを監視します。tickイベントが発生するたびに (今回の場合はデフォルト設定のため24FPS=1秒間に24回)render関数を呼び出して画面を更新、雪を落下させます。
このときに雪の生存フラグをチェックし、canvas外に出たときには位置をリセットして再度降らせるようにします。

参考サイト

CreateJSの基本的な使い方はics.mediaさんの記事が非常に参考になります。
https://ics.media/tutorial-createjs/

関連記事