TypeScriptのクラスをドラクエ風のステータスを実装しながら学んでみた

## はじめに

- `npm: 6.13.7`
- `node: 13.8.0`
- `TypeScript: 3.8.2`

TypeScript 学習のため、ドラクエ風のステータス出力をクラスで実装してみました。

- ステータス

```
HP:  体力
ATK: 攻撃力
DEF: 防御力
```

今回はステータスの出力までですが、次の機会はダメージ計算なども追加して実際にバトルをさせてみたいと思います。

## TypeScript のクラスについて

- 完成

```dorakue_style.ts

class Brave {
  name: string;
  hp:   number;
  atk:  number;
  def:  number;

  constructor(name: string, hp: number, atk: number, def: number) {
    this.name = name;
    this.hp   = hp;
    this.atk  = atk;
    this.def  = def;
  }

  info() {
    return `${this.name}のHPは${this.hp}、攻撃力は${this.atk}、防御力は${this.def}です。`
  }
}

class Monster extends Brave {
  constructor(name: string, hp: number, atk: number, def: number) {
    super(name, hp, atk, def);
  }
}

let brave = new Brave("勇者", 100, 20, 10);
let slime = new Monster("スライム", 10, 2, 1);

console.log(brave.info());
console.log(slime.info());


```

- 実行結果

```bash
$ tsc dorake_style.ts
$ node dorake_style.js
> 勇者のHPは100、攻撃力は20、防御力は10です。
> スライムのHPは10、攻撃力は2、防御力は1です。
```

TypeScript のクラスを使って「勇者」と「モンスター（スライム）」のステータスを表示しています。

<br>

### 勇者を作る（クラス宣言）

```ts
// クラスを宣言
class Brave {
  // ステータスに必要なプロパティを用意
  name: string;
  hp:   number;
  atk:  number;
  def:  number;

  //...
}
```

まずはクラスを定義します。「**勇者**」を作成するため`Brave`クラスとし、ステータスに必要なプロパティを用意します。

<br>

### コンストラクタ
コンストラクタは、`Brave`クラスが`new`されたときに実行されるメソッド。

```ts
class Brave {
  // ...

  // クラスが new されたときに、実行される
  constructor(name: string, hp: number, atk: number, def: number) {
    // new のときに渡された値がそれぞれ代入
    this.name = name;
    this.hp   = hp;
    this.atk  = atk;
    this.def  = def;
  }
}

let brave = new Brave("勇者", 100, 20, 10);
console.log(brave.name); // 勇者

```

`new Brave(名前, HP, ATK, DEF)`の際に値を渡すことでコンストラクタが実行され、渡された値がそれぞれ代入されます。


<br>

## モンスターを作るために`Brave`クラスを継承する
ドラクエの定番であるモンスターのスライムを作っていきます。
スライムも勇者と同様のステータスを持つため、`Brave`クラスをベースに継承を使って`Monster`クラスを作っていきます。


```ts
// Brave クラスをベースに Monster クラスを作成
class Monster extends Brave {
  // 独自にプロパティを定義しなくていい

  constructor(name: string, hp: number, atk: number, def: number) {
    // super(); は継承元のコンストラクタを実行する
    super(name, hp, atk, def);
  }
}
```

<br>

`class Monster extends Brave`とすることで、`Brave`クラスをベースに`Monster`クラスが作成され、`Monster`クラスは`Brave`クラスを継承することで、独自にプロパティを定義する必要がなくなります。


<br>

`super()`は`Monster`クラスの継承元である`Brave`クラスのコンストラクタを実行します。
```ts
super(name, hp, atk, def);
```

<br>

### ステータスを出力

```ts
class Brave {
  // ...

  info() {
    return `${this.name}のHPは${this.hp}、攻撃力は${this.atk}、防御力は${this.def}です。`
  }
}

let brave = new Brave("勇者", 100, 20, 10);
let slime = new Monster("スライム", 10, 2, 1, 15);

console.log(brave.info());
// 勇者のHPは100、攻撃力は20、防御力は10です。
console.log(slime.info());
// スライムのHPは10、攻撃力は2、防御力は1です。
```


`Brave`クラスにステータスを出力する処理を記述して、インスタンス化したそれぞれから`info()`を呼び出します。
`Monster`クラスは`Brave`クラスを継承しているため、`info()`を呼び出すことができます。


<br>

- 完成

```ts
class Brave {
 name: string;
 hp:   number;
 atk:  number;
 def:  number;

 constructor(name: string, hp: number, atk: number, def: number) {
   this.name = name;
   this.hp   = hp;
   this.atk  = atk;
   this.def  = def;
 }

 info() {
   return `${this.name}のHPは${this.hp}、攻撃力は${this.atk}、防御力は${this.def}です。`
 }
}

class Monster extends Brave {
 constructor(name: string, hp: number, atk: number, def: number) {
   super(name, hp, atk, def);
 }
}

let brave = new Brave("勇者", 100, 20, 10);
let slime = new Monster("スライム", 10, 2, 1);

console.log(brave.info());
console.log(slime.info());
// 勇者のHPは100、攻撃力は20、防御力は10です。
// スライムのHPは10、攻撃力は2、防御力は1です。
```



<br>

### 参考

[TypeScript初心者が知っておくと嬉しいこと | Qiita](https://qiita.com/kotaonaga/items/13bec787769d6e8efc52)
[TypeScript ハンドブック](https://www.typescriptlang.org/docs/handbook/basic-types.html)