PHPオブジェクト指向の理解を深める〜簡単なブラウザゲーム開発〜

## はじめに
フロントエンジニアを目指してプログラミング学習をしている小林と申します。
今回は、PHPオブジェクト指向の理解を深めるためにスーパーマリオのキャラクターを元に
簡単なブラウザゲームを制作しました。
この記事ではゲームの制作過程および、PHPオブジェクト指向についての解説を行います。

<img width="1440" alt="スクリーンショット 2019-11-15 16.31.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386284/052ea95e-5ecf-41f0-3a96-f6278556ea0a.png">

## URL
リンク先: <a href="http://objective.jpn.org/">マリオのゲーム</a>

##スペック
使用言語:HTML5/CSS3/PHP
開発環境:macOS Catalina 10.15.1
バージョン管理:SourceTree
本番環境：さくらサーバー

##ゲームの概要
まず、はじめにスタート画面で「Let's play」のボタンを押すことでゲームを開始
次にゲーム画面で「▶︎攻撃する」ボタンを押すことで、画面右側にある「敵のHP」を減らすことができる。
その後、敵が攻撃を行う。
ユーザーが操作するマリオのHPを減らす。
プレイヤーは次々に攻撃を行い、より多くの敵を倒すことが目的
マリオのHPが0になった時点で、セッションを削除しスタート画面に戻る。

##オブジェクト指向
**クラス**
オブジェクト指向における設計書の役割
オブジェクト内のプロパティやメソッドをひとまとめにしたもの

**プロパティ**
オブジェクトが持っているデータをプロパティと言います。
本ゲームのモンスターと言うオブジェクトには、「名前」、「HP」、「攻撃力」といったプロパティを持っています。

**メソッド**
メソッドとはオブジェクトが持っている処理のことです。
本ゲームでは、「攻撃する」「叫ぶ」と言うメソッドを用意しています。

**インスタンス化**
インスタンスとは「実体」という意味で、プログラムでオブジェクトを実際に使う時に生み出されるものです。
クラスからオブジェクトを作ることをインスタンス化と呼ぶ。

**コンストラクタ**
クラスからインスタンスを生成する際（new を行う際）に最初に実行される関数、
それがコンストラクタです。コンストラクタは自動的に実行されます。

コンストラクタは主にインスタンスを生成するときの初期化に用いられます。

コンストラクタには引数を付けることが可能です。インスタンス生成時（new を行ったとき）にこの引数に値を設定します。

```PHP:
public function __construct($name,$hp,$img,$attackMin,$attackMax) {
    $this->name = $name;
    $this->hp = $hp;
    $this->img = $img;
    $this->attackMin = $attackMin;
    $this->attackMax = $attackMax;
}
```


```PHP:
//インスタンス生成
$player = new Player('マリオ',Character::MARIO,500,50,150);
$monsters[] = new Monster( 'クリボー',100,'img/monster01.jpeg',20,40 );
$monsters[] = new Monster( 'ノコノコ',300,'img/monster02.jpeg',20,60 );
$monsters[] = new Monster('ヘイホー',200,'img/monster03.jpeg',30,50 );
$monsters[] = new Monster('パタクリボー',400,'img/monster05.jpeg',50,80 );
$monsters[] = new Monster('パックランフラワー',150,'img/monster04.jpeg',30,60 );
$monsters[] = new Monster('ゲッソー',100,'img/monster07.jpeg',10,30 );
$monsters[] = new SpecialMonster('クッパJr',120,'img/monster06.jpeg',60,100,mt_rand(50,150) );
$monsters[] = new SpecialMonster('クッパ',180,'img/monster08.jpeg',100,200,mt_rand(60,200) );
```

##コード解説
コード全容：https://github.com/yutech941/mario_objective

上記のコードで特に重要なポイントを順番に解説します。

####クラス定数
まず始めに登場キャラクターを追加・変更する可能性を考えてクラス定数を作り保守性を高めました。
ただし、本ゲームにおいてはマリオのみ使用します。

```PHP:
class Character{
    const MARIO = 1;
    const LUIGI = 2;
    const PEACH =3;
}
```

クラス定数を用いることで、静的メンバと同様にインスタンスを生成しなくても
クラス内に定数を定義することができる。

クラス定数を使うメリットは主に以下の2点です。

**設定値を文字で扱えることで可読性を高める。**
**後で修正が必要な場合に該当箇所だけを修正することができる。**


####抽象クラス
本ゲームに登場するキャラクターは
プレイヤーのマリオ、クッパを始めとする8体の敵キャラです。
それぞれに*Playerクラス*、*Monsterクラス*を作成しています。

両者には生き物という共通点があり、共通して使用できるメンバがあります。
そこで、*Creature*という抽象クラスを作成して、Player、Monsterの子クラスに継承させています。



```PHP:
abstract class Creature{
    protected $name;
    protected $hp;
    protected $attackMin;
    protected $attackMax;
    abstract public function sayCry();

```
抽象クラスとは直接インスタンスを生成することができないクラスのことです。
必ず継承して使用する必要がある。

また、抽象クラスには「抽象メソッド」を定義することができます。
抽象メソッドとは処理内容を持たずに名前だけ定義されたメソッドです。

抽象メソッドは継承先のクラスで必ずオーバーライドする必要があります。
オーバーライドしなかった場合はエラーになります。



```PHP:
public function attack($targetObj){
        $attackPoint = mt_rand($this->attackMin, $this->attackMax);
        if(!mt_rand(0,9)){
            $attackPoint = $attackPoint *1.5;
            $attackPoint = (int)$attackPoint;
            History::set($this->getName().'のクリティカルヒット!');
        }
        $targetObj->setHp($targetObj->getHp()-$attackPoint);
        History::set($attackPoint.'ポイントのダメージ!');
    }
}
```
attackメソッドでは、引数として($targetObj)を渡せるようにしています。
こうすることで、プレイヤーがモンスターに攻撃する。
また、モンスタがープレイヤーに攻撃する場合も一つのメソッドで実現することができる。

####ポリモーフィズム

ポリモーフィズムとは異なる動作を同一操作で実現することを指します。
異なるクラスにおいても同じメソッドを使うことで実現します。

```PHP:
public function sayCry(){
    switch($this->character){
        case Character::MARIO :
            History::set('ヤッフー!!!');
            break;
        case Character::LUIGI :
            History::set('マンマミーヤ');
            break;
        case Character::PEACH :
            History::set('レッツゴー!');
            break;
    }
}
```
sayCryメソッドでは、攻撃された際に発するキャラクター3種類のキャラクターの発言を用意しています。
ここではsayCryメソッドが実行された際に自動的にキャラクターを判別し、別々の処理を行っています。

####インターフェイス

History::setのメソッドは密結合の状態にあり、実装されていることが前提となる。
そのため実行を確実にするためにインターフェイスを使ってHistoryクラスインターフェイスを実装しています。

```PHP:
interface HistoryInterface{
    public static function set($str);
    public static function clear();
}

// 履歴管理クラス
class History implements HistoryInterface{
    public static function set($str){
        $_SESSION['history'] .= $str.'<br>';
    }
    public static function clear(){
        unset($_SESSION['history']);
    }
}
```

##おわりに
本ゲームはオブジェクト指向の理解を深めることを目的として作成しました。
オブジェクト指向を理解することで、今後フレームワークを用いた開発を行う際もスムーズに行えるようにしたいと思っています。