講義メモ ゲーム開発演習

フォームサイズの固定化、背景画像の描画など

テーマ2 フォーム名の指定【再掲載】

・System.Windows.Forms.Formクラスには、フォーム名を持つTextプロパティがある
・これを設定すると、見かけ上のアプリ名になる

提出フォロー:演習2 フォーム名の指定

・フォーム名を「Game」にしよう

作成例

//演習2 フォーム名の指定
using System; //フォームアプリケーションに必須
using System.Windows.Forms; //フォームアプリケーションに必須
class Program : Form { //Formクラスを継承
    static void Main() { //publicの指定は任意
        Program p = new Program(); //継承したフォームのインスタンスを生成
        p.Width = 660; //インスタンスのWidthプロパティに幅を代入
        p.Height = 520; //インスタンスのHeightプロパティに高さを代入
        p.Text = "Game"; //インスタンスのTextプロパティにフォーム名を代入
        Application.Run(p); //インスタンスを画面に出す
    }
}

テーマ3 フォームサイズの固定化

・フォームの右上には3つのボタンがあり、ControlBoxという。
・ここで、最大化を可能にしておくと、アプリケーション側で対処が必要
・よって、ControlBoxを非表示にすることで、最大化を抑止できる
・System.Windows.Forms.Formクラスには、ControlBoxプロパティがあり、これをfalseにすると良い
・しかし、最小化やクローズも出来なくなるので、プログラム側で終了処理を記述する必要がある
・なお、タスクバーでアイコンを右クリックして「ウィンドウを閉じる」でも終了できる
・ControlBoxを非表示にした時、Textプロパティにフォーム名を代入いていないと、ウィンドウバーも消えるので注意(ウィンドウの移動ができなくなる)

演習3 フォームサイズの固定化

・ControlBoxを非表示にして最大化・最小化・クローズを出来なくしよう

作成例

//演習3 フォームサイズの固定化
using System; //フォームアプリケーションに必須
using System.Windows.Forms; //フォームアプリケーションに必須
class Program : Form { //Formクラスを継承
    static void Main() { //publicの指定は任意
        Program p = new Program(); //継承したフォームのインスタンスを生成
        p.Width = 660; //インスタンスのWidthプロパティに幅を代入
        p.Height = 520; //インスタンスのHeightプロパティに高さを代入
        p.Text = "Game"; //インスタンスのTextプロパティにフォーム名を代入
        p.ControlBox = false; //ControlBoxを非表示にする
        Application.Run(p); //インスタンスを画面に出す
    }
}

テーマ4 メッセージボックス

・フォームアプリケーションにおいて画面上に小さなダイヤログであるメッセージボックスを表示できる
・確認メッセージの表示に用いることが多いが、テスト時の確認用にも便利
・System.Windows.Forms.MessageBoxクラスの、静的メソッドShow(string)で可能で、引数として表示したい文字列を与える

演習4 メッセージボックス

・起動したら「Hello」と表示するメッセージボックスを表そう
・フォームアプリケーションのMainメソッドで実行する場合は、Application.Run(…)の前に行うこと
・メッセージボックスの表示中はプログラムは待ち状態になる(モーダル)

作成例

//演習4 メッセージボックス
using System; //フォームアプリケーションに必須
using System.Windows.Forms; //フォームアプリケーションに必須
class Program : Form { //Formクラスを継承
    static void Main() { //publicの指定は任意
        Program p = new Program(); //継承したフォームのインスタンスを生成
        p.Width = 660; //インスタンスのWidthプロパティに幅を代入
        p.Height = 520; //インスタンスのHeightプロパティに高さを代入
        p.Text = "Game"; //インスタンスのTextプロパティにフォーム名を代入
        p.ControlBox = false; //ControlBoxを非表示にする
        MessageBox.Show("Hello!"); //【追加】メッセージボックスを表示
        Application.Run(p); //インスタンスを画面に出す
    }
}

テーマ5 描画処理の基礎

