プログラミング

PHPポケモン「オートロード編(修正版)」17 おまけ:日本語化

PHP PHPポケモン ポケモン
PHPポケモン「オートロード編(修正版)」17 おまけ:日本語化

 

前回実装したオートローダーの使い方が盛大に間違っていたので、今回その間違いの説明をしながら、正しい実装方法をご紹介します。

申し訳ありません。(誠意)

  

オートロードについて(再)

 必要なタイミングで必要なファイルをrequireまたはincludeするあれです。

 

前回spl_autoload_registerの関数を使用した簡易オートローダーを作成したのですが、呼び出していないのに必要なクラスを呼び出してインスタンス化されているという現象がタイプの取得部分で起こっていたため、再度公式(PHP.net)や他の紹介記事を参考にしたところ、この関数は一度登録すれば毎回呼び出す必要が無いということが発覚しました。

※よくみればregisterってなってますからね・・・

 

ということで、前回トレイトで作成したオートローダーはなかったことにしてしっかりと理解した上で作り込んでいきます。

 

オートローダーの作成

 1度実行すれば良いのであれば、トレイトである必要はありません。なのでクラスとして作成します。

 

オートローダー(/Classes/AutoLoader.php
<?php
 
class AutoLoader
{
 
    /**
    * 検索するクラスが格納されているフォルダ
    * @return void
    */
    private $folders = [
        'Move', 'Pokemon', 'Type',
    ];
 
    /**
    * オートローダー
    *
    * @return void
    */
    public function __construct()
    {
        spl_autoload_register([$this, 'autoLoader']);
    }
 
    /**
    * コールバック用メソッド
    *
    * @return void
    */
    private function autoLoader($class_name)
    {
        // クラス名からファイルを検索
        foreach($this->folders as $folder){
            $path = __DIR__ . '/../Classes/'.$folder.'/'.$class_name.'.php';
            if(file_exists($path)){
                // 見つかった場合は読み込み実行
                require $path;
            }
        }
    }
}

 

まず、プロパティに注目しましょう。

/**
* 検索するクラスが格納されているフォルダ
* @return void
*/
private $folders = [
    'Move', 'Pokemon', 'Type',
];

 

技(Move)、ポケモン(Pokemon)、タイプ(Type)のClassesに設置した3フォルダを指定しています。もしクラスが見つからなかった際は、ここから探してくれます。もしアイテムなどが増えた際は、ここに必要フォルダを増やしていきましょう。

 

次にコンストラクタを見てみましょう。

/**
* オートローダー
*
* @return void
*/
public function __construct()
{
    spl_autoload_register([$this, 'autoLoader']);
}

 

spl_autoload_registerは処理の前半に1度だけ呼び出しておけば良いので、オートローダーのクラスをインスタンス化した時点で動くようにしました。中にはメソッドを用意して、インスタンス化→メソッド実行という手順をとっているものもありましたが、今の所一括で出来たほうが良いだろうという判断なのでこの仕様にしています。

もし、セキュリティ面や挙動がおかしくなるなど問題が発生したら、適宜修正していきます。

 

コールバック関数は、前回のように無名関数にせず、可視性がよくなるためにもメソッドへ分けて作成しました。

/**
* コールバック用メソッド
*
* @return void
*/
private function autoLoader($class_name)
{
    // クラス名からファイルを検索
    foreach($this->folders as $folder){
        $path = __DIR__ . '/../Classes/'.$folder.'/'.$class_name.'.php';
        if(file_exists($path)){
            // 見つかった場合は読み込み実行
            require $path;
            break;
        }
    }
}

 

読み込まれていないクラスを呼び出そうとしたタイミングで、spl_autoload_registerは起動して、コールバック関数の第1引数に、そのクラス名が渡されます。以下の例を見てみましょう。 

  1. オートローダーをインスタンス化

    spl_autoload_registerが登録される

  2. ピカチュウのクラスを呼び出そうとする

    ピカチュウのクラスはincludeまたはrequireされていない

  3. spl_autoload_registerが動き、コールバック関数(autoLoader)の第1引数($class_name)にPikachu(ピカチュウのクラス名)が渡される

 

上記の流れになります。

そして、コールバック関数内ではforeachを使ってプロパティに設定したフォルダから順番にピカチュウのクラスを検索させています。

 

これだけです。一度登録していれば、見つからないクラスが呼び出された時点で勝手に探してくれるというのが、前回の説明で漏れていた(というより理解できていなかった)部分です。composerの素晴らしさがわかると同時に、頼り切りだと知らないことがいっぱいだということを改めて教えられました。

namespaceを使用していない関係上、一発で該当フォルダへたどり着くことができないため、無駄な動きは発生していますが、膨大な量ではないので今回は無視します。

 

class_existsの挙動について

次に、class_existsの関数について見ていきましょう。これが今回良くも悪くも気づきをくれました。 

 

第2引数でautoloadをデフォルトでコールするかしないかを指定できます。省略すればtrueになるのでコールしてくれます。

最初は関係ないと思ってスルーしていましたが、オートローダーを実装した途端これが大きな意味を成してきました。

 

技の習得や、進化をする際にclass_existsを何度か使用しています。これは、クラスが不正なものでは無いか(または名称間違いになっていないか)を判別するぐらいで使用していたのですが、オートローダーを導入した関係上、基本的にはクラスは存在しない(読み込まれていない状態)ものをチェックすることになります。その際に、それをオートロードを実行してからチェックするかどうかというのが、class_existsの第2引数の役割です。

通常のclass_existsを使う場合、第2引数にはfalseを指定することが多いです。その理由は、基本的にはクラスは読み込んでいることが前提だからです。しかし、今回のPHPポケモンの現段階で使用しているclass_existsは、基本的に読み込んでいないクラスを探してもらうため、第2引数は省略(true)のままで進めていきます。

 

では、実際に修正箇所を見ていきましょう。

 

コントローラー(/Classes/Controller.php
/**
* @return void
*/
public function __construct($post, $session)
{
    // オートローダーの起動
    new AutoLoader();

 

まず、コントローラーの最初にオートローダーをインスタンス化します。これで、spl_autoload_registerが登録されたことになります。

※AutoLoader.phpはrequireしておいてください

 

インスタンス化トレイト(/Traits/InstanceTrait.php
<?php
 
trait InstanceTrait
{
    /**
    * インスタンス化関数
    * @param string $class_name
    * @return object
    */
    protected function getInstance($class_name)
    {
        // 存在チェックをして読み込み
        if(class_exists($class_name)){
            return new $class_name();
        }
    }
 
}

 

インスタンス化用のトレイトも、前回まではポケモンや技など種類分けをしていましたが、その必要が無くなったので簡潔なものに戻しています。

あとは、インスタンス化したい際に使用すれば、class_existsで勝手にクラスを探して読み込んでくれるという仕様です。

 

ポケモンデータの引き継ぎ

 これでタイプや技に関しては上手く行きましたが、ポケモンクラスで問題が発生しました。

今まではコントローラーで各ポケモンのクラスを読み込んでいたのですが、これをオートローダーに変更したところメソッド等が呼び出せなくなりました。原因を確認したところ、セッション内に以下のようなものが入力されていました。 

__PHP_Incomplete_Class Object

 

そもそも、インスタンスはセッションで渡すべきでは無いそうです。よくよく考えたら、セキュリティの関係からも当たり前と納得です。なので、こちらも修正します。

 

いままでは、ポケモンをインスタンス化する際に「捕まえた」「進化前」だけを判定していました。ですが、前画面から同じポケモンの引き継ぎという判定を追加しなければいけません。必要なデータだけを配列としてセッションに渡し、コントローラーの最初でその引き継ぎデータ(配列)を使って新しくポケモンをインスタンス化します。

 

ではまずポケモンクラスの修正版から見ていきましょう。

 

ポケモンクラス(/Classes/Pokemon.php
<?php

require_once(__DIR__.'/../Traits/ResponseTrait.php');
require_once(__DIR__.'/../Traits/InstanceTrait.php');
require_once(__DIR__.'/../Traits/Pokemon/SetTrait.php');
require_once(__DIR__.'/../Traits/Pokemon/GetTrait.php');
 
// ポケモン
abstract class Pokemon
{

    use ResponseTrait;
    use InstanceTrait;
    use SetTrait;
    use GetTrait;
 
    /**
    * ニックネーム
    * @var string(min:1 max:5)
    */
    protected $nickname;
 
    /**
    * 現在のレベル
    * @var integer(min:2 max:100)
    */
    protected $level;
 
    /**
    * 覚えている技
    * @var array(min:1 max:4)
    */
    protected $move = [];
 
    /**
    * 経験値
    * @var integer
    */
    protected $exp;
 
    /**
    * 個体値
    * @var array(value min:0 max:31)
    */
    protected $iv = [
        'HP' => null,
        'Attack' => null,
        'Defense' => null,
        'SpAtk' => null,
        'SpDef' => null,
        'Speed' => null,
    ];
 
    /**
    * 努力値
    * @var array
    */
    protected $ev = [
        'HP' => 0,
        'Attack' => 0,
        'Defense' => 0,
        'SpAtk' => 0,
        'SpDef' => 0,
        'Speed' => 0,
    ];
 
    /**
    * インスタンス作成時に実行される処理
    *
    * @param object|array|null
    * @return void
    */
    public function __construct($before=null)
    {
        switch (gettype($before)) {
            /**
            * 捕まえた際の処理
            * @var null $before
            */
            case 'NULL':
            $this->setLevel();
            $this->setDefaultExp();
            $this->setDefaultMove();
            $this->setIv();
            $this->setMessage($this->name.'をゲットした', 'success');
            break;
            /**
            * 前の画面からの引き継ぎ
            * @var array $before
            */
            case 'array':
            $this->takeOverAbility($before);
            break;
            /**
            * 進化した際の処理
            * @var object $before
            */
            case 'object':
            // 進化前のポケモンと一致しているかチェック
            if(is_a($before, $this->before_class ?? null)){
                $this->takeOverAbility($before);
                // メッセージの引き継ぎ
                $this->setMessage($before->getMessages());
                $this->setMessage($this->name.'に進化した', 'success');
                $this->checkMove();
            }
            break;
        }
    }
 
    /**
    * レベルアップ処理
    *
    * @return void
    */
    protected function actionLevelUp()
    {
        // レベルアップ
        $this->level++;
        $this->setMessage($this->getNickName().'のレベルは'.$this->level.'になった!', 'success');
        // 現在のレベルで習得できる技があるか確認
        $this->checkMove();
    }
 
    /**
    * 進化
    *
    * @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');
        }
    }
 
    /**
    * 現在のレベルで覚えられる技があるか確認する処理
    *
    * @var integer
    */
    protected function checkMove()
    {
        // レベルアップして覚えられる技があれば習得する
        $level_move_keys = array_keys(array_column($this->level_move, 0), $this->level);
        foreach($level_move_keys as $key){
            $move_class = $this->level_move[$key][1];
            // 覚えようとしている技(クラス)が存在かつ重複していないか
            if(class_exists($move_class) && !in_array($move_class, $this->move, true)){
                // 技クラスをセット
                $this->setMove($move_class);
                // インスタンス化
                $move = new $move_class();
                $this->setMessage($move->getName().'を覚えた!', 'success');
            }
        }
    }
 
    /**
    * 現在インスタンスを出力
    *
    * @return array
    */
    public function export()
    {
        return [
            'class_name' => get_class($this),   # クラス名
            'nickname' => $this->nickname,    # ニックネーム
            'level' => $this->level,          # レベル
            'ev' => $this->ev,                # 努力値
            'iv' => $this->iv,                # 個体値
            'exp' => $this->exp,              # 経験値
            'move' => $this->move,            # 技
        ];
    }
 
    /**
    * 進化時の能力引き継ぎ処理
    *
    * @param object $before 進化前
    * @return void
    */
    protected function takeOverAbility($before)
    {
        if(is_object($before)){
            $this->nickname = $before->nickname;    # ニックネーム
            $this->level = $before->level;          # レベル
            $this->ev = $before->ev;                # 努力値
            $this->iv = $before->iv;                # 個体値
            $this->exp = $before->exp;              # 経験値
            $this->move = $before->move;            # 技
        }elseif(is_array($before)){
            $this->nickname = $before['nickname'];    # ニックネーム
            $this->level = $before['level'];          # レベル
            $this->ev = $before['ev'];                # 努力値
            $this->iv = $before['iv'];                # 個体値
            $this->exp = $before['exp'];              # 経験値
            $this->move = $before['move'];            # 技
        }
    }
}

 

コンストラクタ内でswitchを使い、引数で受け取ったbeforeの型をgettype関数を使ってチェックしています。 

 NULL → ゲット

array → 引き継ぎ

object → 進化

 

上記3つの判定になります。ただ、分岐が多くなりすぎるのも良くないので、そろそろメソッド分けする必要がありそうですが、一旦はこのまま押し通します。

 

次に新しく追加したexportというメソッドを見てみましょう。

/**
* 現在インスタンスを出力
*
* @return array
*/
public function export()
{
    return [
        'class_name' => get_class($this),   # クラス名
        'nickname' => $this->nickname,    # ニックネーム
        'level' => $this->level,          # レベル
        'ev' => $this->ev,                # 努力値
        'iv' => $this->iv,                # 個体値
        'exp' => $this->exp,              # 経験値
        'move' => $this->move,            # 技
    ];
}

 

これは、現在のポケモンの引き継ぎ用情報を出力するためのメソッドです。これを使い、セッションに必要なデータを渡します。引き継ぎ後はクラスを呼び出す必要があるため、クラス名をget_classで取得して配列に格納しています。

 

変更が加えられた、能力の引き継ぎメソッド(takeOverAbility)についても見てみましょう。

/**
* 進化時の能力引き継ぎ処理
*
* @param object $before 進化前
* @return void
*/
protected function takeOverAbility($before)
{
    if(is_object($before)){
        $this->nickname = $before->nickname;    # ニックネーム
        $this->level = $before->level;          # レベル
        $this->ev = $before->ev;                # 努力値
        $this->iv = $before->iv;                # 個体値
        $this->exp = $before->exp;              # 経験値
        $this->move = $before->move;            # 技
    }elseif(is_array($before)){
        $this->nickname = $before['nickname'];    # ニックネーム
        $this->level = $before['level'];          # レベル
        $this->ev = $before['ev'];                # 努力値
        $this->iv = $before['iv'];                # 個体値
        $this->exp = $before['exp'];              # 経験値
        $this->move = $before['move'];            # 技
    }
}

 

前回までは進化の際にしか能力値を引き継いでいませんでしたが、今回からは画面移管でも引き継ぐ必要があるので、配列で受け取った場合の処理を追加しました。これで、どちらのパターンでも同じメソッドを使った能力の引き継ぎが可能です。

 

それではコントローラーの修正箇所(コンストラクタ)を見ていきましょう。

 

コントローラー(/Classes/Controller.php
/**
* @return void
*/
public function __construct()
{
    $post = $_POST;
    $session = $_SESSION;
    // オートローダーの起動
    new AutoLoader();
    /**
    * 初期画面
    */
    if(empty($post)){
        $_POST = [];
        $_SESSION = [];
        return;
    }
    /**
    * ポケモンが選択された
    */
    if(isset($post['pokemon'])){
        $this->checkPokemon(htmlspecialchars($post['pokemon']));
        return;
    }
    /**
    * アクションが実行された
    */
    if(isset($post['action']) && class_exists($session['pokemon']['class_name'] ?? null)){
        // 引き継いだデータを引数にポケモンをインスタンス化
        $this->pokemon = new $session['pokemon']['class_name']($session['pokemon']);
        // アクションメソッドの実行
        $this->action(htmlspecialchars($post['action']), htmlspecialchars($post['param'] ?? null));
    }
}

 

前回までは引数でpostsessionを受け取っていましたが、正直グローバルでとっても問題なさそうなので変更しました。ただ、そのままは使用せずに一度変数に格納してから使っています。

 大きく変更されたのは、アクションが実行された際の処理です。今まではそのままpokemonのプロパティに渡していましたが、class_existsでチェックしてからインスタンス化するという手順を踏んでいます。

あと追加で、申し訳程度にhtmlspecialcharsを使ってサニタイズしています。

 

コントローラーの仕様に合わせて出力画面も修正します。

 

出力画面(/index.php
<?php
 
require_once(__DIR__.'/Classes/Controller.php');
require_once(__DIR__.'/Resources/Lang/Translation.php');
 
session_start();
 
$controller = new Controller();
$action_path = '/';
 
?>
<!DOCTYPE html>
<html lang="jp" dir="ltr">
<head>
    <meta charset="utf-8">
    <title>PHPポケモン</title>
    <meta name="robots" content="noindex, nofollow" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    <link rel="stylesheet" href="Resources/Assets/css/style.css">
</head>
<body>
    <header>
        <div class="container">
            <section>
                <div class="row">
                    <div class="col-12">
                        <h1>PHPポケモン</h1>
                    </div>
                </div>
            </section>
        </div>
    </header>
    <main>
        <div class="container">
            <?php if(isset($controller->pokemon)): ?>
                <section>
                    <div class="row">
                        <div class="col-12 col-sm-6 col-md-4">
                            <?php # 詳細 ?>
                            <table class="table table-bordered table-hover">
                                <thead class="thead-light">
                                    <tr>
                                        <th scope="col" colspan="2">詳細</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <?php foreach($controller->pokemon->getDetails() as $key => $val): ?>
                                        <tr>
                                            <th scope="row" class="w-50"><?=transJp($key)?></th>
                                            <td><?=$val?></td>
                                        </tr>
                                    <?php endforeach; ?>
                                </tbody>
                            </table>
                        </div>
                        <div class="col-12 col-sm-6 col-md-4">
                            <?php # ステータス ?>
                            <table class="table table-bordered table-hover">
                                <thead class="thead-light">
                                    <tr>
                                        <th scope="col" colspan="2">ステータス</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <?php foreach($controller->pokemon->getStats() as $key => $val): ?>
                                        <tr>
                                            <th scope="row" class="w-50"><?=transJp($key)?></th>
                                            <td><?=$val?></td>
                                        </tr>
                                    <?php endforeach; ?>
                                </tbody>
                            </table>
                        </div>
                        <div class="col-12 col-sm-6 col-md-4">
                            <?php # 覚えている技 ?>
                            <table class="table table-bordered table-hover">
                                <thead class="thead-light">
                                    <tr>
                                        <th scope="col">覚えている技</th>
                                        <th scope="col">タイプ</th>
                                        <th scope="col">PP</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <?php foreach($controller->pokemon->getMove() as $move): ?>
                                        <tr>
                                            <th scope="row" class="w-50"><?=$move->getName()?></th>
                                            <td><?=$move->getType()->getName()?></td>
                                            <td><?=$move->getPp()?>/<?=$move->getPp()?></td>
                                        </tr>
                                    <?php endforeach; ?>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </section>
            <?php endif; ?>
            <section>
                <div class="row">
                    <div class="col-12 col-sm-6 mb-5">
                        <h2 class="mb-3">メソッドの実行</h2>
                        <?php if(is_object($controller->pokemon ?? null)): ?>
                            <?php $_SESSION['pokemon'] = $controller->pokemon->export(); # ポケモンの情報をセッションに格納 ?>
                            <?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 include('Resources/Partials/Forms/select_pokemon.php'); ?>
                        <?php endif; ?>
                    </div>
                    <div class="col-12 col-sm-6 mb-5">
                        <h2 class="mb-3">実行結果</h2>
                        <div class="result-box border p-3 mb-3">
                            <?php foreach($controller->getMessages() as list($msg, $status)): ?>
                                <?php if($status == 'error') $class = 'text-danger'; ?>
                                <?php if($status == 'success') $class = 'text-success'; ?>
                                <p class="<?=$class ?? ''?>"><?=$msg?></p>
                            <?php endforeach; ?>
                            <?php if(!empty($controller->getResponses())): ?>
                                <pre><?php var_export($controller->getResponses()); ?></pre>
                            <?php endif; ?>
                        </div>
                    </div>
                </div>
            </section>
        </div>
    </main>
</body>
</html>

 

 

日本語化の実装(おまけ)

 先程のindex.phpにも記述していますが、一部分だけ日本語化を実装しました。とは言っても、英語をキーとした日本語を配列として用意し、それを関数で呼び出してチェックしているだけです。

 

翻訳ファイル(/Resources/Lang/Translation.php
<?php
 
function transJp($str)
{
    $array = [
        'attack' => 'こうげき',
        'defense' => 'ぼうぎょ',
        'spatk' => 'とくこう',
        'spdef' => 'とくぼう',
        'speed' => 'ぼうぎょ',
        'name' => '正式名称',
        'nickname' => 'ニックネーム',
        'type' => 'タイプ',
        'level' => 'レベル',
        'exp' => '経験値',
        'nextlevel' => '次のレベルまで',
        'physical' => '物理',
        'special' => '特殊',
        'status' => '変化',
    ];
    // 小文字変換して配列から取得、存在しなければそのまま返却
    return $array[mb_strtolower($str)] ?? $str;
}

 

今まで日本語キーだった部分を英語に置き換え、それに合わせてtransJpという関数を呼び出す仕様です。もし技やポケモンの名前も、わざわざインスタンス化してgetNameをするのが面倒であれば、同じように用意して関数で置き換えるという方法をとっても構いません。

  

まとめ

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

今回のPHPポケモンでは、前回実装したオートローダーの不備を修正し、正しい使い方をご紹介しました。

ぜひオートローダーを使う人は、しっかり公式マニュアルや書籍を読み込んでから実装するようにしておきましょう。

パーフェクトPHP パーフェクトPHP

ワイがPHPを勉強した一冊や! というより、書籍はこれしか読んでないで! ちなみに、最初からこれに挑むとほぼ100%挫折するので、ある程度PHPを理解してからの方がいいぞ   オブジェクト指向がよく分かってなくて、関数がなんとなく理解出来てたあたりで読み出して、理解を深めた一冊や。 古い本やけど、...

 

注目の記事

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

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

ポケモンプロパティ編(全国図鑑No・捕捉率・重さ) PHPポケモン 77
プログラミング
PHP,PHPポケモン,ポケモン
ポケモンプロパティ編(全国図鑑No・捕捉率・重さ) PHPポケモン 77

PHPポケモン記事も記念すべき第77回を迎えることができ、これもひとえに皆様のお力があってのことです。いろんな方のご協力もあり(ドット絵とかドット絵とかドット絵とか)見た目はかなりゲームらしくなってきました。 しかし、肝心のゲーム要素が本家と比べればまだまだ機能も少なく未実装の項目も多いので、これ...

フレンドリィショップ編 アイテムの販売 PHPポケモン 76
プログラミング
PHP,PHPポケモン,ポケモン
フレンドリィショップ編 アイテムの販売 PHPポケモン 76

リュックの作成 前回はフレンドリィショップへ商品を並べ、計算機を作成するところまで作成しました。ですが、商品が購入できたとしても、それを保管しておくためのスペースがなければ意味がありません。 なので、プレイヤー情報に対してアイテムを格納できるように機能拡張をしましょう。   プレイヤークラス(/C...

PHPポケモン(α)攻略wiki「最初のポケモン」
雑記
PHPポケモン,wiki,ポケモン
PHPポケモン(α)攻略wiki「最初のポケモン」

リリースから一ヶ月、遂にPHPポケモン(α)の攻略Wiki(仮)が公開です!   というのは大嘘で、内部の大幅変更の関係上、今回はPHPポケモンをプレイするにあたってのオススメなどをまとめて見た次第です。 ちなみに、バトルシステム自体は本家に沿って作成しているので、種族値や技性能に精通している人はブラウザ...

記事を書いてもブログが伸びないのは何故?SEOの評価を下げてしまう絶対にダメな3つのこと【知らない内に損してます】
SEO対策
SEO,ブログ
記事を書いてもブログが伸びないのは何故?SEOの評価を下げてしまう絶対にダメな3つのこと【知らない内に損してます】

  1年ブログを継続したけど、全くPVが伸びない・・・   ブログを育てるためには、毎日または定期的な更新が必ず必要ですが、それでも思うように伸びないという人は、実は他に致命的にな原因があることがほとんどです。 今回はそういった「努力しても結果が出ない」と悩んでいるブロガーやブログ運営者に...

独立するならWordPress理解しておけばOK!プログラミングでフリーランスはこれ一つで成り立ちます
プログラミング
PHP,WordPress,フリーランス,独立
独立するならWordPress理解しておけばOK!プログラミングでフリーランスはこれ一つで成り立ちます

  プログラミングでフリーランスを目指すには、どの言語始めればいいの?   プログラミングの学習を始めたのに、それをどう活かせばよいか分からず、いざフリーランスで活動しようと思ってもイメージできずに断念してしまう人は多いです。 言語にも向き不向きがあるため、フリーランスとして活動するために向...

PHPポケモン「オートロード編(修正版)」17 おまけ:日本語化
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「オートロード編(修正版)」17 おまけ:日本語化

  前回実装したオートローダーの使い方が盛大に間違っていたので、今回その間違いの説明をしながら、正しい実装方法をご紹介します。 申し訳ありません。(誠意)    オートロードについて(再)  必要なタイミングで必要なファイルをrequireまたはincludeするあれです。   前回spl_autoload_reg...

経験値分配編 PHPポケモン 89
プログラミング
PHP,PHPポケモン,ポケモン
経験値分配編 PHPポケモン 89

経験値の分配とは 大型アップデート後、最初の追加機能は「経験値の分配」についてです。 ポケモンの入れ替えができるようになりましたが、経験値をもらえるのは現在フィニッシャーのみとなっており、レベルの低いポケモンを育てるのが困難な状態です。なので、ゲームバランスを整えるためにも、まず経験値周りの処...

カテゴリ

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