プログラミング

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プログラミングに興味がある方は、ぜひ参考にしてくださいね。

 

注目の記事

【配列とは】初心者が最短でPHPを使えるようになるための実践的な学び方
プログラミング
foreach,PHP,配列
【配列とは】初心者が最短でPHPを使えるようになるための実践的な学び方

  初心者の方、今からプログラミングを始める方、HTMLとCSSの領域から抜け出せない人たちを対象にした、PHPをできるだけ使えるようになるための方法を紹介するコーナー。 栄えある第二回は【配列編】です。   第一回を飛ばしてこのページへに来てしまい「変数って何?」というレベルの人は、第一回の【変数編...

千利休から学ぶビジネスモデルの作り方3ステップ!守破離とは
ビジネスモデル
千利休から学ぶビジネスモデルの作り方3ステップ!守破離とは

  千利休の利休道歌に以下のような記述があります。 規矩作法 守り尽くして破るとも離るるとても本を忘るな    これは武道や芸道など学びの基礎として考えられ、創造過程のベースとして用いられてきました。これはビジネスモデルを作り上げるという観点から見ても非常に重要かつ、失敗する多くの人が疎...

【無料】早起きをして神戸へ行こう!「為になる雑談朝活」
イベント
三宮,朝活,神戸
【無料】早起きをして神戸へ行こう!「為になる雑談朝活」

  朝活を実施することになりましたので、その目的な概要をまとめました。 神戸三宮での開催を予定しておりますので、もしお近くにお住まいの方で日時が会いましたらご参加ください。 土日祝辺りで週1日程度の不定期開催を予定しています。学びにつながる、けど参加しやすい雑談形式ということを主としています...

人員配置計算機〜放課後等デイサービス・児童発達支援〜
プログラミング
JavaScript,児童デイ,児童発達支援,放課後等デイサービス,福祉,計算機
人員配置計算機〜放課後等デイサービス・児童発達支援〜

最近はずっとPHPポケモン開発にかかりっきりでしたが、そろそろ「役立つもの」を作りたくなったので、思いつきで作ってみました。 もちろん「汎用性」のあるものは、既に世の中に存在しているため、ありそうでなさそうなニッチなものを攻めてみます。   そんな中、今回挑んだのは「人員配置計算機」です。 ※実際に...

画像に文字スペースを確保する簡単テクニックを3つ教えます【サムネイル作りで大活躍】
デザイン
Illustrator,Photoshop,サムネイル,バナー
画像に文字スペースを確保する簡単テクニックを3つ教えます【サムネイル作りで大活躍】

  サムネイル用の画像に文字スペースが無くて困っている・・・   せっかくいい写真が撮れたり、フリー画像が見つかったとしても、文字を配置するスペースが確保できずにせっかくのオブジェクトに重ねてしまったり、断念して別の画像を使用するようなケースはかなり多いです。 ですが、せっかく良い画像が見つ...

非公開ディレクトリ画像表示編 PHPポケモン 91
プログラミング
PHP,PHPポケモン,ポケモン
非公開ディレクトリ画像表示編 PHPポケモン 91

非公開ディレクトリの画像を表示する 今回は、β版に向けての取り組みの1つとして、表示させる画像のアクセス先を非公開ディレクトリに変更します。 現在は公開ディレクトリ(Public)内のAssetsフォルダ内に配置していますが、これをルート直下においているStorageに移動させるのが目的となります。   gifのbas...

フィールド効果技編(しろいきり) PHPポケモン 50
プログラミング
PHP,PHPポケモン,ポケモン
フィールド効果技編(しろいきり) PHPポケモン 50

フィールド効果技とは ポケモンの技の中には、ポケモンに対して状態変化や異常を与えるもの以外に、フィールド自体に効果を持たせるものがいくつかあります。PHPポケモンでは未実装ですが、そういったフィールド効果技はポケモンを交代したとしても場に効果が残り続けます。  場の状態(ポケモンwiki) https:/...

英語できたらブログで稼げる 【ネオコピペ】
ライティング
ブログ,翻訳,英語
英語できたらブログで稼げる 【ネオコピペ】

  2010年に楽天が社内公用語の英語化を宣言したのは、多くの人が耳にしたことがあるでしょう。 私からすると、「英語ができることは強み」だという考えから、「これからは英語ができないと行きていけないのでは?」と考えを変えさせられるような、そんな出来事でした。   多言語できるデメリットを見つけるのは難...

カテゴリ

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