・ウィンドウを持つアプリケーションでは、プログラム側からの描画と、システム側からの必要に応じた描画がある
・この両方に対応するために、C#のフォームアプリケーションでは、Formクラスでvoid OnPaint(PaintEventArgs)メソッドを提供している
・この引数のPaintEventArgsはシステム側が提供する「画面を描くための情報」
・フォームアプリケーションではこのメソッドをオーバーライドして、描画処理を記述する(アクセス修飾子はprotecedにすること)
・この時、フォームの基本再描画処理がFormクラスで与えられるので、オーバーライドの冒頭において、FormクラスのOnPaintメソッドの内容を実行すること
・この実行には、PaintEventArgsを引数として渡す
・書式例:
 protected override void OnPaint(PaintEventArgs e) { //Formのメソッドをオーバーライド
  base.OnPaint(e); //まず、Formクラスにおけるメソッドの内容(基本再描画処理)を実行
  :自前の描画処理を書くところ
 }

提出:「演習4 メッセージボックス」

講義メモ

オブジェクト指向演習:プロパティの導入とゲーム性の向上
ゲーム開発演習:フォームサイズの固定化、背景画像の描画など

オブジェクト指向演習

p.207 プロパティ【再掲載】

・データメンバとメソッドの中間の仕掛けで、データメンバに対する操作を代行してくれる役割
・これにより、データメンバの値を外部から直接操作されることを防止できる
・メソッドに近い特殊な形式で、設定用のアクセッサ「set」と、参照用のアクセッサ「get」のどちらかまたは両方を記述する
・定義書式: アクセス修飾子 データ型 プロパティ名 { set {…} get {…} }
・アクセッサ「get」はデータメンバの値などをreturnするので、データ型と型が一致する
・アクセッサ「set」は代入の左辺になり、右辺から与えられたデータをvalueキーワードで受け取ることができる
・例: public int HitP { get {return hp;} set {hp = value;} } 
・利用側は、プロパティ名をデータメンバ名と同様に扱える
・例: 参照変数.HitP = 100; //プロパティ(set)により「hp = 100;」が実行される
・例: x = 参照変数.HitP; //プロパティ(get)によりhpの値(100)が代入の右辺になる

RPG演習3 仕様:プロパティの導入とゲーム性の向上

・MadoshiクラスのGetHP()メソッドをプロパティ「int HP」にしよう。Getしかないのでsetは不要。
・ついでに、DispInfo()メソッドでMPも表示するようにしよう

作成例

//オブジェクト指向演習 RPG演習3
using System;
class Madoshi { //魔導士を表すクラス
    int mp; //MP(カプセル化(p.166)のためにpublicにしない)
    int hp; //HP(〃)
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
    public Madoshi() { //コンストラクタ(p.167)
        mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
        hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
    }
    public int HP { //【以下変更】HPを返すプロパティ
        get { return hp; } 
    }
    public void DispInfo() { //魔導士の情報を表示する
        Console.Write("魔道士(HP={0} MP={1})", hp, mp); //【変更】HP,MPを表示(改行しない)
    }
    public int Fight() { //魔道士があなたを攻撃し、あなたのダメージ値を返す
        if (rnd.Next(2) == 1) { //確率1/2で魔法攻撃かどうかを選ぶ
            int j = rnd.Next(5) + 1; //消費MPは1~5の乱数
            DispInfo(); // 魔導士の情報を表示する
            Console.WriteLine("は消費MP" + j + "の魔法を唱えた!");
            if (mp < j) { // MP不足?
                Console.WriteLine("MPが足りない!");
                return 0; // あなたのダメージ=0を返す(攻撃終了)
            } else { // MP充足?
                Console.WriteLine("あなたは" + j * 4 + "のダメージを受けた!");
                mp -= j; //MP消費
                return j * 4; //あなたのダメージ=消費MPの4倍を返す(攻撃終了)
            }
        } else { //通常攻撃?
            int k = rnd.Next(5) + 1; //攻撃力は1~5の乱数
            DispInfo(); //魔導士の情報を表示する
            Console.WriteLine("の攻撃!");
            Console.WriteLine("あなたは" + k + "のダメージを受けた!");
            return k; //あなたのダメージ=1~50を返す(攻撃終了)
        }
    }
    public void Damage() { //魔道士があなたからダメージをくらう
        int k = 5 + rnd.Next(5); //あなたの攻撃力は5~9の乱数
        Console.WriteLine("あなたの攻撃!");
        DispInfo(); //魔導士の情報を表示する(攻撃を受けた後の魔道士のHPを表示)
        Console.WriteLine("に" + k + "のダメージを与えた!");
        hp -= k; //魔道士のHPをダウン
    }
}
class minimadou { //ゲーム本体のクラス
    public static void Main() { //ゲームを進行するメソッド
        string ans; //入力用
        // 戦闘開始
        int myhp = 20; // あなたのHP
        Madoshi m = new Madoshi(); // 魔道士を生成
        m.DispInfo(); // 魔道士の情報を表示する
        Console.WriteLine("が現れた。");
        // 戦闘中(あなたが死ぬか,魔道士が死ぬまで繰り返す)
        while (myhp > 0 && m.HP > 0) { //【変更】あなたのHPがあり、魔導士のHPがある間
            Console.Write("残りHPは{0}です。攻撃しますか?(1:はい 0:やめる):", myhp);
            ans = Console.ReadLine(); // 攻撃するかどうかを得る
            if (ans == "1") { // はい?
                m.Damage(); // 魔道士を攻撃する
                if (m.HP > 0) { //【変更】魔道士は死んでない?
                    myhp -= m.Fight(); // 魔道士の攻撃!あなたのHPをマイナス
                    if (myhp <= 0) { // あなたのHPがもうない?
                        Console.WriteLine("あなたは死にました。");
                    }
                } else { // 魔道士のHPがもうない?
                    Console.WriteLine("魔道士を倒した!");
                }
            } else { // やめる?
                break; // 繰り返し終了(p.125)
            }
        }
    }
}

