（小学生向け・Python）クラスの基本② 継承

この記事は、岩手県八幡平市のプログラミング教室「アクセルキャンプ」の公開教材です。
[アクセルキャンプ(フリースペースプラウド)のリンク](https://freespaceproud.com)
教材の作成依頼等も承っております。ご意見等は、リンク先の問い合わせ欄からお願いします。
教材の転用・利用等は自由です  
***

アクセルキャンプがある岩手県八幡平市でも
# こなぁぁぁぁゆきぃぃぃぃぃ 
が降りましたね。心まで白く染められそうですね。。。

なにこいつクサ！って思ったZ世代キッズは、「レミオロメン 粉雪」で検索！
  
# クラスの活用の仕方を考えてみよう。  
今日勉強するのは、クラスの性質と、**継承**という、クラスの大事な考え方です。早速一つのクラスを作っていきましょう。サクッとしか先週やってないので、書き方忘れちゃったよ！という人は、見直してみましょう。  
  
```python
class Slyme:
    def __init__(self, hp, mp, attack, magic):
        self.hp = hp
        self.mp = mp
        self.attack = attack
        self.magic = magic


    def butsuri_attack(self):
        return str(self.attack) + "の物理攻撃"

    def damage(self, damage):
        self.hp  -= damage
        return str(damage) + "のダメージ 残りHP:" + str(self.hp)

```
Slyme = スライムです。このクラスを作って、弱いスライム・強いスライムや、メタルスライムなどを作っていきます。  
  
def __init__のところで、クラスで使うデータを整理する、と、先週言いましたね。今回は
>・HP  ヒットポイント=体力  
> ・MP  マジックポイント  
> ・attack  攻撃力  
> ・magic 魔法攻撃力
>
の4つが**メンバー**として使われるそうです。  
  
メソッドを見てみましょう。今回は  
>・butsuri_attack スライムが物理攻撃をする  
> ・damage スライムがダメージを受ける  
> 
の2つが用意されています。
「あれ？MPがあるのに魔法攻撃しないの？」と、気づいちゃった人。。。  

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2732489/cd197505-6950-4420-c73c-2e44b23a05c2.png)

  
その通り、後ほど追加していきます。 
  
と、その前に、せっかく作ったメソッドを使ってみましょう。**インスタンス化**,覚えてますか？yowai_slymeというスライムをうみだしてみましょう。(HP:1000, MP:500, 攻撃力:10、魔法攻撃20)そして、その弱い物理攻撃を,butsuri_attackメソッドで実行してみましょう
```python
yowai_slyme = Slyme(1000, 500, 10, 20)
print(yowai_slyme.butsuri_attack())
# 実行結果: 
# 10の物理攻撃

```  
次に、yowai_slymeにダメージを与えるdamageメソッドを、繰り返しやってみましょう。どうなるでしょう？  
  
```python
yowai_slyme = Slyme(1000, 500, 10, 20)
print(yowai_slyme.damage(100))
print(yowai_slyme.damage(100))
print(yowai_slyme.damage(100))

# 実行結果:
# 100のダメージ 残りHP:900
# 100のダメージ 残りHP:800
# 100のダメージ 残りHP:700

```  
HPがどんどん減っていますね。  
「なにそれ、普通じゃん」って言わずにちょっとまって。クラスの__
init__のコンストラクタは、インスタンス化,つまり  
yowai_slyme = Slyme()
が実行されたときに、一度だけ実行されます。そこでHPなどの初期値が決まるのですが、そこからdamageメソッドが実行されるたびに、HPが減っていきます。  
そりゃそうですよね。ダメージをくらうたびにHPが戻っていたら、意味がないですからね。  

コンストラクタのinitは、 initialize(イニシャライズ) という英語の略で。初期化という意味なんです。  
インスタンス化は、スライムを生み出して最初にステータスを与える、っていう感じの処理になります。  

  
では、練習として,弱いスライムではなく、tsuyoi_slymeをインスタンス化して、物理攻撃をしてみましょう。  
```python
tsuyoi_slyme = Slyme(3000, 1000, 500, 1000)
print(tsuyoi_slyme.bugtsuri_attack())
# 実行結果
# 500
```
  
うまく強いスライムをつくれましたか？  
  
# メタルスライムを作ってみよう。  
現在のSlymeクラスでは、物理攻撃しか行うことができません。せっかくMPもあるので、魔法攻撃をできるようにしましょう。ここで、スライムのクラスがあるのに、また最初からメタルスライムクラスを作るのはメンドクサイ！ということで、もともと作ってあるクラスを使って改良する、**継承**というテクニックを使います。  
  
