継承を用いてRPGに出てくるような敵クラスを実装してみる

敵クラスを継承を用いて実装していきたいと思います。

# 基底クラス
基底クラスには全ての敵に共通するような変数、あるいは関数を実装したいと思います。

まずは変数について考えていきましょう。
ドラクエのようなRPGに出てくる敵を思い浮かべてみてください。
その敵全てに共通するようなステータスは何だと思いますか？
思いつくだけでこれくらいはあると思います。
　**・HP
　・MP
　・攻撃力
　・防御力
　・倒したときに貰える経験値
　・倒したときに貰えるお金
　・死んだかどうかの判定**
ではこれらのステータスを基底クラスに実装してみましょう。

```C++:IEnemy.h
#include "Player.h"  //プレイヤークラスの実装は省きます。

//敵クラスの基底クラス
class IEnemy{
public:
    IEnemy() {}  //コンストラクタ
    //デストラクタ
    //C++の場合、基底クラスにはvirtualが必要です。
    virtual ~IEnemy() {}
//派生クラスからアクセスできるように
//protectedにしておきます。
protected:
    int HP;               //HP
    int MP;               //MP
    int Atk;              //攻撃力
    int Def;              //防御力
    int Exp;              //経験値
    int Gold;             //お金
    bool isDeath = false; //死んだかどうか、falseで初期化しておく
public:
    Player* player        //プレイヤー
};
```
　次に関数です。敵全体に共通するとしては、**攻撃する時の処理**、**ダメージを受けた時の処理**、**死んだ時の処理**...色々ありますよね。

攻撃する時の処理ですが、敵によって色々変わってきますよね。打撃だったり、魔法を撃ったり。とりあえずここは純粋仮想関数として、派生クラスで具体的な処理を実装することにしましょう。ダメージを受けた時の処理も同様とします。
死んだ時の処理ですが、全敵共通でお金と経験値をプレイヤーが獲得する、死亡フラグをオンにする、というものにします。これらの処理は基底クラスで実装したいと思います。
他にも色々あるかと思いますが、この3つを実装していきます。
```C++:IEnemy.h
#include "Player.h"  //プレイヤークラスの実装は省きます。

//敵クラスの基底クラス
class IEnemy{
public:
    IEnemy() {}  //コンストラクタ
    virtual ~IEnemy() {}  //デストラクタ、virtualを忘れないように
    //攻撃をする処理。
    //純粋仮想関数にして、派生クラスで実装する。
    virtual void Attack() = 0;
    //攻撃を受ける処理。
    //純粋仮想関数にして、派生クラスで実装する。
    virtual void Damage(int damage) = 0;  
    //死んだ時の処理
    //こちらは全敵共通の処理にする。
    void Death()
    {
        player->AddExp(Exp);     //プレイヤーに経験値を加算する
        player->AddGold(Gold);   //プレイヤーにお金を加算する
        isDeath = true;          //死んだフラグをオンにする
    }
    //死んでるかどうか
    bool GetisDeath()
    {
        return isDeath;
    }
protected:
    int HP;               //HP
    int MP;               //MP
    int Atk;              //攻撃力
    int Def;              //防御力
    int Exp;              //経験値
    int Gold;             //お金
    bool isDeath = false; //死んだかどうか、falseで初期化しておく
    Player* player        //プレイヤー
};
```
以上が基本クラスの実装です。

# 派生クラス
まずはスライムのような敵を実装していきたいと思います。
攻撃の処理は攻撃力をそのままダメージとする通常攻撃、ダメージの処理はダメージ-防御力の値をHPから減らすものとします。

```C++:Slime.h
#include "IEnemy.h"
class Slime : public IEnemy{
public:
    Slime();
    ~Slime() {}
    Attack() override;
    Damage(int damage) override; 
private:
    
};
```

```C++:Slime.cpp
Slime::Slime() 
{
    //各種ステータスを初期化します
    HP = 10;
    MP = 0;
    Atk = 5;    
    Def = 2;
    Exp = 2;              
    Gold = 2;  
}

Slime::Attack()
{
    //プレイヤーに攻撃する！
    player->Damage(Atk);
}

Slime::Damage(int damage)
{
    //HPを減らす
    HP -= (damage - Def);
    //もし、HPが0以下なら死んだ時の処理をする
    if(HP <= 0) {
        Death();
    }
}
```

次はゴーレムのような敵を実装していきたいと思います。
攻撃する時の処理ですが、HPが半分以上なら通常攻撃だけ、半分より下ならちからため(次の攻撃の時に与えるダメージ2倍)と通常攻撃を交互にするものとします。
ダメージを受けた際の処理ですが、ダメージ-防御力をさらに2分の1したものをHPから減らすものとします。

```C++:Golem.h
#include "IEnemy.h"
class Golem : public IEnemy{
public:
    Golem();
    ~Golem() {}
    Attack() override;
    Damage(int damage) override; 
private:
    int MaxHP;                //最大HP
    bool isThikara = false;   //ちからためをしたかどうか
}
```

```C++:Golem.cpp
Golem::Golem()
{
      //各種ステータスを初期化します
    HP = 100;
    MP = 0;
    Atk = 30;    
    Def = 30;
    Exp = 50;              
    Gold = 20;  
    MaxHP = HP;
}

Golem::Attack()
{
    //HPが半分以上なら
    if(HP * 2 >= MaxHP) {
        //プレイヤーに攻撃
        player->Damage(Atk);
    }
    //HPが半分を切っていたら
    else {
        //力を溜めていたら
        if(isThikara) {
            //プレイヤーに2倍の攻撃力で攻撃
            player->Damage(Atk * 2);
            //力溜めフラグをオフ
            isThikara = false;
        }
        //溜めてなかったら
        else {
           //力溜めフラグをオン
           isThikara = true;
        }
    }
}

Golem::Damage(int damage)
{
    //受けるダメージ2分の1!
    HP -= (damage - Def) / 2;
    if(HP <= 0) {
        Death();
    }
}
```
実際にこれらのクラスを実際に使うとなると、こんな感じになる...と思います。

```C++:main.cpp
int main()
{
    //プレイヤーを作る
    Player* player = new Player;
    //エネミーの配列
    std::vector<IEnemy*> enemyList;
    //スライムが現れた！
    enemyList.push_back(new Slime);
    enemyList.push_back(new Slime);
    //ゴーレムが現れた！
    enemyList.push_back(new Golem);

　　//戦闘！
    while(true) {
        //プレイヤーの攻撃！
        player->Attack();
        //エネミーの攻撃！
        for(int i = 0; i < enemyList.size(); i++) {
            //死んでなかったら
            if(enemyList[i]->GetisDeath() == flase) {
                //攻撃！
                //SlimeやGolemクラスのAttack関数が実行される。
                enemyList[i]->Attack();
            }
        }
        .
        .
        .
    }
}

```

以上です、拙い文章でしたが最後までご覧いただきありがとうございました。