RPG演習4 仕様:ゲーム性の向上の続き

・「攻撃しますか?(1:はい 0:やめる):」で「0」を選んだら確率50%で「逃げることができた」と表示しよう
・そうでなければ「逃げられない」と表示して、魔導士の攻撃に進むようにしよう

RPG演習4 ヒント

・minimadouクラスでも乱数用のRandomクラスのインスタンスを生成する必要がある
・確率50%は「if(乱数オブジェクト.Next(2) == 0)」で実装できる
・「魔道士の攻撃!あなたのHPをマイナス」を「逃げられない」場合にも行えば良い
・その為「あなたのHPがもうない?」チェックを「はい」でも「やめる」でも行うように移動する

作成例

//オブジェクト指向演習 RPG演習4
using System;
class Madoshi { //魔導士を表すクラス
    int mp; //MP(カプセル化(p.166)のためにpublicにしない)
    int hp; //HP(〃)
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
    public Madoshi() { //コンストラクタ(p.167)
        mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
        hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
    }
    public int HP { //HPを返すプロパティ
        get { return hp; } 
    }
    public void DispInfo() { //魔導士の情報を表示する
        Console.Write("魔道士(HP={0} MP={1})", hp, mp); //HP,MPを表示(改行しない)
    }
    public int Fight() { //魔道士があなたを攻撃し、あなたのダメージ値を返す
        if (rnd.Next(2) == 1) { //確率1/2で魔法攻撃かどうかを選ぶ
            int j = rnd.Next(5) + 1; //消費MPは1~5の乱数
            DispInfo(); // 魔導士の情報を表示する
            Console.WriteLine("は消費MP" + j + "の魔法を唱えた!");
            if (mp < j) { // MP不足?
                Console.WriteLine("MPが足りない!");
                return 0; // あなたのダメージ=0を返す(攻撃終了)
            } else { // MP充足?
                Console.WriteLine("あなたは" + j * 4 + "のダメージを受けた!");
                mp -= j; //MP消費
                return j * 4; //あなたのダメージ=消費MPの4倍を返す(攻撃終了)
            }
        } else { //通常攻撃?
            int k = rnd.Next(5) + 1; //攻撃力は1~5の乱数
            DispInfo(); //魔導士の情報を表示する
            Console.WriteLine("の攻撃!");
            Console.WriteLine("あなたは" + k + "のダメージを受けた!");
            return k; //あなたのダメージ=1~50を返す(攻撃終了)
        }
    }
    public void Damage() { //魔道士があなたからダメージをくらう
        int k = 5 + rnd.Next(5); //あなたの攻撃力は5~9の乱数
        Console.WriteLine("あなたの攻撃!");
        DispInfo(); //魔導士の情報を表示する(攻撃を受けた後の魔道士のHPを表示)
        Console.WriteLine("に" + k + "のダメージを与えた!");
        hp -= k; //魔道士のHPをダウン
    }
}
class minimadou { //ゲーム本体のクラス
    public static void Main() { //ゲームを進行するメソッド
        Random rnd = new Random(); //【追加】乱数用のRandomクラスのインスタンスを生成
        string ans; //入力用
        // 戦闘開始
        int myhp = 20; // あなたのHP
        Madoshi m = new Madoshi(); // 魔道士を生成
        m.DispInfo(); // 魔道士の情報を表示する
        Console.WriteLine("が現れた。");
        // 戦闘中(あなたが死ぬか,魔道士が死ぬまで繰り返す)
        while (myhp > 0 && m.HP > 0) { //あなたのHPがあり、魔導士のHPがある間
            Console.Write("残りHPは{0}です。攻撃しますか?(1:はい 0:やめる):", myhp);
            ans = Console.ReadLine(); // 攻撃するかどうかを得る
            if (ans == "1") { // はい?
                m.Damage(); // 魔道士を攻撃する
                if (m.HP > 0) { //魔道士は死んでない?
                    myhp -= m.Fight(); // 魔道士の攻撃!あなたのHPをマイナス
                } else { // 魔道士のHPがもうない?
                    Console.WriteLine("魔道士を倒した!");
                }
            } else { // やめる?
                if (rnd.Next(2) == 0) { //【以下追加】確率50%で
                    Console.WriteLine("逃げることができた!");
                    break; // 繰り返し終了(p.125)
                } else {
                    Console.WriteLine("逃げられない!");
                    myhp -= m.Fight(); // 魔道士の攻撃!あなたのHPをマイナス
                }
            }
            if (myhp <= 0) { //【以下移動】あなたのHPがもうない?
                Console.WriteLine("あなたは死にました。");
            }
        }
    }
}

