Edited at

Canvasでティウンティウンティウン...

More than 3 years have passed since last update.


はじめに

Canvasを利用して、ライフが無くなった時のゲームオーバーエフェクトを表現してみました。SE(音)は著作権的にアヤシイ気がしたので付けていません。エフェクトはシリーズによってもずいぶん違うかと思いますが、何となく雰囲気が伝われば幸いです。


ティウンティウンとは (ニコニコ大百科)


[動作イメージ]

※エフェクト以外はDOMで表現しています

thiwn_thiwn.gif


なお実際の動作は以下で確認することができます

http://codepen.io/nekoneko-wanwan/pen/JYmaJx



特長・仕様


  • Canvasサイズに依存しない

  • 粒の数・大きさ・色は柔軟に変更可能

  • ※少しラクをしたので、調整には直接関数内の修正が必要ですがご容赦ください


ソースコード


index.html

<!-- 動作イメージに出てくる○キャラは省略 -->

<canvas id="myCanvas" width="500" height="300"></canvas>


canvas.js

var cs       = document.getElementById('myCanvas');

var ctx = cs.getContext('2d');
var csWidth = cs.width;
var csHeight = cs.height;

var fps = 60;
var frameTime_ms = 1000 / fps; // 1フレーム辺りのミリ秒
var frameTime_sec = frameTime_ms / 1000; // 秒数に変換

var startTime = new Date().getTime();

/* 経過時間を返す */
var getTimer = function() {
return (new Date().getTime() - startTime);
};

/* ティウンティウンティウン...コンストラクタ */
var ThiwnThiwn = function() {
this.initialize();
};

ThiwnThiwn.prototype = {
initialize: function() {
this.x = 0;
this.y = 0;
this.r = 20;
this.vx = 0;
this.vy = 0;
this.scale = 0;
this.alpha = 1;
this.isBorder = true;
this.time = getTimer();
},
update: function() {
/* 実行時の経過時間を定義 */
var nowTime = getTimer();

/* X座標とY座標を更新 */
this.x += this.vx * frameTime_sec;
this.y += this.vy * frameTime_sec;

/* 透明度を下げていく */
this.alpha -= 0.4 * frameTime_sec;
if (this.alpha < 0) {
this.alpha = 0;
}

/* 経過時間によってスタイルを変更 */
if (nowTime - this.time > 0) {
this.scale += 3 * frameTime_sec;
this.isBorder = false;
}
if (nowTime - this.time > 300) {
this.isBorder = true;
this.scale = 0;
this.time = nowTime;
}
},
draw: function() {
ctx.save();
ctx.translate(this.x, this.y);
ctx.globalAlpha = this.alpha;

/* 枠線のみ描画 */
if (this.isBorder) {
ctx.beginPath();
ctx.arc(0, 0, this.r + 7, 0, Math.PI * 2, false);
ctx.closePath();
ctx.lineWidth = 3;
ctx.strokeStyle = '#fff';
ctx.stroke();
ctx.closePath();
}

/* 中心部を描画 */
ctx.scale(this.scale, this.scale);
var grad = ctx.createRadialGradient(0, 0, 0, 0, 0, this.r);
ctx.beginPath();
grad.addColorStop(0.8, '#fff ');
grad.addColorStop(1, 'rgba(255,213,0,0.8)');
ctx.fillStyle = grad;
ctx.arc(0, 0, this.r, 0, Math.PI * 2, false);
ctx.fill();

ctx.restore();
}
};

/**
* コンストラクタから複数のインスタンスを作成して配列を返す
* @param {num} x: エフェクトを発生させる中心のX座標
* @param {num} y: エフェクトを発生させる中心のY座標
* @param {num} deg: インスタンスをいくつ作成するかに使用
* 45を指定すると、360/45 = 8個生成される
*/

var createCircle = function(x, y, deg) {
var arr = []; // 複数のインスタンスを格納
var sp = 200; // アニメーション速度に影響
var _deg = 0;
var obj; // インスタンスを格納
for (; _deg <= 360 * 2; _deg += deg) {
obj = new ThiwnThiwn();

/* 2週目以降はスピードを落とすことで、二重の輪を表現 */
if (_deg > 360) {
sp = 100;
}

obj.x = x;
obj.y = y;
obj.vx = sp * Math.cos(_deg * Math.PI / 180);
obj.vy = sp * Math.sin(_deg * Math.PI / 180);

arr[arr.length] = obj;
}
return arr;
};

/**
* レンダリング
* @param {arr} arr: createCircleにより複数インスタンスを格納した配列を渡す
*/

var render = function(arr) {
var obj;
ctx.clearRect(0, 0, csWidth, csHeight);
for (var i = 0, l = arr.length; i < l; i++) {
obj = arr[i];
obj.update();
obj.draw();
}
requestAnimationFrame(function() {
render(arr);
});
};

/* 実行 */
var circles = createCircle(csWidth/2, csHeight/2, 45);
setTimeout(function() {
render(circles);
}, 100);



作り方・考え方


コンストラクタの用意


  • 丸オブジェクトを生成するコンストラクタを用意します

  • インスタンスには更新時に必要な値を持たせます(x, y座標、スケールなど)

  • インスタンスの共通メソッドとして、以下を用意します


    • どのように値を更新していくかのupdate()

    • どのようにCanvasに描画していくかのdraw()




  • update()内では経過時間を見ることで、動作の細かい制御を可能にしています


  • draw()内では、translate()scale()によりアニメーションを制御しています

  • 描画の度に座標軸のズレを初期化するため、save(), restore()で元に戻してます


インスタンスを生成し、インスタンスを実行するメソッドを用意



  • createCircle()メソッドにより、コンストラクタから複数のインスタンスを生成します


  • render()メソッドにより、一定期間ごとに各インスタンスのupdate(), draw()を一度に実行し続けます


なおrequestAnimationFrameを止める処理は考慮していません



残り


  • 最後にcreateCircle()render()を実行する処理を書いてお終いです

  • サンプルの動作イメージでは、自キャラと敵キャラの位置を監視し、重なった(衝突と見なした)ら上記メソッドを実行するようにしています


終わりに

作り方は自分で考えてみたので、書き方が微妙だったり非効率な可能性があります。もっと良い方法があればご教授くださいませ。

今まで作成した謎なシリーズ


Canvasでビックリマンなシールを書いてみた(光るゾ!)

Canvasで斬!っと画面が斬れるようなエフェクトを書いてみた

Canvasで漫画にあるような吹き出しを書いてみた

Canvasで漫画にあるような "ざわ・・・" を書いてみた

Canvasで漫画にあるような集中線を書いてみた