こんにちは、フロントエンドエンジニアの雅(みやび)です。
以前、文具が美少女になって戦う完全新作スマートフォンゲーム「ステリアデイズ・ウィキッド」の公式サイト制作を弊社が担当させていただいたのですが、その際に...
ゲーム内のキャラクター紹介で「文具⇔美少女の切り替え機能&エフェクトアニメーション」を付けて欲しいというご依頼をいただきました。
プラグインなどを探しても上手く当てはまるようなものがなかったので、1から作成してみたところ様々なシーンで活用できそうだったので、今回は別途作成したデモを用いながらどのように実装したのかをご紹介しようと思います。
目次
今回は「卵⇔ひよこ」の切り替えでデモを作成しました。ボタンをクリックする度にパーティクルが生成され、キャラクターが相互に切り替わるというものです。
ゲームのキャラクターの切り替えには「CSS3 アニメーション」と「jQuery」を使用し、
パーティクルの実装には「pixi.js」を使用しました。
See the Pen
Hatching_completed by miyabi (@miyabi_irokoto)
on CodePen.
まずはベースを作ります。
この時点では切り替え先のひよこはscale(0)
にして非表示にしておきます。
See the Pen
Hatching_step01 by miyabi (@miyabi_irokoto)
on CodePen.
See the Pen
Hatching_step02 by miyabi (@miyabi_irokoto)
on CodePen.
まずは切り替え用のアニメーションを作成します。
.on
クラスが付与された要素には@keyframes scale-easeOutElastic
のアニメーションが実行され、
.off
クラスが付与された要素には@keyframes scale-down
のアニメーションが実行されるようにしておきます。
.content{
//(省略)
.character{
//(省略)
> div{
//(省略)
&.off{
animation: scale-down .1s ease-in forwards;
}
&.on{
animation: scale-easeOutElastic .75s ease-in forwards;
}
}
//(省略)
}
//(省略)
}
@keyframes scale-down {
0% { transform: scale(1); }
100% { transform: scale(0); }
}
@keyframes scale-easeOutElastic {
0% { transform: scale(0); }
16% { transform: scale(1.1); }
28% { transform: scale(.9); }
44% { transform: scale(1.025); }
59% { transform: scale(.975); }
73% { transform: scale(1.0125); }
88% { transform: scale(1); }
100% { transform: scale(1); }
}
次にボタンをクリックした際の処理です。
ボタンをクリックするとクリックした回数を変数に貯め、クリック数とdiv.character
内にあるdiv
要素のインデックスが等しいと.on
クラスが付与されるようにします。
それ以外のdiv
要素には.off
クラスを付与し、クリック数はdiv
要素数-1の値になると0にリセットされるようにします。
$('.js-Character_Change').each(function(){
const $this = $(this);
const $target = $this.children('.js-Character_Target');
const $switcher = $this.children('.js-Character_Switcher');
// クリック処理
let index = 0;
$switcher.on('click',function(){
// 切り替え処理
const targetLength = $target.children().length - 1;
index+=1;
if(index > targetLength){
index = 0;
}
$target.children('div').addClass('off').removeClass('on');
$target.children('div').eq(index).removeClass('off').addClass('on');
});
});
See the Pen
Hatching_completed by miyabi (@miyabi_irokoto)
on CodePen.
まずはcanvas
要素を格納するためのdiv
要素を追加します。
div.content.js-Character_Change
//(省略)
div.canvas.js-Character_Canvas
上記にて追加したdiv
要素にスタイルを追加します。
.content{
//(省略)
.canvas{
width: 500px;
height: 500px;
position: absolute;
top: -90px;
left: 50%;
transform: translateX(-50%);
z-index: -1;
}
}
//(省略)
Pixiアプリケーションを生成し、パーティクルの数と画像の設定をします。
totalParticles
でパーティクルの数を指定します。
images
は配列になっているため、必要に応じて画像を追加することもできます。
$('.js-Character_Change').each(function(){
//(省略)
const $canvas = $this.children('.js-Character_Canvas');
let canvasWidth = $canvas.innerWidth();
let canvasHeight = $canvas.innerHeight();
// アプリケーションの作成
const app = new PIXI.Application(canvasWidth, canvasHeight, {transparent : true});
$canvas.append(app.view);
// コンテナの作成
let container = new PIXI.Container();
// ステージに反映
app.stage.addChild(container);
container.x = 0;
container.y = 0;
// 表示をするパーティクルの数
let totalParticle = 50;
// 画像配列
let images = ['https://dl.dropbox.com/s/eejj0fryiojjcfw/star.png?dl=0']
//(省略)
});
キャラの切り替えで使用したクリック処理の中にパーティクル用の処理を追加します。
ボタンを押す度に先程指定したtotalParticles
の分だけ、パーティクルが生成されます。
それらパーティクルは毎フレーム毎に動き、寿命が亡くなるとコンテナから削除されるようになっています。
$('.js-Character_Change').each(function(){
//(省略)
// クリック処理
let index = 0;
$switcher.on('click',function(){
//(省略)
// パーティクル用の配列
const particles = [];
// totalParticle回数分ループ
for (let i = 0; i < totalParticle; i++) {
// パーティクルの画像設定
let n = Math.floor(Math.random() * images.length);
const particle = PIXI.Sprite.from(images[n]);
// パーティクルの中心をきめる
particle.anchor.set(0.5);
// 透明度
particle.alpha = 1;
// サイズをランダムにきめる
const max = app.screen.width * 0.000166666666667;
const size = Math.random() * max;
particle.scale.set(size);
// パーティクルの位置をcanvasの中心に
particle.x = app.screen.width / 2;
particle.y = app.screen.height / 2;
// 速度と向き
particle.vx = app.screen.width * 0.02 * (Math.random() - 0.5); // 0~1 - .5 = -.5 ~ .5;
particle.vy = app.screen.width * 0.02 * (Math.random() - 0.5);
// 寿命
particle.life = 100;
// 生成されたパーティクルの配列をpushして簡単にアクセスできるようにします
particles.push(particle);
// コンテナに反映
container.addChild(particle);
}
// アニメーションフレーム毎の処理を指定
app.ticker.add(function() {
// 画像を繰り返し処理して位置を更新する
for (let i = 0; i < particles.length; i++) {
//配列を代入
const particle = particles[i];
// 透明度
particle.alpha -= 0.01;
// 回転
particle.rotation += 0.1;
// 寿命
particle.life -= 1;
// 摩擦
particle.vx *= .98;
particle.vy *= .98;
// 速度を位置に足していく
particle.x += particle.vx;
particle.y += particle.vy;
if (particle.life <= 0) {
// コンテナから削除
container.removeChild(particle);
// 配列からも削除(i番目から1個削除)
particles.splice(i, 1);
}
}
}
});
});
以上を持って完成となります。
div.character
内にあるdiv
要素をそのまま増やすこともできます、例えば「幼虫→蛹→蝶」といったこともできます。
他にもapp.ticker
の中にparticle.tint = Math.random() * 0xFFFFFF;
と追加すれば、よりキラキラ感を演出することもできます。
弊社ではクライアント様からのご依頼に応じて最適なサービスをご提供することを心掛けております。お仕事のご相談をお考えのご担当者様がいらっしゃいましたら、お気軽に問い合わせフォームよりお問い合わせください。
CreateJS でパーティクルシステムの開発に挑戦しよう
雅(みやび)
フロントエンジニア。料理と音楽好きです。