今週の話題

販売本数ランキング 今回トップも「帰ってきた 名探偵ピカチュウ(Switch)」GO!
上位10アプリの合計消費支出は約151億円に―data.ai、2023年第3四半期ゲームアプリランキングを発表 GO!
「東京eスポーツフェスタ2024」プレイベントが10月21日開催―出展検討事業者に向け説明会/ゲストトーク/交流会をオン&オフラインにて実施 GO!
PlayStation PlusプレミアムプランにてPS5向けのクラウドストリーミング開始―ゲームカタログやトライアルの作品をダウンロード無しでプレイ GO!

「ドラゴンクエスト ユア・ストーリー」主人公の名前巡る裁判で「小説ドラゴンクエストV」著者の請求が棄却―東京地裁 GO!
『バトルフィールド 2042』無料プレイ&セールの影響で接続人数が大幅増加もサーバー容量でログインできない状況に―現在は改善へと取り組み中 GO!

講義メモ ゲーム開発演習①

イントロダクション

・グラフィックスやポインティングディバイス(マウス、タッチ)を用いるプログラムを開発するには、Unity等の開発ツールを用いると便利
・しかし、Windowsの場合、OSが提供するプログラミングインタフェース(API)を直接用いることでプログラミングの自由度が上げられる
・そこで、この演習ではC#からGDI+というWindowsが提供するAPIを用いて、フォームアプロケーションとして開発しよう
・GDI+の利用により、グラフィックスやポインティングディバイスやサウンドなどを用いるゲームを開発しよう

フォームアプリケーションの作成と確認

・VSで「新しいプロジェクト」「C#」「Windowsフォームアプリケーション(.NET)」
・作成するとフォームデザイナ画面になり、この上でフォームパーツを配置することができるが、プログラム側で定義・配置する方が
 精度が上がる
・そのためのソース「Program.cs」を右クリックして「コードの表示」

p.421 Windowsフォームプログラミング

・上記で自動作成されたソース「Program.cs」には不用なusing指定や、任意(必須ではない)記述が含まれている
・そこで、p.422「mostsimple.cs」を参考にして、必要なソースに絞って用いよう

作成例

