【学習】WinFormsで作るRPG入門(1)最小構成のPlayerとEnemy 〜Unityへ繋がる設計〜
C# を学習していると、次のような悩みがよく出てきます。
- Unity に進みたいが、いきなりは難しい
- オブジェクト指向(クラス)がまだ腑に落ちていない
そこで有効なのが、WinForms で小さな RPG を作ることです。
理由はシンプルです。
- UI が見える(すぐフィードバックが返る)
- イベント駆動(「何かが起きたら処理する」という Unity に近い構造)
- クラス設計を自然に使うことになる
つまり、ゲーム的な思考を C# で固める練習になります。
今回はシリーズ第1回として、勇者とスライム、攻撃ボタンだけの最小構成にします。
今回の最小ゴール
- 攻撃ボタンを押すたびに、スライムの HP が勇者の攻撃力分だけ減る
- 画面の Label に、勇者とスライムの HP が表示され続ける
前回からの差分
第1回のため、差分はありません。あとから読む人向けに、このシリーズの入口だと考えてください。
なぜ RPG なのか?(Unity との似方)
RPG は、Unity と 考え方の置き方が似ています。
| 要素 | WinForms(この記事) | Unity(イメージ) |
|---|---|---|
| プレイヤー | Player クラス |
GameObject + スクリプト |
| 敵 | Enemy クラス |
GameObject + スクリプト |
| 入力 | Button.Click |
Input System(キー等) / UI |
| 処理のきっかけ | イベント | Update() や UI イベント |
設計は同じで、描画と入力の取り方が違うと捉えると、あとから Unity に進みやすくなります。
ソリューションとプロジェクトを作る
- テンプレート: Windows フォーム アプリ(.NET / C#)
- プロジェクト名: 任意(例:
MiniRpgStep1)
WinForms の新規作成が初めての場合は、WinForms入門シリーズ:フォームとコントロールも参照してください。
フォームに配置する
Form1 に次のコントロールを配置します。
| コントロール | 名前(例) | 用途 |
|---|---|---|
| Label | lblPlayerHp |
プレイヤー HP 表示 |
| Label | lblEnemyHp |
敵 HP 表示 |
| Button | btnAttack |
攻撃 |
Player クラス
新しいクラスを追加し、プレイヤーの 名前・HP・攻撃力 と、敵を攻撃する処理をまとめます。
public class Player
{
public string Name { get; set; }
public int Hp { get; set; }
public int Attack { get; set; }
public Player(string name, int hp, int attack)
{
Name = name;
Hp = hp;
Attack = attack;
}
public void AttackEnemy(Enemy enemy)
{
enemy.Hp -= Attack;
}
}Enemy クラス
敵の 名前と HP を持ちます。
public class Enemy
{
public string Name { get; set; }
public int Hp { get; set; }
public Enemy(string name, int hp)
{
Name = name;
Hp = hp;
}
}Form1 のフィールドと初期化
フォーム側では、Player と Enemy のインスタンスをフィールドで持ちます。
Player player;
Enemy enemy;Form1 の Load イベント(Form1_Load)で初期化し、画面を更新します。
private void Form1_Load(object sender, EventArgs e)
{
player = new Player("勇者", 100, 20);
enemy = new Enemy("スライム", 50);
UpdateUI();
}攻撃ボタンの Click イベント
btnAttack の Click に、攻撃と UI 更新を書きます。HP が負にならないよう 0 で打ち切る例です。
private void btnAttack_Click(object sender, EventArgs e)
{
player.AttackEnemy(enemy);
if (enemy.Hp < 0)
enemy.Hp = 0;
UpdateUI();
}UI 更新メソッド
表示だけをまとめると、あとから項目が増えても扱いやすくなります。
private void UpdateUI()
{
lblPlayerHp.Text = $"HP: {player.Hp}";
lblEnemyHp.Text = $"HP: {enemy.Hp}";
}プログラムの流れ
Form1_Load
→ player / enemy を new
→ UpdateUI(Label に反映)
btnAttack_Click
→ player.AttackEnemy(enemy)
→ HP が 0 未満なら 0 に直す
→ UpdateUIこの時点で学べること
- オブジェクト指向:
PlayerとEnemyに役割を分ける - 状態管理: HP が変わるデータを持ち、画面に反映する
- イベント駆動: ボタン → 処理 → 表示更新
Unity での当たり所(入力だけ置き換えイメージ)
WinForms では ボタン1回=1回攻撃です。Unity では「キーを押した瞬間だけ同じ処理を呼ぶ」などに置き換えられます。
WinForms(Click)
private void btnAttack_Click(object sender, EventArgs e)
{
player.AttackEnemy(enemy);
// …省略
}Unity(例: スペースキー・Input System)
本講義の Unity 入門では Input System を使います(入力の取得)。Update で「押したその1フレームだけ」反応させる短い例です。
using UnityEngine;
using UnityEngine.InputSystem;
void Update()
{
if (Keyboard.current != null && Keyboard.current.spaceKey.wasPressedThisFrame)
{
player.AttackEnemy(enemy);
// …UI や Animator の更新は別処理になりがち
}
}Keyboard.current はキーボードが無い実行環境では null になり得るため、上のように null チェックを入れます。プロジェクト全体では PlayerInput と .inputactions で受け取る方法も常用です(詳細は上記リンク)。
Player / Enemy の フィールドとメソッドの考え方は、そのまま活かせます。Unity 側では「そのクラスを コンポーネント として GameObject に載せる」「参照を SerializeField や GetComponent で取る」など、持ち方が増えます。
よくあるつまずき
「クラスがわからない」
Player= 主人公のデータと行動Enemy= 敵のデータ
現実のものを、そのまま型としてコードにすると考えると取っかかりやすいです。
「Unity に行くと全部変わる気がする」
変わりやすいのは 見た目(Sprite / UI)と入力です。HP が減る・攻撃するといったロジックの構造は、むしろ近いです。
発展アイデア(次の記事へ)
- 敵の HP が 0 になったら「勝利」メッセージやボタン無効化
- スライム側も反撃する(交互に HP が減る=ターン制の入口)
シリーズ全体の目次は WinFormsでRPG入門 〜Unityへ繋がる設計の考え方〜(固定ページ) を参照してください。
まとめ
- WinForms で RPG の最小構成を作ると、クラス・状態・イベントが一度に練習できる
- Unity では 入力と表示の層が変わりやすいが、データとルールの分け方は応用しやすい
- 次回: 敵を複数にする(配列 /
List)(その先はランダム・コマンド選択・ターン制へ)