プログラミング

進化アニメーション 後編 PHPポケモン 60

PHP PHPポケモン ポケモン
進化アニメーション 後編 PHPポケモン 60

ポケモンの進化演出

前回に続いて、ポケモンの進化演出を実装していきます。バックエンドの処理はざっと説明をしたので、今回はフロントエンド(JavaScript)側の処理を作成していきましょう。

 

進化画面は新しく設けたので、こちらにもバトル画面で使っているメッセージ用JSを作成していきます。処理自体はほとんど変わりませんが、最終処理や分岐が少し異なるため、ファイル分けしています。

 

進化画面用メッセージJS/Public/Assets/js/Evolve/message.js
/*----------------------------------------------------------
// 初期化する関数
----------------------------------------------------------*/
var supportedFlag = $.keyframe.isSupported();
// 自動メッセージ判定用
var auto_msg;
// メッセージボックスのクリック判定用
var click_flg;
 
/**
* 画面読み込み時の関数
* @function ready
* @return void
**/
var startInit = function(){
    // 現在のメッセージ
    var now = $('.result-message.active');
    if((now.length === 0) || now.hasClass('last-message')){
        doLastMsg();
        return;
    }
    doNotLastMsg();
}
 
/**
* メッセージボックスクリック時の関数
* @function click
* @return void
**/
var clickMsgBoxInit = function(){
    click_flg = true;
    // 変数をリセット
    auto_msg = false;
    $('.action-message-box').on('click', async function(){
        if(click_flg === false) return;
        $(".message-scroll-icon").hide();
        // メッセージボックスを処理終了まで無効化
        click_flg = false;
        // 現在のメッセージ
        var now = $('.result-message.active');
        await actionMsgBox(now);
        // 次がオートメッセージの場合は再度実行
        while(auto_msg){
            now = now.next();
            await actionMsgBox(now);
        }
        // メッセージボックスを有効可
        click_flg = true;
    });
}
 
/**
* 進化キャンセルボタン
* @function click
* @return void
**/
var clickCancelEvolveInit = function(){
    $('#cancel-evolve').on('click', async function(){
        // 自身のボタンを非表示化
        $(this).hide()
        // アニメーションの強制終了(コールバックを無効化)
        $('#pokemon-before').resetKeyframe(function(){});
        $('#pokemon-before').css('opacity', 1);
        await nextMsg($('.result-message.active'));
        // cancelボタンで発火しないように1秒後にメッセージボックスを有効可
        setTimeout(function() {
            click_flg = true;
        }, 1000);
    });
}
 
/*----------------------------------------------------------
// 処理内で呼び出す関数
----------------------------------------------------------*/
/**
* メッセージアクション
* @param now element
* @return Promise
**/
var actionMsgBox = function(now){
    return new Promise( async (resolve, reject) => {
        // 最終メッセージかどうか確認
        if((now.length === 0) || now.hasClass('last-message')){
            await doLastMsg();
        }else{
            // メッセージにアクションがセットされていれば実行
            switch (now.data('action')){
                // ==============================================
                // 進化アニメーション ===========================
                //
                case 'evolve':
                $('#cancel-evolve').show()
                await evolvePokemon();
                break;
                // ==============================================
                // 進化キャンセル ===============================
                //
                case 'cancel':
                $('#remote-form-action').val('cancel');
                $('#remote-form').submit();
                break;
            }
            // 次のメッセージへ
            await nextMsg(now);
        }
        resolve();
    });
}
 
// ==============================================
// 進化演出 =====================================
//
/**
* 5秒間の進化アニメーション
* @param mixed param
* @return Promise
**/
var evolvePokemon = function(param){
    return new Promise ((resolve, reject) => {
        var keyframe = {};
        var per = 100;
        var opacity = 1;
        while (per) {
            if(opacity){
                keyframe[per + '%'] = {opacity: 0};
                opacity = 0;
            }else{
                keyframe[per + '%'] = {opacity: 1};
                opacity = 1;
            }
            per -= 3;
            if(per < 0){
                per = 0;
            }
        }
        keyframe['0%'] = {opacity: 1};
        keyframe.name = 'evolve-animation';
        // キーフレームの用意
        $.keyframe.define(keyframe);
        // 経験値バーのアニメーション
        $('#pokemon-before').playKeyframe({
            name: 'evolve-animation',
            duration: '5000ms',
            timingFunction: 'ease',
            delay: '0s',
            iterationCount: 1, // 繰り返し回数
            direction: 'normal',
            fillMode: 'forwards',
            complete: function(){
                $('#cancel-evolve').hide()
                $('#remote-form-action').val('evolve');
                $('#remote-form').submit();
            }
        });
    });
}
 
// ==============================================
 