using System; //フォームアプリケーションに必須
using System.Windows.Forms; //フォームアプリケーションに必須
class Program : Form { //Formクラスを継承
    static void Main() { //publicの指定は任意
        Application.Run(new Program()); //継承したフォームを生成して画面に出す
    }
}

プログラムの説明

・Windowsフォームアプリケーション(.NET)は、C#/.NETが提供するSystem.Windows.Forms.Formクラスのオブジェクトによって
 自前のウィンドウを生成して用いる
・これを、Formクラスを継承した派生クラスで行うことが可能
・派生クラスで行えば、各種の記述を追加できるので、こちらの方が自由度が高い
・継承により、Formクラスが持っている最小化・最大化・閉じるの3ボタンの機能や、マウスによるサイズ変更などの機能が引き継がれる
・フォームの生成は、Formクラスまたはその派生クラスのオブジェクトをnewすればOK
・このオブジェクトを、C#/.NETが提供するSystem.Windows.Forms.Applicationクラスの静的メソッドRunに引数として渡すと、
 画面に表示してくれる

テキスト p.422 補足

・「前準備」として参照設定の追加が記述されているが、Visual Studio 2019以降では不要

テーマ1 フォームサイズの指定

・System.Windows.Forms.Formクラスには、Controlクラスから継承したWidthプロパティがある
・これに整数値(int)を与えると、フォームの幅に設定される
・同様に、Heightプロパティがある、整数値(int)を与えると、フォームの高さに設定される
・ただし、実際には全体の大きさになり、内側の領域の大きさにするには余裕を取って行うこと
・プロパティへの代入はオブジェクトの生成後で、Runメソッドによる表示の前に行うこと
・よって「Application.Run(new Program());」を分割する必要がある

演習1 フォームサイズの指定

・領域を640×480にしたいので、フォームサイズを660×520にしよう

作成例

//演習1 フォームサイズの指定
using System; //フォームアプリケーションに必須
using System.Windows.Forms; //フォームアプリケーションに必須
class Program : Form { //Formクラスを継承
    static void Main() { //publicの指定は任意
        Program p = new Program(); //継承したフォームのインスタンスを生成
        p.Width = 660; //インスタンスのWidthプロパティに幅を代入
        p.Height = 520; //インスタンスのHeightプロパティに高さを代入
        Application.Run(p); //インスタンスを画面に出す
    }
}

補足:幅と高さをSizeとしてまとめて扱う

・System.Drawing.Sizeクラスのコンストラクタに、幅と高さを渡すとサイズ情報オブジェクトを生成してくれる
・これを、FormオブジェクトのSizeプロパティに渡すことで、幅と高さをまとめて扱える
例:
  Program p = new Program(); //継承したフォームのインスタンスを生成
  p.Size = new System.Drawing.Size(660, 520); //インスタンスのSizeプロパティにSizeオブジェトを代入
  Application.Run(p); //インスタンスを画面に出す
・フォームアプリケーションのクラスでは「using System.Drawing;」を指定することが多いので、指定すると下記のようになる。
 p.Size = new Size(660, 520); //インスタンスのSizeプロパティにSizeオブジェトを代入
・この書き方は、各種の描画オブジェクトに対して、予めサイズを用意しておきたい場合などに便利

テーマ2 フォーム名の指定

・System.Windows.Forms.Formクラスには、フォーム名を持つTextプロパティがある
・これを設定すると、見かけ上のアプリ名になる

提出:演習2 フォーム名の指定

・フォーム名を「Game」にしよう
・ソースファイル「Program.cs」をZIP圧縮して送信してください

講義メモ 続き

乱数に関する補足説明

・Randomクラスは乱数を提供するもので、System名前空間にあるので「using System;」があればクラス名だけで利用可能
・Randomクラスのデフォルトコンストラクタを呼び出すと、内部的にシステムクロックを用いたシード処理(乱数系の初期設定)が行われて、
 乱数機能を提供するオブジェクトが生成される
 ※ C/C++が提供する疑似乱数と同等だが、自前のシード処理は不要なので便利
・Randomクラスのインスタンスメソッド「int Next(int)」は0から引数値-1までのどれかの整数を返す
例:
 Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
 int mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
 int hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
・乱数オブジェクトは使いまわしが可能なので、クラスのデータメンバとして定義・初期化しておくと良い

