好きなだけかりんとうを食べる人生

フロントエンドとかデザインとかバックエンドとか浅く広く。社会人3年目のうぇぶでぃれくたーです。

canvasで花火(らしきもの)

前回ホタルを描いてみたので、今回はその応用として花火です。

サンプル

サンプル
クリックしてみてね。

コード(Javascriptのみ)

// 定数
var HANABI_NUM = 75;
var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
var GRAVITY = 0.05;

// 変数
var cvs = null;
var ctx = null;
var mX = 0;
var mY = 0;
var timer = "";
var hanabiArr = [];

window.onload = function() {

  // 初期化
  init();

  // クリックイベントの登録
  bundleEvent();

};

// イベントリスナの登録
function bundleEvent() {

  addListener(cvs, 'click', getPosition);
  addListener(cvs, 'click', startHanabi);

};

// イベントリスナの削除
function removeEvent() {

  removeListener(cvs, 'click', getPosition);
  removeListener(cvs, 'click', startHanabi);

};

// 初期化
function init() {

  // canvasの初期化
  cvs = document.getElementById("canvas");
  cvs.width = SCREEN_WIDTH;
  cvs.height = SCREEN_HEIGHT;
  ctx = cvs.getContext("2d");

  // 背景の描画
  ctx.fillStyle = "rgb(0, 0, 0)";
  ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

};

// 座標の取得
function getPosition(e) {

  var rect = e.target.getBoundingClientRect();
  mX = e.clientX - rect.left;
  mY = e.clientY - rect.top;

};

// アニメーション
function startHanabi() {

  create(mX, mY);
  removeEvent();
  loop();

};

// クラス
var Hanabi = function(x, y) {
  this.x = x;
  this.y = y;
};

Hanabi.prototype = {

  // 座標
  x: 0,
  y: 0,

  // 速度
  vX: 0,
  vY: 0,

  // 大きさ
  size: null,

  // 色
  color: null,

  // 透明度
  alpha: 1.0,

  // 削除フラグ
  deleteflg: false,

  update: function() {

    this.vY += GRAVITY;
    this.x += this.vX;
    this.y += this.vY;
    this.size *= 0.98;
    this.alpha = Math.round((this.alpha - 0.01) * 100) / 100;
    if (this.x < 0 || this.x > SCREEN_WIDTH || this.y > SCREEN_HEIGHT) {
      this.deleteflg = true;
    }

  },

  draw: function() {

    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false);
    ctx.fill();

  }

};

// インスタンスの設定、格納
function create(mX, mY) {

  for (var i = 0; i < HANABI_NUM; i++) {

    var hanabi = new Hanabi(mX, mY);
    hanabi.color = "rgba(255, 255, 255, " + hanabi.alpha + ")";
    hanabi.vX = Math.random() * 4 - 2;
    hanabi.vY = Math.random() * 4 - 2;
    hanabi.size = 5;
    hanabiArr.push(hanabi);

  }


};

// 花火の描画
function draw() {

  ctx.fillStyle = "rgb(0, 0, 0)";
  ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

  for (var i = 0; i < hanabiArr.length; i++) {
    hanabiArr[i].draw();
  }

};

// 位置の更新
function update() {

  var list = [];

  for (var i = 0; i < hanabiArr.length; i++) {

    hanabiArr[i].update();
    if (!hanabiArr[i].deleteflg) {
      list.push(hanabiArr[i]);
    }

  }

  if (list.length == 0) {
    clearTimeout(timer);
    bundleEvent();
  }

  hanabiArr = list;

};

function loop() {

  draw();
  update();
  timer = setTimeout(loop, 1000 / 60);

};

解説

canvasで何かを描画する時は

  1. オブジェクトを生成(パラメータを設定)
  2. オブジェクトの位置情報を更新
  3. 背景を描画
  4. オブジェクトを描画
  5. 2~4を繰り返す

ことが多いです(体感)。
他に方法あるのかな…気になる。

感想

まだ複数の花火を同時に描画したり、スワイプに対応したような処理ができていないのでその辺りが課題です。
あとはきれいなコード書けるようになりたいです。
もっとコードを書く機会を増やさないと…