【チュートリアル】スライム50体から学ぶオブジェクト指向
~本当に手で書いて、OOPのありがたみを体感しよう~
チュートリアルの目的
このチュートリアルでは、「スライム50体を管理する」という課題を通して、オブジェクト指向(OOP)の必要性と有効性を実感します。

✅ 前提
- C#の基本構文(変数・if文・for文)を理解している
- Visual Studio または C#が動作する環境がある
🧱 Step 0. 手続き型でスライムを50体作る
プロジェクト名 Slime50Manager
🔍 目的:
「クラスを使わずに」スライムを50体管理する大変さを体験する
📝 手順:
以下のコードのように、スライム1〜10体分の変数と処理を手で書き出してください。
残りの 11〜50 体分も、同じように書き足していく前提で行います。
string name1 = "スライム1";
int hp1 = 10;
string name2 = "スライム2";
int hp2 = 12;
string name3 = "スライム3";
int hp3 = 14;
// ……省略……
string name50 = "スライム50";
int hp50 = 60;
hp1 -= 5;
hp2 -= 5;
// ……hp3~hp50も同様に
Console.WriteLine($"{name1} のHP: {hp1}");
Console.WriteLine($"{name2} のHP: {hp2}");
// ……name3~name50も同様に
💡 考察:
- 少しずつ変わる数字を1つずつ打つのがとにかく面倒。
- 「あと5体追加して」と言われたら?
- 「全スライムのHPを2倍にして」と言われたら?
🧰 Step 1. Enemy クラスを作って再設計しよう
🔍 目的:
スライムの情報と行動を1つのまとまり(クラス)にする
📝 手順:
Visual Studio に Enemy.cs を追加し、以下のクラスを作成します。
class Enemy
{
public string Name;
public int HP;
public Enemy(string name, int hp)
{
Name = name;
HP = hp;
}
public void TakeDamage(int damage)
{
HP -= damage;
if (HP < 0) HP = 0;
}
}
🧪 Step 2. Enemy を使って50体をループで作ろう
🔍 目的:
クラスとリスト、for 文を使ってスライムを効率よく量産する
📝 手順:
以下のコードを Main メソッド内に記述します。
List<Enemy> enemies = new List<Enemy>();
for (int i = 1; i <= 50; i++)
{
int hp = 10 + (i % 5) * 2; // HPにばらつき
enemies.Add(new Enemy($"スライム{i}", hp));
}
✅ 解説:
- List<Enemy> は複数のスライムを1つにまとめる箱。
- for 文で名前とHPを連番付きで自動生成。
⚔️ Step 3. まとめて攻撃、まとめて表示
🔍 目的:
繰り返し処理で一括管理する便利さを体験する
📝 手順:
foreach (var enemy in enemies)
{
enemy.TakeDamage(5);
}
foreach (var enemy in enemies)
{
Console.WriteLine($"{enemy.Name} の残りHP: {enemy.HP}");
}
💡 考察:
- たった数行で50体分の処理が完了!
- コードが短く・読みやすく・変更しやすい
🧬 Step 4. 継承とオーバーライドを試してみよう
🔍 目的:
クラスを拡張し、「種類ごとの振る舞いの違い」を作る
📝 手順:
Goblin.cs を作成して以下のように記述します。
class Goblin : Enemy
{
public Goblin(string name) : base(name, 20) {}
public override void TakeDamage(int damage)
{
Console.WriteLine($"{Name} は防御した!");
base.TakeDamage(damage - 1);
}
}
🧪 敵リストにゴブリンを追加:
enemies.Add(new Goblin("ゴブリンA"));
enemies.Add(new Goblin("ゴブリンB"));
✅ 解説:
- Goblin クラスは Enemy を継承
- TakeDamage をオーバーライドして、動きを変えた
- それでも Enemy 型として扱える → ポリモーフィズム
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Slime50Manager
{
internal class Program
{
static void Main(string[] args)
{
string name1 = "スライム1";
int hp1 = 10;
string name2 = "スライム2";
int hp2 = 12;
string name3 = "スライム3";
int hp3 = 14;
// ……省略……
string name50 = "スライム50";
int hp50 = 60;
hp1 -= 5;
hp2 -= 5;
// ……hp3~hp50も同様に
Console.WriteLine($"{name1} のHP: {hp1}");
Console.WriteLine($"{name2} のHP: {hp2}");
// ……name3~name50も同様に
List<Enemy> enemies = new List<Enemy>();
for (int i = 1; i <= 50; i++)
{
int hp = 10 + (i % 5) * 2; // HPにばらつき
enemies.Add(new Enemy($"スライム{i}", hp));
}
enemies.Add(new Goblin("ゴブリンA"));
enemies.Add(new Goblin("ゴブリンB"));
foreach (var enemy in enemies)
{
enemy.TakeDamage(5);
}
foreach (var enemy in enemies)
{
Console.WriteLine($"{enemy.Name} の残りHP: {enemy.HP}");
}
}
}
class Enemy
{
public string Name;
public int HP;
public Enemy(string name, int hp)
{
Name = name;
HP = hp;
}
public virtual void TakeDamage(int damage)
{
HP -= damage;
if (HP < 0) HP = 0;
}
}
class Goblin : Enemy
{
public Goblin(string name) : base(name, 20) { }
public override void TakeDamage(int damage)
{
Console.WriteLine($"{Name} は防御した!");
base.TakeDamage(damage - 1);
}
}
}
🔚 Step 5. まとめと振り返り
💡 手続き型との比較
観点 | 手続き型 | オブジェクト指向 |
---|---|---|
敵の数を増やす | 地獄のコピペ作業 | for 文で無限に対応 |
処理の追加 | すべてに個別で追加 | メソッドで一括処理 |
表示やダメージ処理 | 個別に1体ずつ | foreach で一括 |
拡張性 | 極めて低い | 継承・オーバーライドで高い |
📝 実践課題
ぜひ、自分の力で以下にチャレンジしてください。
- 手続き型でスライム10体を作って攻撃&表示処理を実装
- Enemy クラスを使って書き直し(リファクタリング)
- List<Enemy> と for 文で50体生成
- Goblin クラスを作成して TakeDamage をオーバーライド
- すべての敵を Enemy 型で一括管理して攻撃処理を行う
以下に、「📝 実践課題」に対応した 5つのC#サンプルコード を順を追って提示します。
すべて実行可能な形で構成されており、手続き型 → OOP → 継承・多態性へとステップアップできる流れになっています。
✅ 1. 手続き型でスライム10体を作って攻撃&表示処理を実装
string name1 = "スライム1"; int hp1 = 10;
string name2 = "スライム2"; int hp2 = 12;
string name3 = "スライム3"; int hp3 = 14;
string name4 = "スライム4"; int hp4 = 16;
string name5 = "スライム5"; int hp5 = 18;
string name6 = "スライム6"; int hp6 = 20;
string name7 = "スライム7"; int hp7 = 22;
string name8 = "スライム8"; int hp8 = 24;
string name9 = "スライム9"; int hp9 = 26;
string name10 = "スライム10"; int hp10 = 28;
// 5ダメージを与える
hp1 -= 5; hp2 -= 5; hp3 -= 5; hp4 -= 5; hp5 -= 5;
hp6 -= 5; hp7 -= 5; hp8 -= 5; hp9 -= 5; hp10 -= 5;
// 結果表示
Console.WriteLine($"{name1} のHP: {hp1}");
Console.WriteLine($"{name2} のHP: {hp2}");
Console.WriteLine($"{name3} のHP: {hp3}");
Console.WriteLine($"{name4} のHP: {hp4}");
Console.WriteLine($"{name5} のHP: {hp5}");
Console.WriteLine($"{name6} のHP: {hp6}");
Console.WriteLine($"{name7} のHP: {hp7}");
Console.WriteLine($"{name8} のHP: {hp8}");
Console.WriteLine($"{name9} のHP: {hp9}");
Console.WriteLine($"{name10} のHP: {hp10}");
✅ 2. Enemy クラスを使って書き直し(リファクタリング)
class Enemy
{
public string Name;
public int HP;
public Enemy(string name, int hp)
{
Name = name;
HP = hp;
}
public void TakeDamage(int damage)
{
HP -= damage;
if (HP < 0) HP = 0;
}
public void ShowStatus()
{
Console.WriteLine($"{Name} のHP: {HP}");
}
}
// 使用例
Enemy slime1 = new Enemy("スライム1", 10);
Enemy slime2 = new Enemy("スライム2", 12);
slime1.TakeDamage(5);
slime2.TakeDamage(5);
slime1.ShowStatus();
slime2.ShowStatus();
✅ 3. List<Enemy> と for 文で50体生成
List<Enemy> enemies = new List<Enemy>();
for (int i = 1; i <= 50; i++)
{
int hp = 10 + (i % 5) * 2;
enemies.Add(new Enemy($"スライム{i}", hp));
}
// 全員に5ダメージ
foreach (var enemy in enemies)
{
enemy.TakeDamage(5);
}
// 結果表示
foreach (var enemy in enemies)
{
enemy.ShowStatus();
}
✅ 4. Goblin クラスを作成して TakeDamage をオーバーライド
class Goblin : Enemy
{
public Goblin(string name, int hp) : base(name, hp) {}
public override void TakeDamage(int damage)
{
Console.WriteLine($"{Name} は防御した!");
base.TakeDamage(damage - 1); // 1だけ軽減
}
}
// 使用例
enemies.Add(new Goblin("ゴブリンA", 25));
enemies.Add(new Goblin("ゴブリンB", 30));
✅ 5. すべての敵を Enemy 型で一括管理して攻撃処理を行う
foreach (Enemy enemy in enemies)
{
enemy.TakeDamage(5); // Goblinなら防御付き処理になる
}
foreach (Enemy enemy in enemies)
{
enemy.ShowStatus();
}
🧩 補足:全体構成のクラスファイル例
Project/
├── Program.cs // Mainメソッド、リスト生成と処理
├── Enemy.cs // 基本クラス
├── Goblin.cs // 継承クラス(オーバーライドあり)
🎓 最後に
オブジェクト指向のありがたみは、「ない世界を体験してから」初めて心に響きます。
スライム50体を手書きすることで、あなたはプログラマーとして最初の“本質”に触れました。
クラス、メソッド、継承――それは人間がコードを快適に扱うための知恵の結晶です。
これから先、あなたが書くコードが、もっとスッキリ・スマートになることを願っています。
ディスカッション
コメント一覧
まだ、コメントがありません