ミニ演習 mini01.cs じゃんけんの基礎

・乱数によって、"グー"または"チョキ"または"パー"を表示しよう

作成例 その1

//ミニ演習 mini01.cs じゃんけんの基礎
using System;
class mini01 { //乱数によって、"グー"または"チョキ"または"パー"を表示
    public static void Main() { 
        Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
        int r = rnd.Next(3); //0~2の間のランダムな整数を得る
        Console.WriteLine((r == 0) ? "グー" : ((r == 1) ? "チョキ" : "パー"));
    }
}

作成例 その2

//ミニ演習 mini01.cs じゃんけんの基礎
using System;
class mini01 { //乱数によって、"グー"または"チョキ"または"パー"を表示
    public static void Main() {
        string[] hand = {"グー", "チョキ", "パー"};
        Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
        int r = rnd.Next(3); //0~2の間のランダムな整数を得る
        Console.WriteLine(hand[r]); //乱数を添字にして文字列を得て表示
    }
}

参考:暗黙の型指定

・暗黙の型指定(p.147)を用いて「var hand = new[]{"グー", "チョキ", "パー"};」としても良い

RPG演習2 仕様

・プレイヤーのHPを表示しよう
・「攻撃しますか?(1:はい 0:やめる):」を「残りHPは●です。攻撃しますか?(1:はい 0:やめる):」にしよう

作成例

//オブジェクト指向演習 RPG演習2
using System;
class Madoshi { //魔導士を表すクラス
    int mp; //MP(カプセル化(p.166)のためにpublicにしない)
    int hp; //HP(〃)
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成(後述)
    public Madoshi() { //コンストラクタ(p.167)
        mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
        hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
    }
    public int GetHP() { return hp; } //HPを返すメソッド
    public void DispInfo() { //魔導士の情報を表示する
        Console.Write("魔道士(HP=" + hp + ")"); //HPを表示(改行しない)
    }
    public int Fight() { //魔道士があなたを攻撃し、あなたのダメージ値を返す
        if (rnd.Next(2) == 1) { //確率1/2で魔法攻撃かどうかを選ぶ
            int j = rnd.Next(5) + 1; //消費MPは1~5の乱数
            DispInfo(); // 魔導士の情報を表示する
            Console.WriteLine("は消費MP" + j + "の魔法を唱えた!");
            if (mp < j) { // MP不足?
                Console.WriteLine("MPが足りない!");
                return 0; // あなたのダメージ=0を返す(攻撃終了)
            } else { // MP充足?
                Console.WriteLine("あなたは" + j * 4 + "のダメージを受けた!");
                mp -= j; //MP消費
                return j * 4; //あなたのダメージ=消費MPの4倍を返す(攻撃終了)
            }
        } else { //通常攻撃?
            int k = rnd.Next(5) + 1; //攻撃力は1~5の乱数
            DispInfo(); //魔導士の情報を表示する
            Console.WriteLine("の攻撃!");
            Console.WriteLine("あなたは" + k + "のダメージを受けた!");
            return k; //あなたのダメージ=1~50を返す(攻撃終了)
        }
    }
    public void Damage() { //魔道士があなたからダメージをくらう
        int k = 5 + rnd.Next(5); //あなたの攻撃力は5~9の乱数
        Console.WriteLine("あなたの攻撃!");
        DispInfo(); //魔導士の情報を表示する(攻撃を受けた後の魔道士のHPを表示)
        Console.WriteLine("に" + k + "のダメージを与えた!");
        hp -= k; //魔道士のHPをダウン
    }
}
class minimadou { //ゲーム本体のクラス
    public static void Main() { //ゲームを進行するメソッド
        string ans; //入力用
        // 戦闘開始
        int myhp = 20; // あなたのHP
        Madoshi m = new Madoshi(); // 魔道士を生成
        m.DispInfo(); // 魔道士の情報を表示する
        Console.WriteLine("が現れた。");
        // 戦闘中(あなたが死ぬか,魔道士が死ぬまで繰り返す)
        while (myhp > 0 && m.GetHP() > 0) { //あなたのHPがあり、魔導士のHPがある間
            Console.Write("残りHPは{0}です。攻撃しますか?(1:はい 0:やめる):", myhp);
            ans = Console.ReadLine(); // 攻撃するかどうかを得る
            if (ans == "1") { // はい?
                m.Damage(); // 魔道士を攻撃する
                if (m.GetHP() > 0) { // 魔道士は死んでない?
                    myhp -= m.Fight(); // 魔道士の攻撃!あなたのHPをマイナス
                    if (myhp <= 0) { // あなたのHPがもうない?
                        Console.WriteLine("あなたは死にました。");
                    }
                } else { // 魔道士のHPがもうない?
                    Console.WriteLine("魔道士を倒した!");
                }
            } else { // やめる?
                break; // 繰り返し終了(p.125)
            }
        }
    }
}