### 継承サンプルコード
```python
# スライム(親)クラス
class Slyme:
    # 親クラスコンストラクタ
    def __init__(self, hp, mp, attack, magic):
        self.hp = hp
        self.mp = mp
        self.attack = attack
        self.magic = magic

    # 物理攻撃
    def butsuri_attack(self):
        return str(self.attack) + "の物理攻撃"
    
    # ダメージを受ける
    def damage(self, damage):
        self.hp  -= damage
        return str(damage) + "のダメージ 残りHP:" + str(self.hp)

# メタルスライム(子)クラス Slymeクラスを継承 
class Metal_slyme(Slyme):
    # 子クラス(メタルスライムクラス)コンストラクタ
    def __init__(self,hp, mp, attack, magic):
        super().__init__(hp, mp, attack, magic)
        
    # 魔法攻撃
    def mahou_attack(self, mp_use):
        self.mp -= mp_use
        return str(self.magic) + "の魔法攻撃 \nMPを" + str(mp_use) + "消費した"

# インスタンス化
metal_slyme = Metal_slyme(10000, 5000, 2500, 3000)
print(metal_slyme.butsuri_attack(100))
print(metal_slyme.mahou_attack(300))

# 実行結果
# 2500の物理攻撃
# 3000の魔法攻撃 
# MPを300消費した
```  

あれ？メタルスライムにbutsuri_attack書いてないのになんで動いてんの？って思った人、これこそが継承のいいところです。メタルスライムクラスを作るところで、Metal_Slyme(Slyeme) と、カッコ付きで、スライムクラスを指定していますね。コメントで書いてあるように、大元となるクラスは**親クラス**、その機能を受け継いだ新しいクラスを**子クラス**といいます.この場合は親クラスがスライムクラス、子クラスはメタルスライムクラスです。  
子クラスは、親クラスのメンバーやメソッドを使うことができます。コンストラクターを見てください。super()というのが、親クラス(スライムクラス)のことです。親クラスの__init__関数、つまりコンストラクタを使うことで、子クラスでもhp, mp, attack, magicのメンバーを使うことができます。
  
初代スライムの遺伝子は未来の子クラスたちに受け継がれていくわけですね。ｲｲﾅﾊｼﾀﾞﾅｰ ( ；∀；)
  
そして子クラスたちもただ親の七光りなわけではありません。自ら努力して、技を進化させたり、新しい技を習得したりできるわけです。メタルスライムは、新しく魔法攻撃ができるようになりました。  

このように、すでにあるクラスを利用して、新機能や別の能力を持ったクラスを作り出すことができるのです。コレを利用して、メタルスライムの他に、キングスライムや、その両方の特性を持った「キング・メタルスライム」なんていうキャラクターも作り出すことができるわけです。 
```python
class Slyme:
    # 親クラスコンストラクタ
    def __init__(self, hp, mp, attack, magic):
        self.hp = hp
        self.mp = mp
        self.attack = attack
        self.magic = magic

    # 物理攻撃
    def butsuri_attack(self):
        return str(self.attack) + "の物理攻撃"

    # ダメージを受ける
    def damage(self, damage):
        self.hp -= damage
        return str(damage) + "のダメージ 残りHP:" + str(self.hp)


# メタルスライム(子クラス1)
class Metal_slyme(Slyme):
    # 子クラス(メタルスライムクラス)コンストラクタ
    def __init__(self, hp, mp, attack, magic):
        super().__init__(hp, mp, attack, magic)

    # 魔法攻撃
    def mahou_attack(self, mp_use):
        self.mp -= mp_use
        return str(self.magic) + "の魔法攻撃 \nMPを" + str(mp_use) + "消費した"
# キングスライム(子クラス2)
class King_slyme(Slyme):
    def __init__(self, hp, mp, attack, magic):
        super().__init__(hp, mp, attack, magic)

    def sokushi_attack(self):
        return("即死攻撃")
# メタルキングスライム(孫クラス)  メタルスライムとキングスライムの2つを継承
class Metal_king_slyme(Metal_slyme, King_slyme):
    def __init__(self, hp, mp, attack, magic):
        super().__init__(hp, mp, attack, magic)




# インスタンス化
metal_king_slyme = Metal_king_slyme(10000, 5000, 2500, 3000)
# メソッドを実行
print(metal_king_slyme.butsuri_attack())
print(metal_king_slyme.sokushi_attack())
```

実際のゲーム開発でも、クラスを使って複数のキャラクターや敵キャラなどを作成します。
「最初の方に出てきた弱い敵キャラが実は真のラスボスだった」とかってよくあるストーリーですが、全然関連性がない能力のキャラにしちゃうのも違うし、かと言ってその基本の能力をまた書き直すのもメンドクサイですよね。そういったときにクラスの継承を使えると、新たしいキャラを作れますし、同じ能力を持ったステータスの違うキャラをコピーしたりすることもできます。こういうのを「**オブジェクト指向**」といいます。

***

では来週は、コレを使って、前回作ったRPGアプリにいろんなキャラを追加していきましょう。

また来週！