/**
* 次のメッセージへ移行する処理
* @param now element
* @return Promise
**/
var nextMsg = function(now){
    return new Promise( async (resolve, reject) => {
        // 現在のメッセージのactiveを解除
        now.removeClass('active');
        // 次のメッセージにactiveを付与
        var next = now.next();
        next.addClass('active');
        /**
        * メッセージのステータスに合わせた分岐
        **/
        // 最終メッセージかどうかの判別
        if(next.hasClass('last-message')){
            // 最終メッセージ
            await doLastMsg();
        }else{
            // 最終メッセージではない
            doNotLastMsg();
        }
        // 次のメッセージがオートメッセージかどうかの判定
        if(next.data('auto')){
            auto_msg = true;
        }else{
            auto_msg = false;
        }
        // 処理終了
        resolve();
    });
}
 
/**
* 最終メッセージの処理
* @return void
**/
var doLastMsg = function(){
    // スクロールアイコンを非表示
    $('.message-scroll-icon').hide();
    // 終了
    $('#remote-form-action').val('');
    setTimeout(function() {
        $('#remote-form').submit();
    }, 500);
}
 
/**
* 最終メッセージではない場合の処理
* @return void
**/
var doNotLastMsg = function(){
    // スクロールアイコンを表示
    $('.message-scroll-icon').show();
}
 
/*----------------------------------------------------------
// 初期化
----------------------------------------------------------*/
jQuery(function($){
    startInit();
    clickMsgBoxInit();
    clickCancelEvolveInit();
});

 

それでは、1つずつ処理を見ていきましょう。

 

点滅処理

まずは進化時の点滅処理についてです。ピカチュウがライチュウに進化する場合、ピカチュウが点滅してライチュウがチラチラと見えている状態になりますね。これをCSSで演出するには、ライチュウの画像にピカチュウを重ね、ピカチュウの透明度を0→1とループさせることで演出ができます。

ただ、ピカチュウはgif画像のため背景がなく、ただ重ねただけでは標準状態でライチュウが見えてしまいます。そうならないためにも、ピカチュウの背景色を白にして、paddingを大きめに設定することで、後ろに用意されているライチュウを隠します。

 