講義メモ

・オブジェクト指向演習①
・ゲーム開発演習①

オブジェクト指向演習①

・コンソールアプリケーションによるRPGを題材にして、テキスト10章までのノウハウとテクニックを確認&実習しましょう。

RPG演習1 仕様

・プロジェクトはコンソールアプリケーションで「rpg」とします
・魔導士とプレイヤーが戦うゲーム
・詳細はスケルトンのコメントを読み解いて理解を

実行例

魔道士(HP=10)が現れた。
攻撃しますか?(1:はい 0:やめる):1
あなたの攻撃!
魔道士(HP=10)に5のダメージを与えた!
魔道士(HP=5)は消費MP4の魔法を唱えた!
あなたは16のダメージを受けた!
攻撃しますか?(1:はい 0:やめる):1
あなたの攻撃!
魔道士(HP=5)に7のダメージを与えた!
魔道士を倒した!

プログラム ver.0(穴埋めになっています)

//オブジェクト指向演習 RPG演習1
using System;
class Madoshi {
    int mp; //MP
    int hp; //HP
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
    public ● () { //コンストラクタ
        mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
        hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
    }
    public int GetHP() { return hp; } //HPを返すメソッド
    public void DispInfo() { //魔導士の情報を表示する
        Console.Write("魔道士(HP=" + hp + ")"); //HPを表示(改行しない)
    }
    public int Fight() { //魔道士があなたを攻撃し、あなたのダメージ値を返す
        if (rnd.Next(2) == 1) { //確率1/2で魔法攻撃かどうかを選ぶ
            int j = rnd.Next(5) + 1; //消費MPは1~5の乱数
            DispInfo(); // 魔導士の情報を表示する
            Console.WriteLine("は消費MP" + j + "の魔法を唱えた!");
            if (mp < j) { // MP不足?
                Console.WriteLine("MPが足りない!");
                return 0; // あなたのダメージ=0を返す(攻撃終了)
            } else { // MP充足?
                Console.WriteLine("あなたは" + j * 4 + "のダメージを受けた!");
                mp -= j; //MP消費
                return j * 4; //あなたのダメージ=消費MPの4倍を返す(攻撃終了)
            }
        } else { //通常攻撃?
            int k = rnd.Next(5) + 1; //攻撃力は1~5の乱数
            DispInfo(); //魔導士の情報を表示する
            Console.WriteLine("の攻撃!");
            Console.WriteLine("あなたは" + k + "のダメージを受けた!");
            return k; //あなたのダメージ=1~50を返す(攻撃終了)
        }
    }
    public void Damage() { //魔道士があなたからダメージをくらう
        int k = 5 + rnd.Next(5); //あなたの攻撃力は5~9の乱数
        Console.WriteLine("あなたの攻撃!");
        DispInfo(); //魔導士の情報を表示する(攻撃を受けた後の魔道士のHPを表示)
        Console.WriteLine("に" + k + "のダメージを与えた!");
        hp -= k; //魔道士のHPをダウン
    }
}
class minimadou { //ゲーム本体のクラス
    public static void Main() { //ゲームを進行するメソッド
        string ans; //入力用
        // 戦闘開始
        int myhp = 20; // あなたのHP
        Madoshi m = new Madoshi(); // 魔道士を生成
        m.DispInfo(); // 魔道士の情報を表示する
        Console.WriteLine("が現れた。");
        // 戦闘中(あなたが死ぬか,魔道士が死ぬまで繰り返す)
        ● (myhp > 0 && m.GetHP() > 0) { //あなたのHPがあり、魔導士のHPがある間
            Console.Write("攻撃しますか?(1:はい 0:やめる):");
            ans = Console.ReadLine(); // 攻撃するかどうかを得る
            if (ans == "1") { // はい?
                m.Damage(); // 魔道士を攻撃する
                if (m.GetHP() > 0) { // 魔道士は死んでない?
                    myhp -= m.Fight(); // 魔道士の攻撃!あなたのHPをマイナス
                    if (myhp <= 0) { // あなたのHPがもうない?
                        Console.WriteLine("あなたは死にました。");
                    }
                } else { // 魔道士のHPがもうない?
                    Console.WriteLine("魔道士を倒した!");
                }
            } else { // やめる?
                ●// 繰り返し終了
            }
        }
    }
}

