プログラミング

PHPポケモン「UI(Bootstrap4の導入)編」コード配布・デモ有り 13

PHP PHPポケモン ポケモン
PHPポケモン「UI(Bootstrap4の導入)編」コード配布・デモ有り 13

 

第13回のPHPポケモンは「UI編」ということで、CSSの大人気フレームワークBootstrapさんにお手伝いいただきます。

また、前回実装したレスポンス機能により進化のアクションに一部不具合が出ていたので、このあたりも合わせて修正をしながら進めていきましょう。

 

Bootstrapを導入するにあたり、今までindex.phpに書き込んでいたものを分割するため、新しくResourcesの階層を追加しています。

 

 最後にはコード配布デモページを用意しているので、ぜひ最後まで読んでからご活用ください。

  

Bootstrapの導入

 まずは見た目から見直しをしていきます。ただ、整えるためにCSSを打ち込んでいけばそれだけでかなりの量になってしまうため、前述したとおり今回は大人気CSSのフレームワーク「Bootstrap」のお力を借ります。

とはいっても、線を引いたり余白を整えたりフォームのデザインをお借りするなど、単純なクラスだけしか利用しない(予定)なので、Bootstrapを学習目的の方はその旨ご理解ください

 

出力ファイル(/index.php
# head内に記述
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">

  

ステータス詳細の常時表示化

ステータスや詳細を表示するのに、今まではアクションで選択していましたが、これらは常時確認できるに越したことはありません。なので、もし既にポケモンを選択済みであれば出力するようにしましょう。

 

出力ファイル(/index.php
<?php if(isset($controller->pokemon)): ?>
    <section>
        <div class="row">
            <div class="col-12 col-sm-6">
                <?php foreach($controller->pokemon->getDetails() as $key => $val): ?>
                    <dl class="row">
                        <dt class="col-4"><?=$key?></dt>
                        <?php if(is_array($val)) $val = implode(',', $val); ?>
                        <dd class="col-8"><?=$val?></dd>
                    </dl>
                <?php endforeach; ?>
            </div>
            <div class="col-12 col-sm-6">
                <?php foreach($controller->pokemon->getStats() as $key => $val): ?>
                    <dl class="row">
                        <dt class="col-4"><?=$key?></dt>
                        <dd class="col-8"><?=$val?></dd>
                    </dl>
                <?php endforeach; ?>
            </div>
        </div>
    </section>
<?php endif; ?>

 

技一覧の出力には、再度implodeを使用しています。出力結果は以下のとおりです。

 

 

 

これで選択しているポケモンの詳細がひと目で分かるようになりました。

 

 

フォームの分割 

次にフォーム部分を見直ししていきます。前回は配列として項目やメソッドを用意しましたが、増えていけば自由度が制限されてしまい、それこそ保守性が悪くなってしまうため。ファイルを分割して管理していきます。 

さらに、今までは全データをポストしていましたが、メソッドごとにフォームを用意することで解決ができるということが判明したので、こちらも合わせて実装していきます。

 

ポケモンの選択フォーム(/Resources/Parcials/Forms/select_pokemon.php
<form action=" <?=$action_path?>" method="post">
    <p>ポケモンを選択してください</p>
    <div class="input-group">
        <select class="form-control" id="select_pokemon" name="pokemon">
            <option>--選択してください--</option>
            <?php foreach($controller->getPokemonList() as $class => $pokemon): ?>
                <option value="<?=$class?>"><?=$pokemon?></option>
            <?php endforeach; ?>
        </select>
        <div class="input-group-append">
            <button type="submit" class="btn btn-primary">ゲット</button>
        </div>
    </div>
</form>

 

ニックネームの変更フォーム(/Resources/Parcials/Forms/change_nickname.php
<form action="<?=$action_path?>" method="post">
    <input type="hidden" name="action" value="setNickname">
    <div class="input-group mb-3">
      <input type="text" class="form-control" placeholder="最大5文字" name="param" aria-describedby="submit-setNickname">
      <div class="input-group-append">
          <input class="btn btn-primary" type="submit" id="submit-setNickname" value="ニックネームを変更">
      </div>
    </div>
</form>

 

経験値の取得フォーム(/Resources/Parcials/Forms/add_exp.php
<form action="<?=$action_path?>" method="post">
    <input type="hidden" name="action" value="setExp">
    <div class="input-group mb-3">
      <input type="number" class="form-control" min="1" name="param" aria-describedby="submit-setExp">
      <div class="input-group-append">
          <input class="btn btn-primary" type="submit" id="submit-setExp" value="経験値を取得">
      </div>
    </div>
</form>

 

リセットフォーム(/Resources/Parcials/Forms/reset.php
<form action="<?=$action_path?>" method="post">
    <input type="hidden" name="action" value="reset">
    <input class="btn btn-danger" type="submit" value="リセット">
</form>

 

出力用ファイル(/index.php
<?php
 
require_once(__DIR__.'/Classes/Controller.php');
 
session_start();
 
$controller = new Controller($_POST, $_SESSION);
$action_path = '/';
 
?>
 
--省略
 
<div class="col-12 col-sm-6">
    <h2 class="mb-3">メソッドの実行</h2>
    <?php if(is_object($controller->pokemon ?? null)): ?>
        <?php $_SESSION['pokemon'] = $controller->pokemon; # ポケモンのインスタンスをセッションに格納 ?>
        <?php include('Resources/Partials/Forms/change_nickname.php'); # ニックネームの変更?>
        <?php include('Resources/Partials/Forms/add_exp.php'); # 経験値の取得 ?>
        <?php include('Resources/Partials/Forms/reset.php'); # リセット ?>
    <?php else: ?>
        <?php
        // ポストとセッションをリセット
        $_POST = [];
        $_SESSION = [];
        ?>
        <?php include('Resources/Partials/Forms/select_pokemon.php'); ?>
    <?php endif; ?>
</div>

 

それぞれのフォームのアクションパス($action_path)はindex.phpで指定しています。現在はフォームの使いまわしをしていませんが、後々使い回す際に役立つために変数で管理しています。

 

それぞれにフォームを割り当てることで、パラメーターの指定が楽になりましたね。

  1. アクションが選択不要になったため、hiddenで隠しパラメーターとして用意
  2. パラメーターのメソッド判定が不要になったため、nameparamに変更

 

この仕様に合わせてコントローラー側も修正しましょう。

 

コントローラー(/Classes/Controller.php
/**
* @return void
*/
public function __construct($post, $session)
{
    if(get_parent_class($session['pokemon'] ?? null) === 'Pokemon'){
        // Pokemonのインスタンスに溜まったメッセージとレスポンスデータを初期化
        $session['pokemon']->resetMessage();
        $session['pokemon']->resetResponse();
    }
    if(isset($post['pokemon'])){
        // ポケモンをゲットした
        $this->checkPokemon($post['pokemon']);
    }
    if(isset($post['action'])){
        // アクションを選択した
        $this->pokemon = $session['pokemon'] ?? null; # 更新時エラー回避用にnullをセット
        // アクションメソッドの実行
        $this->action($post['action'], $post['param'] ?? null);
    }
}
 
--省略
 
/**
* アクション
*
* @param string $action(method_name)
* @param mixed $param
* @return void
*/
private function action($action, $param)
{
    if($action === 'reset' || is_null($this->pokemon)){
        // 初期化
        $this->pokemon = null;
        return;
    }
    // 呼び出せるメソッドか判別
    if(is_callable([$this->pokemon, $action])){
        // メソッド実行結果を$resultに格納
        $result = $this->pokemon
        ->$action($param);
        switch ($action) {
            // 経験値の取得
            case 'setExp':
            $this->pokemon = $result;
            break;
        }
        // Pokemonクラスに溜まったメッセージを取得
        $this->setMessage($this->pokemon->getMessages());
    }else{
        $this->setMessage('このアクションは使用できません', 'error');
    }
}

 

パラメーター($param)の判別が無くなった分、簡易化することができました。表示を確認してみましょう。

 

 

  

Bootstrapのおかげで大分使いやすくなりましたUIの重要性を改めて感じます。

 

進化アクションの見直し 

次に進化アクションを一部見直したいと思います。前回の仕様で行くと「進化してもメッセージが引き継がれない」という問題がありました。なので、進化後にメッセージを引き継ぐ処理を追加します。

 

ポケモンクラス(/Classes/Pokemon.php
/**
* インスタンス作成時に実行される処理
*
* @param object|null
* @return void
*/
public function __construct($before=null)
{
    // 進化前のポケモンと一致しているかチェック
    if(is_a($before, $this->before_class ?? null)){
        // 進化した際の処理
        $this->takeOverAbility($before);
        // メッセージの引き継ぎ
        $this->setMessage($before->getMessages());
        $this->setMessage($this->name.'に進化した', 'success');
        $this->checkMove();
    }else{
        // 捕まえた際の処理
        $this->setLevel();
        $this->setDefaultExp();
        $this->setDefaultMove();
        $this->setIv();
        $this->setMessage($this->name.'をゲットした', 'success');
    }
}

 

進化メッセージの前に、進化前($before)からのメッセージを引き継ぎさせます。これで進化後にメッセージが消えてしまうという不具合を解消することができました。

 

進化前プロパティの設定

各ポケモンに割り当てていた 進化メソッド(evolve)についても少し見直しをしましょう。

evolveというメソッドはポケモン共通項目です。もちろん進化条件などは様々ですが、現状では特に分けておく必要性もないためポケモンクラスへ移動させましょう。そしてそのためには、進化先を判別できる必要があるので、各ポケモンに進化先のプロパティを用意します。リザードのクラスを例に見てみましょう。

 

リザードのクラス(/Classes/Pokemon/Lezardo.php)
/**
* 進化前(クラス名)
* @var string
*/
protected $before_class = 'Hitokage';
 
/**
* 進化後(クラス名)
* @var string
*/
protected $after_class = 'Lizardon';

※前回までは進化前のクラス用プロパティをchild_classとしていましたが、そうなると進化先のクラス用プロパティを「parent_class」とする必要があり、意味が異なってしまうため、before_classに名称変更しました

 

最終進化のリザードンやライチュウなどは不要のプロパティです。では、ポケモンクラスに移動したevolveメソッドを見直していきましょう。

 

ポケモンクラス(/Classes/Pokemon.php
/**
* 進化
*
* @return Classes\Pokemon\$after_class
*/
protected function evolve()
{
    if(class_exists($this->after_class ?? null)){
        $pokemon = new $this->after_class($this);
        // 進化後のインスタンスを返却
        return $pokemon;
    }else{
        $this->setMessage('このポケモンは進化できません', 'error');
    }
}

 

進化前の判別と同じように、class_existsを使って正しい進化先かどうかを判定しています。これで各ポケモンに設定しているevolveメソッドは不要になりましたので、削除しておきましょう。

 

コードの配布

 出力用ファイルを階層分けした関係で大幅な変更が出ているので、第13回終了時点でのコードをGitHubより配布します。ぜひご活用ください。

 

デモページ

UIの変更により大分遊びやすくなったので、興味ある人はぜひデモページで遊んでみてください。

デモページ

 

まとめ

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

今回のPHPポケモンは「UIの変更(Bootstrapの導入)」についてご紹介しました。

ゲームは見た目が重要です。PHPではバックエンドの処理がメインとなるため、どうしてもJavascriptCSSの力に頼ることが多くなるでしょう。これらは状況に合わせて活用しながら、あくまでPHPでの処理をメインとして紹介していく予定です。

Webプログラミングに興味がある方は、ぜひ参考にしてくださいね。

 

注目の記事

フリーランス必見!良質案件を獲得するための3つのプロセス
フリーランス
フリーランス必見!良質案件を獲得するための3つのプロセス

  「良い案件に巡り会えない」 「なかなか仕事が受注できない」   駆け出しフリーランスや、これから独立しようと考えている人が直面する大きな悩みの1つですね。 ですが、意外にも自分でその案件自体を制限していたり、良質だった案件を自らで質を下げてしまっているというケースは少なくありません。...

レベルアップ時のステータス表示編 PHPポケモン 48
プログラミング
PHP,PHPポケモン,ポケモン
レベルアップ時のステータス表示編 PHPポケモン 48

ステータスの表示 前回経験値バーのアニメーションとレベルアップ時の動的な変更を実装しましたが、レベルアップ時に表示されるステータスの実装は先送りにしていました。なので今回はそのステータス表示を作成しましょう。   ステータスはメッセージとして返却せずに、小モーダルを起動させるという方法で対応しま...

壁技編(リフレクター・ひかりのかべ)PHPポケモン 51
プログラミング
PHP,PHPポケモン,ポケモン
壁技編(リフレクター・ひかりのかべ)PHPポケモン 51

壁技とは 前回実装した「しろいきり」と同じく、初代から実装されたフィールド効果技が存在します。それが「壁技」です。 壁(ポケモンwiki) https://wiki.ポケモン.com/wiki/壁 壁とは、バトルにおける場の状態の一種、およびその場を形成するわざの総称。わざとしては第一世代から存在するが、場の状...

放物線アニメーション編 PHPポケモン 81
プログラミング
PHP,PHPポケモン,ポケモン
放物線アニメーション編 PHPポケモン 81

ボールアニメーション 前回までに作成した捕獲判定処理を使って、ボールのアニメーションを作成します。 捕獲演出は以下の通りです。  味方側から相手に向かってボールを投げる 相手ポケモンの前でボールを開く 捕獲判定で算出した揺れ回数分ボールを揺らす   捕まえた際は、ボールの揺れをストップ...

フリーランスが打ち合わせで押さえておきたい3つのポイント【収入アップします】
フリーランス
フリーランス,営業
フリーランスが打ち合わせで押さえておきたい3つのポイント【収入アップします】

  フリーランスになれば、デザイナーやプログラマーといった制作をメインとする仕事の人でもクライアントと打ち合わせをしなければいけません。 特に独立や起業前のキャリアとして営業職に縁がなかった人からすれば、打ち合わせが苦手な人は多いはずです。   今回は、そういった営業ベタでやり方が分からない...

迷惑メールはなぜ届く?amazonや楽天を騙る悪質メールへの対処法とは
ネットワーク
amazon,スパム,メール,楽天
迷惑メールはなぜ届く?amazonや楽天を騙る悪質メールへの対処法とは

「いきなり迷惑メールが届くようになった」 「Amazonや楽天を装ったメールはどうやって見分ければいいの?」   知らない人からいきなり連絡が届いたり、登録もしていないようなサービスからメールが届けば、それは詐欺メールかも知れません。 スマホやパソコンが一般的に普及して、ネットでの買い物やサービスを利用...

くれくれ姿勢が実は起業の近道だった!相手のことを考え過ぎるとハマる落とし穴とは
雑記
フリーランス,独立,起業
くれくれ姿勢が実は起業の近道だった!相手のことを考え過ぎるとハマる落とし穴とは

  仕事ください アドバイスしてください 〇〇について教えてください   こういったくれくれ姿勢の人は多く、投げかけられた側からすると「メリットは?」と感じてしまいます。 ですが実はこのくれくれ姿勢には意外な成功の要因が隠れています。多くの自己啓発記事やツイートをする人はこの本質的なものに触...

PHPポケモン「バトルシステム編〜努力値の獲得〜」33
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「バトルシステム編〜努力値の獲得〜」33

努力値の実装 今回はポケモンのやりこみ要素の一つ、努力値システムを導入します。既に努力値の項目は「ピカチュウで学ぶオブジェクト指向」の段階で実装し、ステータス計算にも判定済みですが、肝心な「努力値を獲得する仕組み」自体は出来ていませんでした。なので、バトルシステムも終盤となったこのタイミングで...

カテゴリ

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 独立 神戸 福祉 秘密鍵 翻訳 自己啓発 英語 見積書 計算機 読書 起業 迷惑メール 配列 銀の弾丸 集客 雑学力