進化画面(/Resources/Pages/Evolve.php
<figure class="position-relative d-inline-block">
    <img
    src="/Assets/img/pokemon/dots/front/<?=$pokemon->getAfterClass()?>.gif"
    alt="進化先"
    class="bg-white p-5">
    <img
    id="pokemon-before"
    src="/Assets/img/pokemon/dots/front/<?=get_class($pokemon)?>.gif"
    alt="<?=$pokemon->getName()?>"
    class="position-absolute bg-white p-5"
    style="left:0;top:0;">
</figure>

 

点滅処理はキーフレームで行いますが、こちらはHPバーと同じくjQueryのKeyframeライブラリを使用してセットしています。

// ==============================================
// 進化演出 =====================================
//
/**
* 5秒間の進化アニメーション
* @param mixed param
* @return Promise
**/
var evolvePokemon = function(param){
    return new Promise ((resolve, reject) => {
        var keyframe = {};
        var per = 100;
        var opacity = 1;
        while (per) {
            if(opacity){
                keyframe[per + '%'] = {opacity: 0};
                opacity = 0;
            }else{
                keyframe[per + '%'] = {opacity: 1};
                opacity = 1;
            }
            per -= 3;
            if(per < 0){
                per = 0;
            }
        }
        keyframe['0%'] = {opacity: 1};
        keyframe.name = 'evolve-animation';
        // キーフレームの用意
        $.keyframe.define(keyframe);
        // 経験値バーのアニメーション
        $('#pokemon-before').playKeyframe({
            name: 'evolve-animation',
            duration: '5000ms',
            timingFunction: 'ease',
            delay: '0s',
            iterationCount: 1, // 繰り返し回数
            direction: 'normal',
            fillMode: 'forwards',
            complete: function(){
                $('#cancel-evolve').hide()
                $('#remote-form-action').val('evolve');
                $('#remote-form').submit();
            }
        });
    });
}

 

点滅処理は透明度の0→1を単純にループさせるわけではなく、0%から100%まで0→1を刻んで設定しています。PHPポケモンの場合は3%区切りです。この設定にした理由は、playKeyframeの完了コールバックで進化処理を実行させるためです。

ポケモンでは、進化演出が始まり放っておくことで進化が確定します。操作が必要なのは中断させる場合のみです。また、演出処理は中断させる判断への余裕を持たせるためにも5秒間としています。

完了コールバックでは、リモートフォームにアクションをセットしてサブミットしています。

 

進化の中断

次に進化の中断処理についてです。進化演出が始まり、5秒後には進化が確定します。それを中断させられるように、演出が始まればメッセージボックス上にキャンセルボタンを配置します。

<div class="message-box action-message-box border p-3 mb-3">
    <?php # メッセージエリア ?>
    <?php foreach($controller->getMessages() as $key => list($msg, $status, $auto)): ?>
        <?php $class = $key === $controller->getMessageFirstKey() ? 'active' : ''; ?>
        <?php $last_class = $key === $controller->getMessageLastKey() ? 'last-message' : ''; ?>
        <p class="result-message <?=$class?> <?=$last_class?> <?=$status ?? ''?>"
            data-action='<?=$responses[$status]['action'] ?? ''?>'
            data-target='<?=$responses[$status]['target'] ?? ''?>'
            data-param='<?=$responses[$status]['param'] ?? ''?>'
            data-toggle='<?=$responses[$status]['toggle'] ?? ''?>'
            data-auto='<?=$auto ?? ''?>'>
            <?=$msg?>
        </p>
    <?php endforeach; ?>
    <span class="message-scroll-icon small">【CLICK】</span>
    <button type="button" id="cancel-evolve" class="btn btn-danger" style="display:none;">進化させない</button>
</div>

 

操作パネルはメッセージボックス欄のみにしておきたかったため、今回メッセージボックス上にボタンを配置するというレイアウトにしました。

 

中断ボタンが押されれば、進化演出と送信処理を止める必要があります。なので、クリック判定でキーフレームを破棄して、事前に用意した中断時のメッセージへ進めます

 

/**
* 進化キャンセルボタン
* @function click
* @return void
**/
var clickCancelEvolveInit = function(){
    $('#cancel-evolve').on('click', async function(){
        // 自身のボタンを非表示化
        $(this).hide()
        // アニメーションの強制終了(コールバックを無効化)
        $('#pokemon-before').resetKeyframe(function(){});
        $('#pokemon-before').css('opacity', 1);
        await nextMsg($('.result-message.active'));
        // cancelボタンで発火しないように1秒後にメッセージボックスを有効可
        setTimeout(function() {
            click_flg = true;
        }, 1000);
 
    });
}

 

中断後、タイミングによっては進化先のポケモンが見えてしまっている場合があります。それを防ぐためにも、キーフレーム中断後に透明度を1に変更しています。

さらに、中断後は無効化されているメッセージボックスを有効にする必要があります。そのためにグローバル化したクリックフラグを1秒後に有効化させました。

 ※すぐに有効化させると、中断ボタンを押した判定が同時に動いているためメッセージが2つ進むという現象が起こりました。別の対策方法もありそうですが今回は簡易的にこの方法で対処しました。

 

それでは実際に、PHPポケモンの進化演出を見てみましょう。

 

進化の中断

 

進化

 

しっかり期待通りの演出がされましたね。点滅はもっと細かく抑揚がほしいところですが、今回はこれぐらいにしておきましょう。

より本家らしく再現したい人は、ぜひ挑戦してみてください。

 

まとめ

いかがだったでしょうか。

今回のPHPポケモンは「進化アニメーション・演出」についてご紹介しました。

 

検証用に、レベルが1発で上がる経験値をくれる同レベルのカメックスを用意して、さらにササッと倒せるように「つるのムチ」の威力を245まで引き上げたのですが、まさかの確定2発というカメックスの装甲の硬さ(フシギダネの攻撃の貧弱さ)がわかる結果となりました。

 

プログラミングやゲーム制作に興味がある人は、ぜひ参考にしてみてくださいね。

 

注目の記事

ピカチュウから学ぶオブジェクト指向 〜入門編〜 1
プログラミング
PHP,PHPポケモン,オブジェクト指向,ポケモン
ピカチュウから学ぶオブジェクト指向 〜入門編〜 1

オブジェクト指向とは  オブジェクト指向プログラミング https://ja.wikipedia.org/wiki/オブジェクト指向プログラミング オブジェクト指向プログラミングとは、互いに密接な関連性を持つデータとメソッドをひとつにまとめてオブジェクトとし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定...

WordPressのJSファイル読み込みで覚えておきたい便利ワザを2つ紹介します
プログラミング
jQuery,PHP,WordPress
WordPressのJSファイル読み込みで覚えておきたい便利ワザを2つ紹介します

  JSファイルを読み込むときに、deferやasyncを付与したい・・・ get_template_directory_uri()をJSファイル内で使用したい・・・   WordPressには便利な関数が沢山用意されていますが、その全てが万能だということはありません。 今回はSEO対策でも必要になるdeferやasyncをスクリプトタグに付与させる...

ポケモン図鑑編 PHPポケモン 88
プログラミング
PHP,PHPポケモン,ポケモン
ポケモン図鑑編 PHPポケモン 88

ポケモン図鑑とは ポケモンに出会ったり、仲間にしたりすると、ポケモン図鑑のデータがどんどんと埋まっていきます。PHPポケモンでもこの仕組みを実現させるために、ポケモン図鑑を作成していきましょう。   クラスによる管理 ポケモン図鑑はクラス管理をしていきます。プレイヤー1人に対して1つのポケモン図...

ブログで生活するための7つの道のり 〜収益化と拡散の方法教えます〜
ライティング
Facebook,Google AdSense,Twitter,ノマドワーク
ブログで生活するための7つの道のり 〜収益化と拡散の方法教えます〜

  ブログで生活したい   毎日数時間、ブログを書くだけで生きていける、そんな夢のような生活を実現させたいと思い描く人は多いですが、簡単なことでは有りません。 ですが、やらなければいけないことがわかっていれば、収益化するのは簡単です。   今回は「ブログで生活するための7つの道のり」をテ...

お金を生む仕組みを理解しよう【知っておきたい3つのポイント】
マーケティング
お金を生む仕組みを理解しよう【知っておきたい3つのポイント】

  どんなビジネスが儲かるのか・・・   一度はこういった悩みを持ったことがあるのではないでしょうか。 それを知るためには、どういった要素がお金を生むために作用しているのかを理解しておく必要があります。 今回は「お金を生む仕組み」について、知っておいてためになる基礎的な部分をわかりやすく...

PHPポケモン「引数メソッド実行編」デモ有り(御三家の追加)11
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「引数メソッド実行編」デモ有り(御三家の追加)11

  前回のPHPポケモンではメソッドを外部から実行できるようにコントローラー(インターフェース)を作成しました。なので、今回は引数が必要となるメソッドの実装に挑戦してみましょう。 最後にはデモページを準備しているので、気になった人はぜひ遊んでみてください。   第1回はコチラ     ...

TwitterでYouTubeのリンク付きサムネイルを表示させる方法【超実践的Webプログラミング活用法】
プログラミング
HTML,JavaScript,PHP,Twitter,YouTube
TwitterでYouTubeのリンク付きサムネイルを表示させる方法【超実践的Webプログラミング活用法】

  Twitter(ツイッター)をブログや商品、イベントの宣伝目的で使用している人は多いです。そして、そのためのマーケティング方法や戦略は数多く練られています。 今回は、その中でもYouTubeの告知をするために特化させた内容をまとめました。   一般的な方法と、プログラミングの知識(HTMLやJavascript等)があ...

ゲームバランス調整編 DateTimeクラスの活用 PHPポケモン 101
プログラミング
PHP,PHPポケモン,ポケモン
ゲームバランス調整編 DateTimeクラスの活用 PHPポケモン 101

ゲームバランスの調整 まだまだ開発途中のPHPポケモンはゲームバランスの調整がほとんどされていません。現段階では機能も揃っていない関係上、完全なゲームバランスを求めて行くことにはあまり意味がありませんが、今後調整するための役割として機能自体は作成しておこうというのが今回の目的です。   トレーナ...

カテゴリ

SEO対策 イベント デザイン ネットワーク ビジネスモデル フリーランス プログラミング マーケティング ライティング 動画編集 雑記

タグ

5G Adobe AfterEffects AI ajax amazon Animate api artisan atom Automator AWS Bluetooth CSS CVR description EC-CUBE4 ECショップ ESLint Facebook feedly foreach function Google Google AdSense Honeycode htaccess HTML IEEE 802.11ax Illustrator Instagram IoT JavaScript jQuery jQuery UI keyword LAN Laravel Linux MacBook MAMP meta MLM MySQL NoCode note OS OSI参照モデル Paypal Photoshop PHP phpMyAdmin PHPポケモン PremierePro rss SEO SEO対策 Sequel Pro Skype SNS SSH Symfony TCP/IP title Toastr Trait Twig Twitter UCC V系 WAN WebSub Wi-Fi wiki Windows WordPress XAMPP xml Xserver YouTube YouTuber Zoom アーティスト アウトプット アクセス層 アニメーション アフィリエイト イーブイ インターネット インプット エンジニア オブジェクト指向 お金配り クリック単価 クリック数 コミュニケーション能力 コロナ コンサルティング サムネイル システムエンジニア スタートアップ スタイルシート スパム データベース ディープフェイク デザイナー デザイン テレワーク ナンパ ニュース ネットワークモデル ノマドワーク バナー ピカチュウ ビジネス フィード フリーランス ブロガー ブログ プログラマー プログラミング プログラミング学習 プログラミング教育 プロトコル ホームページ制作 ポケモン マークアップ マーケティング メール リモートワーク レンダリング 三井住友 三宮 仕事依頼 児童デイ 児童デイサービス 児童発達支援 公開鍵 初心者 助成金 勉強法 営業 広告 広告収入 必勝マニュアル 放課後等デイサービス 朝活 楽天 深層学習 無線LAN 独立 神戸 福祉 秘密鍵 翻訳 自己啓発 英語 見積書 計算機 読書 起業 迷惑メール 配列 銀の弾丸 集客 雑学力