株式会社イロコト株式会社イロコト

Blogイロコトのブログ

  1. Home
  2. Blog
  3. アニメ/ゲーム系のサイトで活用しやすいキャラクターの切り替え&パーティクルアニメーションを作った

アニメ/ゲーム系のサイトで活用しやすいキャラクターの切り替え&パーティクルアニメーションを作った

2020.04.06
2023.02.21
  • コーディング

こんにちは、フロントエンドエンジニアの雅(みやび)です。

 

以前、文具が美少女になって戦う完全新作スマートフォンゲーム「ステリアデイズ・ウィキッド」の公式サイト制作を弊社が担当させていただいたのですが、その際に...

 

ゲーム内のキャラクター紹介で「文具⇔美少女の切り替え機能&エフェクトアニメーション」を付けて欲しいというご依頼をいただきました。

 

プラグインなどを探しても上手く当てはまるようなものがなかったので、1から作成してみたところ様々なシーンで活用できそうだったので、今回は別途作成したデモを用いながらどのように実装したのかをご紹介しようと思います。

 

 

完成デモ

今回は「卵⇔ひよこ」の切り替えでデモを作成しました。ボタンをクリックする度にパーティクルが生成され、キャラクターが相互に切り替わるというものです。

ゲームのキャラクターの切り替えには「CSS3 アニメーション」と「jQuery」を使用し、
パーティクルの実装には「pixi.js」を使用しました。

 

See the Pen
Hatching_completed
by miyabi (@miyabi_irokoto)
on CodePen.

 

 

1. ベースを作る

まずはベースを作ります。
この時点では切り替え先のひよこはscale(0)にして非表示にしておきます。

 

See the Pen
Hatching_step01
by miyabi (@miyabi_irokoto)
on CodePen.

 

 

2. キャラクターの切り替え機能を作る

 

See the Pen
Hatching_step02
by miyabi (@miyabi_irokoto)
on CodePen.

 

CSS(SCSS)

まずは切り替え用のアニメーションを作成します。
.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); }
}

 

JavaScript

次にボタンをクリックした際の処理です。

ボタンをクリックするとクリックした回数を変数に貯め、クリック数と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');
  });
});

 

3. パーティクルを作る

 

See the Pen
Hatching_completed
by miyabi (@miyabi_irokoto)
on CodePen.

 

HTML(Pug)

まずはcanvas要素を格納するためのdiv要素を追加します。

div.content.js-Character_Change
  //(省略)
  div.canvas.js-Character_Canvas

 

CSS(SCSS)

上記にて追加したdiv要素にスタイルを追加します。

.content{
  //(省略)
  .canvas{
    width: 500px;
    height: 500px;
    position: absolute;
    top: -90px;
    left: 50%;
    transform: translateX(-50%);
    z-index: -1;
  }
}
//(省略)

 

JavaScript

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 でパーティクルシステムの開発に挑戦しよう

https://ics.media/tutorial-createjs/particle/

Contact

案件のご相談や、弊社についてのご質問など、
お気軽にご連絡くださいませ。

お問い合わせ