作成例

//オブジェクト指向演習 RPG演習1
using System;
class Madoshi { //魔導士を表すクラス
    int mp; //MP(カプセル化(p.166)のためにpublicにしない)
    int hp; //HP(〃)
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成(後述)
    public Madoshi() { //コンストラクタ(p.167)
        mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
        hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
    }
    public int GetHP() { return hp; } //HPを返すメソッド
    public void DispInfo() { //魔導士の情報を表示する
        Console.Write("魔道士(HP=" + hp + ")"); //HPを表示(改行しない)
    }
    public int Fight() { //魔道士があなたを攻撃し、あなたのダメージ値を返す
        if (rnd.Next(2) == 1) { //確率1/2で魔法攻撃かどうかを選ぶ
            int j = rnd.Next(5) + 1; //消費MPは1~5の乱数
            DispInfo(); // 魔導士の情報を表示する
            Console.WriteLine("は消費MP" + j + "の魔法を唱えた!");
            if (mp < j) { // MP不足?
                Console.WriteLine("MPが足りない!");
                return 0; // あなたのダメージ=0を返す(攻撃終了)
            } else { // MP充足?
                Console.WriteLine("あなたは" + j * 4 + "のダメージを受けた!");
                mp -= j; //MP消費
                return j * 4; //あなたのダメージ=消費MPの4倍を返す(攻撃終了)
            }
        } else { //通常攻撃?
            int k = rnd.Next(5) + 1; //攻撃力は1~5の乱数
            DispInfo(); //魔導士の情報を表示する
            Console.WriteLine("の攻撃!");
            Console.WriteLine("あなたは" + k + "のダメージを受けた!");
            return k; //あなたのダメージ=1~50を返す(攻撃終了)
        }
    }
    public void Damage() { //魔道士があなたからダメージをくらう
        int k = 5 + rnd.Next(5); //あなたの攻撃力は5~9の乱数
        Console.WriteLine("あなたの攻撃!");
        DispInfo(); //魔導士の情報を表示する(攻撃を受けた後の魔道士のHPを表示)
        Console.WriteLine("に" + k + "のダメージを与えた!");
        hp -= k; //魔道士のHPをダウン
    }
}
class minimadou { //ゲーム本体のクラス
    public static void Main() { //ゲームを進行するメソッド
        string ans; //入力用
        // 戦闘開始
        int myhp = 20; // あなたのHP
        Madoshi m = new Madoshi(); // 魔道士を生成
        m.DispInfo(); // 魔道士の情報を表示する
        Console.WriteLine("が現れた。");
        // 戦闘中(あなたが死ぬか,魔道士が死ぬまで繰り返す)
        while (myhp > 0 && m.GetHP() > 0) { //あなたのHPがあり、魔導士のHPがある間
            Console.Write("攻撃しますか?(1:はい 0:やめる):");
            ans = Console.ReadLine(); // 攻撃するかどうかを得る
            if (ans == "1") { // はい?
                m.Damage(); // 魔道士を攻撃する
                if (m.GetHP() > 0) { // 魔道士は死んでない?
                    myhp -= m.Fight(); // 魔道士の攻撃!あなたのHPをマイナス
                    if (myhp <= 0) { // あなたのHPがもうない?
                        Console.WriteLine("あなたは死にました。");
                    }
                } else { // 魔道士のHPがもうない?
                    Console.WriteLine("魔道士を倒した!");
                }
            } else { // やめる?
                break; // 繰り返し終了(p.125)
            }
        }
    }
}