はじめに
phina.jsでゲームを作ろうとするとエフェクトが欲しくなりますよね。
「図形を組み合わせて作ることもできるけど、パーティクルを使いたい!」
そこで見つけたのが「Proton」というパーティクルエンジンです。
Protonとは?
Proton is a lightweight and powerful javascript particle engine.
With it you can easily create countless cool effects.
Protonは軽くて強いJavaScript製パーティクルエンジン!
簡単にクールなエフェクトが沢山作れるよ!
- Seven kinds of renderers
- canvas - CanvasRenderer
- dom - DomRenderer
- webgl - WebGLRenderer
- pixel - PixelRenderer
- easeljs - EaselRenderer
- pixi.js - PixiRenderer
- custom - CustomRenderer
7種類のレンダラーがあるよ!
- Integratable into any game engine.
どのゲームエンジンでも使えるよ!
proton.min.jsのファイルサイズを確認してみると64.6KB!確かに軽いです。
なんだかphina.jsとも仲良くしてくれそうなので、とりあえず試してみます。
サンプルを動かす
このページに書いてあるコードを写してphina.jsで動くようにしてみます。
var SCREEN_W = 640;
var SCREEN_H = 640;
phina.globalize();
phina.define('MainScene', {
superClass: 'DisplayScene',
init: function(options) {
this.superInit(options);
this.backgroundColor = 'black';
var plainElement = PlainElement({
width: SCREEN_W,
height: SCREEN_H
}).setPosition(SCREEN_W/2, SCREEN_H/2).addChildTo(this);
// plainElementからcanvasを取得する
var canvas = plainElement.canvas.domElement;
// Proton本体を作る
var proton = new Proton();
// エミッター(パーティクルの発生源)を作る
var emitter = new Proton.Emitter();
// rateを設定する
emitter.rate = new Proton.Rate(Proton.getSpan(10, 20), 0.1);
// Initializeを追加する
emitter.addInitialize(new Proton.Radius(1, 22));
emitter.addInitialize(new Proton.Life(2, 4));
emitter.addInitialize(new Proton.Velocity(2, Proton.getSpan(0, 360), 'polar'));
// Behaviourを追加する
emitter.addBehaviour(new Proton.Color('ff0000', 'random'));
emitter.addBehaviour(new Proton.Alpha(1, 0));
// エミッターの座標を設定する
emitter.p.x = canvas.width / 2;
emitter.p.y = canvas.height / 2;
emitter.emit();
// Proton本体にエミッターを追加する
proton.addEmitter(emitter);
// canvas rendererを追加する
var renderer = new Proton.CanvasRenderer(canvas);
proton.addRenderer(renderer);
this.on('enterframe', function(e) {
// 毎フレーム proton.update()を呼んであげる
proton.update();
});
}
});
phina.main(function() {
var app = GameApp({
startLabel: 'main',
width: SCREEN_W,
height: SCREEN_H,
fps: 60
});
app.run();
});
どうやらエミッターにInitializeとBehaviourを追加してパーティクルに動きを加えていくようです。
チュートリアルが用意されていなかったので、試しながら使い方をまとめていきます。
Protonの使い方
初期設定する「Initialize」たち。
new Proton.Body(image, w, h)
パーティクル本体の画像を指定します。
引数のimage
は画像のURLかImageオブジェクト。w
とh
は省略可能です。
画像の指定が無かった場合、普通の円形のパーティクルになります。
new Proton.B()
と省略できます。
var image = AssetManager.get('image', 'particle').domElement;
var bodyEx1 = new Proton.Body(image, 100, 100);
var bodyEx2 = new Proton.B('./image/particle.png');
new Proton.Life(a, b, c)
パーティクルの生存時間を指定します。
a
とb
に数を指定した場合はa~bのからランダムな値(小数含む)になります。
c
は省略可能ですがtrue
を指定すると、ランダムの範囲がa-b~a+bに変わります。
a
のみに数を指定するとa
の値固定になり、配列を指定するとその中からランダムにピックアップされます。
new Proton.L()
と省略できます。
var lifeEx1 = new Proton.Life(1, 4); // 1~4 からランダム
var lifeEx2 = new Proton.Life(3, 1, true); // 2~4 からランダム
var lifeEx3 = new Proton.Life(2); // 2 固定
var lifeEx4 = new Proton.L([1, 3, 5]); // 1 か 3 か 5
new Proton.Mass(a, b, c)
パーティクルの質量を指定します。
指定方法は上記のProton.Life
と同じです。
new Proton.M()
と省略できます。
new Proton.Position(zone)
パーティクルを発生させる範囲をZoneで指定します。
Zoneについては「発生・行動範囲を決める「Zone」たち。」で説明します。
new Proton.P()
と省略できます。
new Proton.Radius(a, b, c)
パーティクルの半径を指定します。
指定方法は上記のProton.Life
と同じです。
new Proton.R()
と省略できます。
new Proton.Rate(numpan, timepan)
パーティクルを1度に発生させる個数と、発生の間隔を指定します。
numpan
とtimepan
はそれぞれProton.Life
のように指定します。ただ少しだけ方法が違い、Proton.getSpan(a, b, c)
というものを使って指定します。具体的にはこんな感じです。
// 発生個数: 10~20, 発生間隔: 0.1~0.25
var rateEx1 = new Proton.Rate(Proton.getSpan(10, 20), Proton.getSpan(.1, .25));
// 発生個数: 4 or 8 or 16 or 32, 発生間隔: 0.5
var rateEx2 = new Proton.Rate([4, 8, 16, 32], .5);
// 発生個数: 5~15, 発生間隔: 0.2
var rateEx3 = new Proton.Rate(new Proton.Span(10, 5, true), .2);
emitter.rate = rateEx1;
この子だけ特殊で、エミッターのaddInitialize()
ではなくrate
プロパティに渡してあげます。
rateEx2のように数や配列で指定したり、rateEx3のようにProton.getSpan()
ではなくnew Proton.Span()
を使っても同じ表現ができます。
また、Proton.Life
などもこのSpanを利用できます。
var lifeEx5 = new Proton.Life(Proton.getSpan(2, 4));
var lifeEx6 = new Proton.Life(new Proton.Span(1, 3));
new Proton.Velocity(rpan, thapan, type)
パーティクルの発生方向や強さを指定します。
指定方法は2種類あります。
1つ目はnew Proton.Velocity(x速度, y速度)
。
x速度とy速度をそれぞれ数か配列かSpanで指定します。
2つ目はnew Proton.Velocity(速度, 角度, 'polar')
。
速度と角度をそれぞれ数か配列かSpanで指定します。
'polar'
ではなく'p'
や'P'
と省略できます。
1つ目はxとyの速度を直接指定するのに対して、2つ目は放射状にパーティクルを発生させます。※画像上のコードは略しています。
個人的には後者の方が馴染みがあるので好きです。
new Proton.V()
と省略できます。
var velocityEx1 = new Proton.Velocity(2, 2);
var velocityEx2 = new Proton.Velocity(2, Proton.getSpan(0, 360), 'polar');
var velocityEx3 = new Proton.V(Proton.getSpan(1, 3), Proton.getSpan(-45, 45), 'p');
動きを加える「Behaviour」たち。
new Proton.Alpha(a, b, life, easing)
透明度をa
からb
に変化させます。
life
はこの動きを加え続ける時間で省略可能。デフォルトではInfinity
が設定されます。
easing
も省略可能でProton.easeLinear
がデフォルトで設定されます。
phina.jsのtweenerで使えるイージングの名前がそのまま使えます。
new Proton.A()
と省略できます。
var alphaEx1 = new Proton.Alpha(1, 0);
var alphaEx2 = new Proton.A(.8, 0, Infinity, Proton.easeInSine);
life
とeasing
はbehaviourの引数の後ろ2つに必ずありますが、全て同じなので以降は説明を省きます。
new Proton.Attraction(targetPosition, force, radius, life, easing)
パーティクルを引きつける力を加える場所を作ります。
targetPosition
には引きつける中心の座標をnew Proton.Vector2D(x座標, y座標)
で指定します。new Proton.Vector(x座標, y座標)
でもOKです。
force
とradius
はそのまま力と半径の意味で省略可能です。デフォルトでは100と1000が設定されます。
var attractionEx1 = new Proton.Attraction(new Proton.Vector2D(100, 100));
var attractionEx2 = new Proton.Attraction(new Proton.Vector(10, 10), 15, 300);
new Proton.Collision(emitter, mass, callback, life, easing)
パーティクルに衝突判定を追加します。
emitter
にエミッターを指定します。mass
とcallback
は省略可能です。
mass
にはtrue
orfalse
で指定します。デフォルトではtrue
でパーティクルの質量が影響しますが、false
にすると質量に影響しなくなります。
callback
には衝突が起きた時にコールバックする関数を指定します。
var collisionEx1 = new Proton.Collision(emitter);
var callback = function(particle) {
particle.radius += 0.1;
};
var collisionEx2 = new Proton.Collision(emitter, false, callback);
new Proton.Color(color1, color2, life, easing)
color1
からcolor2
に色を変化させます。
色は16進数カラーコード(#は省略可能)か、ランダムな色になる'random'
が使えます。
複数の色を指定したい場合は配列を使い、color1
のみ指定した場合は単色になります。
var colorEx1 = new Proton.Color('#ffff00', '#ff0000');
var colorEx2 = new Proton.Color(['ffffff', 'ffff00'], 'random');
var colorEx3 = new Proton.Color('00ffff');
new Proton.CrossZone(zone, crossType, life, easing)
パーティクルの行動可能な範囲を指定します。
zone
にはZoneで範囲を指定します。
crossType
には'dead'
か'bound'
か'cross'
を指定します。デフォルトはdead
です。
dead
はZoneの外に出たらパーティクルが消えます。
bound
はZoneの端でパーティクルが跳ね返るようになります。
cross
はZoneの端から出ると反対の端から出てきます。(RectZoneのみ対応)
var zone = new Proton.RectZone(0, 0, canvas.width, canvas.height);
var crossZoneEx1 = new Proton.CrossZone(zone, 'bound');
new Proton.Force(fx, fy, life, easing)
パーティクルに力を加えます。
fx
とfy
にそれぞれの方向の力を数で指定します。
new Proton.F()
と省略できます。
var forceEx1 = new Proton.Force(2, 0);
var forceEx2 = new Proton.F(-3, 2, Infinity, Proton.easeInSine);
new Proton.Gravity(g, life, easing)
パーティクルに重力を加えます。
g
に重力の強さを数で指定します。
new Proton.G()
と省略できます。
var gravityEx1 = new Proton.Gravity(1);
var gravityEx2 = new Proton.G(5, Infinity, Proton.easeInSine);
new Proton.GravityWell(centerPointopt, force, life, easing)
パーティクルに拡散させるような力を加える場所を作ります。
GravityWellは「重力井戸」という意味のようですが、よく分かりませんでしたw
centerPoint
にはProton.Vector2D
で位置を指定します。
force
は省略可能で、デフォルトで100が設定されます。
var gravityWellEx1 = new Proton.GravityWell(new Proton.Vector2D(10, 10));
var gravityWellEx2 = new Proton.GravityWell(new Proton.Vector(10, 10), 20);
new Proton.RandomDrift(driftX, driftY, delay, life, easing)
パーティクルを上下左右に揺らします。
driftX
とdriftY
にそれぞれの方向の大きさを数で指定します。
delay
にも数を指定しますが、値が小さい方が頻繁に揺れるようになります。
var randomDriftEx1 = new Proton.RandomDrift(10, 0, .035);
var randomDriftEx2 = new Proton.RandomDrift(0, 10, .1);
new Proton.Repulsion(targetPosition, force, radius, life, easing)
パーティクルを反発させる力を加える場所を作ります。
targetPosition
にはProton.Vector2D
で位置を指定します。
force
とradius
は省略可能で100と1000がデフォルトで設定されます。
var repulsionEx1 = new Proton.Repulsion(new Proton.Vector2D(10, 10));
var repulsionEx2 = new Proton.Repulsion(new Proton.Vector(10, 10), 10, 200);
new Proton.Rotate(a, b, style, life, easing)
パーティクルを回転させます。トマピコかわいい。
指定方法は3種類あります。
1つ目はnew Proton.Rotate(始まりの回転速度, 終わりの回転速度, 'to')
。
回転速度を決めて回転させます。回転速度は数か配列かSpanで指定します。
style
には'to'
か'To'
か'_'
を、省略した場合もこの'to'
になります。
2つ目はnew Proton.Rotate(始まりの角度, 回転速度, 'add')
。
始まりの角度と回転速度を決めて回転させます。1つ目は回転速度が変化するのに対して、回転速度が固定になります。
3つ目はnew Proton.Rotate('Velocity')
。
パーティクルの移動する方向に合わせて自動で向きを変えます。
'Velocity'
ではなく'V'
や'v'
でも、全部省略してnew Proton.Rotate()
ともできます。
var rotateEx1 = new Proton.Rotate(0, [-15, 15]);
var rotateEx2 = new Proton.Rotate(Proton.getSpan(0, 360), [-3, 3], 'add');
var rotateEx3 = new Proton.Rotate('V');
new Proton.Scale(a, b, life, easing)
パーティクルの大きさをa
からb
に変化させます。
a
とb
にはそれぞれ数か配列かSpanで指定します。
var scaleEx1 = new Proton.Scale(1, Proton.getSpan(0, 1));
var scaleEx2 = new Proton.Scale(1, 0, Infinity, Proton.easeInCubic);
発生・行動範囲を決める「Zone」たち。
new Proton.CircleZone(x, y, radius)
円形のZoneを作ります。
x
とy
に円の中心の座標、radius
に円の半径を指定します。
new Proton.ImageZone(imageData, x, y, d)
画像からZoneを作ります。画像の透明ではない場所がZoneの範囲になります。
x
とy
は左上のx座標とy座標を指定します。中心ではないので注意が必要です。
d
には1以上の数を指定します。大きいほど範囲が荒くなります。省略可能でデフォルトでは2が設定されます。
imageDataの取得方法がイマイチですが、上手く動いた例を書いておきます。
var context = canvas.getContext('2d');
var image = AssetManager.get('image', 'zone').domElement;
// new Proton.Rectangle(x, y, width, height)で getImageData に必要な rect を作る
var rect = new Proton.Rectangle(0, 0, image.width, image.height);
// Proton.Util.getImageData(context, image, rect)は imageData を返してくれる関数
var imageData = Proton.Util.getImageData(context, image, rect);
var imageZone = new Proton.ImageZone(imageData, 0, 0);
new Proton.LineZone(x1, y1, x2, y2, direction)
線形のZoneを作ります。
x1
とy1
に始点の座標、x2
とy2
に終点の座標を指定します。
direction
は省略可能です。CrossZoneで利用時にcrossTypeがdeadのときのみ影響します。
線に対してパーティクルが右か下方向に来る場合に'>'
か'R'
か'right'
か'down'
を使い、左か上方向に来る場合はそれ以外('<'
か'L'
か'left'
か'up'
が良いかも)を使います。
デフォルトでは'>'
が設定されます。
new Proton.PointZone(x, y)
点のZoneを作ります。Positionでしか利用できません。
x
とy
に座標を指定します。
new Proton.RectZone(x, y, width, height)
矩形のZoneを作ります。
x
とy
に左上の座標を、width
とheight
に横幅と高さを指定します。
xとyが中心の座標ではなく、左上の座標なことに注意してください。
さいごに
Protonの使い方をまとめただけで長くなってしまったので、今回はここまでにします。
「phina.jsでエフェクトとして使う」という目標を達成できていないので、今度別の記事を書こうと思います。
Runstantに簡単なサンプルを置いておきました。
皆さんもphina.jsとProtonで遊んでみてくださいね!