プログラミング

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を理解してからの方がいいぞ   オブジェクト指向がよく分かってなくて、関数がなんとなく理解出来てたあたりで読み出して、理解を深めた一冊や。 古い本やけど、...

 

注目の記事

Laravelで生成したCookie情報をjQueryで取得する方法【JavaScript】
プログラミング
ajax,api,JavaScript,jQuery,Laravel,PHP
Laravelで生成したCookie情報をjQueryで取得する方法【JavaScript】

  今回はLaravel開発備忘録です。 ajaxでapi認証してviewに記述したhtmlデータを取得するために、cookieを使ったapi_tokenの受け渡し手順をまとめてみました。   Laravelを使った開発をしている人は、ぜひ参考にしてくださいね。     Laravel側の処理   まずはcookieにデータをセットする必要があり...

HTMLの基本設計「よくわかるSEO対策」構造化(マークアップ)編
SEO対策
HTML,SEO,マークアップ
HTMLの基本設計「よくわかるSEO対策」構造化(マークアップ)編

  HTML5がリリースされて随分経ちました。 それにより多くのタグが増え、それにより今までデザインを目的と使用されていたものが「構造化」という本来の役割を持たされるようになりました。    構造化は、目に見えにくい部分です   それぞれの役割を理解していなければ、せっかくきれいなサ...

Toastr(トースト)活用編 PHPポケモン 100
プログラミング
JavaScript,PHP,PHPポケモン,ポケモン
Toastr(トースト)活用編 PHPポケモン 100

記念すべき第100回目です!   色々考えましたが、100回目だからと言って特別な内容ではなく、いつもの流れの延長での開発進行となります。ご了承ください。 今回は、何人かのプレイユーザーの声も参考にしながら、ユーザビリティをあげるための機能追加を進めていきます。   Toastr(トースト)と...

PHPポケモン「技クラス実装編」14
プログラミング
PHP,PHPポケモン,ポケモン
PHPポケモン「技クラス実装編」14

  前回せっかくBootstrapを使って見た目を整えたにも関わらず、ビューポートの記述が抜けているという凡ミスが発覚したので修正しています。 サーセン。   今回のPHPポケモンでは本格的な技システムを実装していきます。技システムが整えば、皆さん期待のバトルシステムも間近です。セキュリティ面やファイル構成...

フリーランスの最大の敵は休日!?正しい休息の取り方教えます
フリーランス
フリーランス,独立
フリーランスの最大の敵は休日!?正しい休息の取り方教えます

  フリーランスになりたての人は、仕事のペースがわからなかったり、無理に自分へ追い込みをかけて頑張ろうとしてしまうことがあります。 毎日を仕事でいることが、フリーランスにとっての心がけや意識のあり方としては大切ですが、それをそのままの意味で実行してしまうと明らかなオーバーペースになるのは事...

ブログ運営者のための「よくわかるSEO対策」フィード編
SEO対策
atom,feedly,rss,WebSub,WordPress,xml,フィード
ブログ運営者のための「よくわかるSEO対策」フィード編

  アメブロやFC2など優れたブログサービスが存在している中、好きなデザイン、こだわった機能を求めてWordPressを選択される方も多いですね。 また、コーポレートサイトにWordPressを用いる方もいるでしょう。ただしSEO対策がしっかりとされていなければ、提供されているサービスに太刀打ちできません。  もちろん...

動画にカラオケテロップを入れる編集方法【AfterEffectsで色変わりの文字】
動画編集
Adobe,AfterEffects
動画にカラオケテロップを入れる編集方法【AfterEffectsで色変わりの文字】

  動画に声と同じタイミングでテロップを入れたい カラオケのような文字はどうやっていれればいいの?   一見簡単に見えるものも、いざ導入しようとすればどうやればいいかわからない、そんなこと多いのではないでしょうか? 今回はAdobe AfterEffectsを使った方法をご紹介します。些細な編集が動画のク...

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

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

カテゴリ

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