学習記事一覧 · WinFormsRPG

【学習】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 のフィールドと初期化

フォーム側では、PlayerEnemy のインスタンスをフィールドで持ちます。

Player player;
Enemy enemy;

Form1Load イベント(Form1_Load)で初期化し、画面を更新します。

private void Form1_Load(object sender, EventArgs e)
{
    player = new Player("勇者", 100, 20);
    enemy = new Enemy("スライム", 50);

    UpdateUI();
}

攻撃ボタンの Click イベント

btnAttackClick に、攻撃と 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

この時点で学べること

  • オブジェクト指向: PlayerEnemy に役割を分ける
  • 状態管理: 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 に載せる」「参照を SerializeFieldGetComponent で取る」など、持ち方が増えます。


よくあるつまずき

「クラスがわからない」

  • Player = 主人公のデータと行動
  • Enemy = 敵のデータ

現実のものを、そのまま型としてコードにすると考えると取っかかりやすいです。

「Unity に行くと全部変わる気がする」

変わりやすいのは 見た目(Sprite / UI)と入力です。HP が減る・攻撃するといったロジックの構造は、むしろ近いです。


発展アイデア(次の記事へ)

  • 敵の HP が 0 になったら「勝利」メッセージやボタン無効化
  • スライム側も反撃する(交互に HP が減る=ターン制の入口)

シリーズ全体の目次は WinFormsでRPG入門 〜Unityへ繋がる設計の考え方〜(固定ページ) を参照してください。


まとめ

  • WinForms で RPG の最小構成を作ると、クラス・状態・イベントが一度に練習できる
  • Unity では 入力と表示の層が変わりやすいが、データとルールの分け方は応用しやすい
  • 次回: 敵を複数にする(配列 / List(その先はランダム・コマンド選択・ターン制へ)