2020年1月10日金曜日

[Enchant.js]Granim.jsを利用してマ〇オの無敵状態(スターの状態)みたいな虹色グラデーションをつくる


はい、こんにちは。
@CortanMathです。


少し遅れましたが、あけましておめでとうございます。



僕は今年(去年?)年賀状代わりにこんなものを作りました。
Enchant.jsを使用した横スクロールゲームになっています。





一応こちらにリンク張っておきます。

http://kumakuma.life.coocan.jp/ShiraoAkeome/

上のはバージョン1になります。



で、こっちがバージョン2。

http://kumakuma.life.coocan.jp/ShiraoAkeome2/

何が違うがおわかりいただけたでしょうか。




答えは無敵状態機能です。

以前のバージョンでは、1倍速⇒2倍速⇒8倍速という感じにスクロールスピードを上げ、難易度を高めていたのですが、さすがに8倍速は無理がありまし た。

ということで、いのししを5回倒すと永遠に無敵状態に入るようなアップデートを行いました。
(ゲームとしての仕様に問題があることに関してはアップデートされませんでした。)


実際に完成したものがこんな感じになっています。
無敵状態は動画の後半の方です。



でこれをつくるにあたって課題となったのが、マ〇オの無敵状態みたいにキラキラ光らせる処理で す。



無敵状態なったとき敵に当たったらその敵を倒すという処理は、フラグの変数を使用すれば割と簡単に実現できます。


ただ、この無敵状態を表すため、プレイヤーを虹色にするという処理に悩みました。




いろいろ調べた結果、Granim.jsというライブラリを使用することに決めました。



Granim.jsについて



今回使用するGranim.jsというのは、いろいろな色のグラデーションをアニメーションさ せることのできるJavaScriptライブラリです。



公式サイトにデモやソースコードが載っているので、そちらを見た方が理解がはやいと思います。



公式サイト:
https://sarcadass.github.io/granim.js/index.html


デモページ:
https://sarcadass.github.io/granim.js/examples.html



見てるだけでも、結構面白いです。



使い方は簡単で、以下のページからGranim.js本体をダウンロードし、HTMLファイルから読み込むだけです。

https://github.com/sarcadass/granim.js/releases


解凍したうちの「dist」フォルダ内に「granim.js」「granim.min.js」があると思います。


どちらか一方(どちらでもよい。minは圧縮されたファイルになっていて少し容量が少ない。)をコピーして使う感じですね。


公式サイトにサンプルコードがいろいろ載っているので、迷うことはあまりないと思います。


現在(この記事執筆時)の最新バージョンはv2.0.0です。


実際に無敵状態にする



では実際にやってみましょう。


まずは、Enchant.jsとGranim.jsをHTMLから読み込みます。


<script type="text/javascript" src="./js/lib/enchant.min.js"></script>
<script type="text/javascript" src="./js/lib/granim.min.js"></script>


今回はどちらも、minとなっている方(軽量化タイプ)を選びました。

ファイルのパスは各自のフォルダ構造に合わせて設定してください。



次にJavaScriptの方を書いていきます。

Enchant.jsを使用しますので、詳しい全体のコードの書き方などは、Enchant.jsのサイトを参考にしてください。

今回は無敵処理部分のみ載せておきます。



ちょっと長いです。


    //無敵状態画像
    var player_surface = new Surface(360, 180);

    var tmpCanvas = document.createElement('canvas');
    tmpCanvas.width = 360;
    tmpCanvas.height = 180;

    document.body.appendChild(tmpCanvas);
    tmpCanvas.style.visibility = 'hidden';

    var granimInstance = new Granim({
        element: tmpCanvas,
        direction: 'left-right',
        opacity: [1, 1],
        states: {
            "default-state": {
                gradients: [
                    ['#EB3349', '#F45C43'],
                    ['#FF8008', '#FFC837'],
                    ['#4CB8C4', '#3CD3AD'],
                    ['#24C6DC', '#514A9D'],
                    ['#FF512F', '#DD2476'],
                    ['#DA22FF', '#9733EE']
                ],
                transitionSpeed: 100
            }
        }
    });

    var mask = new Image();
    mask.src = './img/player.png';

    var invincibleDraw = function () {
        player_surface.context.globalCompositeOperation = 'source-over';
        player_surface.context.drawImage(tmpCanvas, 0, 0);
        player_surface.context.globalCompositeOperation = 'destination-in';
        player_surface.context.drawImage(mask, 0, 0);
    };

    mask.onload = function () {
        invincibleDraw();
    };


    var player = new Sprite(120, 180);
    player.image = game.assets['./img/player.png'];
    player.y = 120;
    main.addChild(player);


まず前提として、プレイヤーの画像はこんな感じになっていて、アニメーション用に3パターンが あります。
これらは、360×180の1つの画像にまとまっていまして、一つのパターンあたり120×180のサイズになっています。



上に乗せたコードは、メインシーン読み込み時に一度だけ実行されるものです。

player_surfaceというのは、無敵状態の画像を入れておく Surface(Canvasをラップしたもの)です。



大まかな流れとしては、

player_surfaceに無敵用のキラキラ画像を生成しておく。

通常時はplayerのスプライトの画像として、直接元の画像ファイルを指定しておく。

無敵状態に入った場合、playerのスプライトの画像を、player_surfaceに切り替える。


という感じですね。


スプライト自体は、120×180にし、サーフェイスの方はアニメーションの切り替えのため360×180にしてあります。

また、フレームの切り替えは、ここには載せていませんが、onenterframeの部分に書いてあります。




で、ここからが今回の本題となります。

どうやって、虹色画像を生成するかです。



Granim.jsではキャンバスを指定し、そこに虹色のグラデーションを生成することができます。

ということで今回は、360×180の一時的なキャンバスを生成し、bodyに追加後(追加しないと正しく動作しませんでした。)、非表示にしていま す。

あくまで、プレイヤーの全体の画像と同じサイズの虹色グラデーションを作り、画面上では見えないようにしているだけです。

ちなみに、このグラデーションは勝手にアニメーションされます。



granimInstanceというのが、実際にグラデーションを生成している部分ですね。



elementに描画するキャンバスを指定しています。


本来はCSSセレクタで指定するようです。
なので、一時的なキャンバスにidを設定し、element部分に「#id名」と指定してみましたが、うまく動きませんでした。


なぜか、キャンバスの変数を指定したら動きました。



Granim.jsの詳しい使い方は、公式サイトのAPIのところを見てください。



次に進みます。



先ほど作った虹色グラデーション画像を元のプレイヤー画像でマスクし、player_surfaceに描画します。



要するに、虹色グラデーション画像のうち、キャラ画像の形の部分だけが残る画像が生成されるわけです。



ただ、これだけだと、グラデーションがアニメーションされないので、invincibleDraw関数は毎フレーム事に呼び出します。



後は、無敵状態を表すフラグを変数で用意しておき、無敵の条件が揃ったらそれをtrueにする。

それをもとに、スプライトの画像をplayer_surfaceに切り替えたり、敵を倒す処理を書いたりすればよいわけです。





Granim.jsは別に無敵処理とかじゃなくても面白く使えると思うので、ぜひ試してみてください。




ではさようなら。
またお会いしましょう。

もしよければ、LINEスタンプの方もよろしくお願いします。


https://line.me/S/sticker/7072968

無言で何かを伝えよう とする白男くん - LINE スタンプ | LINE STORE

白男くんが何もしゃべらずに、何か大事なことを伝えようとするスタンプです。


お そらくいつでも使えるLINEスタンプ集


人気の記事