講義メモ

オブジェクト指向演習:3人の魔導士の続き(オブジェクト配列、乱数の改良)
ゲーム開発演習:メッセージボックス、システム側からの必要に応じた再描画の確認、背景画像の描画

RPG演習7 3人の魔導士 ver.2

・3人の魔導士にしたいので、魔導士オブジェクトを長さ3の配列で扱うようにしよう
・実行イメージ

魔道士1(HP=14 MP=0)が現れた。
魔道士2(HP=14 MP=0)が現れた。
魔道士3(HP=14 MP=0)が現れた。
残りHPは20です。どれを攻撃しますか?(1/2/3:魔導士を攻撃 0:やめる):1
あなたの攻撃!
魔道士1(HP=14 MP=0)に8のダメージを与えた!
魔道士1(HP=6 MP=0)の攻撃!
あなたは4のダメージを受けた!
魔道士2(HP=14 MP=0)の攻撃!
あなたは3のダメージを受けた!
魔道士3(HP=14 MP=0)の攻撃!
あなたは2のダメージを受けた!
残りHPは11です。どれを攻撃しますか?(1/2/3:魔導士を攻撃 0:やめる):1
:
・まずは、最低限の仕様を実装し、追加すべきことを洗い出そう
・「魔道士[0]の情報を表示する」を3人分に
・ループの条件「あなたのHPがあり、魔導士[0]のHPがある間」を「あなたのHPがあり、どれかの魔導士のHPがある間」に
・「攻撃しますか?(1:はい 0:やめる)」を「どれを攻撃しますか?(1/2/3:魔導士を攻撃 0:やめる)」に
・「魔道士[0]を攻撃する」を「魔道士[入力値を整数化して-1した値]を攻撃する」に
・「魔道士[0]は死んでない?」を「どれかの魔導士のHPがある?」に
・「魔道士[0]の攻撃!あなたのHPをマイナス」を3人分に
・「逃げられない!」の後の「魔道士[0]の攻撃!あなたのHPをマイナス」も3人分に

作成例

//オブジェクト指向演習 RPG演習7 3人の魔導士 ver.2
using System;
class Madoshi { //魔導士を表すクラス(部品)
    int mp; //MP
    int hp; //HP
    int id; //魔導士番号
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
    public Madoshi (int id) { //コンストラクタ
        mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
        hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
        this.id = id; //生成時に指定した魔導士番号を設定
    }
    public int HP { //HPを返すプロパティ
        get { return hp; } //getのみなので外部からのhpの書換を禁止
    }
    public void DispInfo() { //魔導士の情報を表示する
        Console.Write("魔道士{0}(HP={1} MP={2})", id, 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~5を返す(攻撃終了)
        }
    }
    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() { //ゲームを進行するメソッド
        const int N = 3; //【追加】魔導士の数
        Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
        string ans; //入力用
        // 戦闘開始
        int myhp = 20; // あなたのHP
        Madoshi[] m = new Madoshi[N]; //【変更】魔導士の配列を生成
        for (int i = 0; i < N; i++) { //【追加】魔導士の数だけ繰返す
            m[i] = new Madoshi(i + 1); //【変更】魔道士(i + 1)を魔導士[i]に生成
            m[i].DispInfo(); //【変更】魔道士[i]の情報を表示する
            Console.WriteLine("が現れた。");
        }
        // 戦闘中(あなたが死ぬか,魔道士が死ぬまで繰り返す)
        while (myhp > 0 && (m[0].HP > 0 || m[1].HP > 0 || m[2].HP > 0)) { //【変更】あなたのHPがあり、どれかの魔導士のHPがある間
            Console.Write("残りHPは{0}です。どれを攻撃しますか?(1/2/3:魔導士を攻撃 0:やめる):", myhp); //【変更】
            ans = Console.ReadLine(); // 攻撃するかどうかを得る
            if (ans != "0") { //【変更】攻撃する?
                int num = int.Parse(ans) - 1; //【追加】攻撃対象の魔導士の添字を得る
                m[num].Damage(); //【変更】魔道士[num]を攻撃する
                if (m[0].HP > 0 || m[1].HP > 0 || m[2].HP > 0) { //【変更】どれかの魔導士のHPがある?
                    for (int i = 0; i < N; i++) { //【追加】魔導士の数だけ繰返す
                        myhp -= m[i].Fight(); //【変更】魔道士[i]の攻撃!あなたのHPをマイナス
                    }
                } else { //魔道士のHPがもうない?
                    Console.WriteLine("魔道士を倒した!");
                }
            } else { // やめる?
                if (rnd.Next(2) == 0) { //確率50%で
                    Console.WriteLine("逃げられない!");
                    for (int i = 0; i < N; i++) { //【追加】魔導士の数だけ繰返す
                        myhp -= m[i].Fight(); //【変更】魔道士[i]の攻撃!あなたのHPをマイナス
                    }
                } else {
                    Console.WriteLine("逃げることができた");
                    break; // 繰り返し終了
                }
            }
            if (myhp <= 0) { //あなたのHPがもうない?
                Console.WriteLine("あなたは死にました。");
            }
        }
    }
}

RPG演習8 3人の魔導士 ver.3

・Madoshiクラスに下記の静的メンバを追加して効率化しよう
 ① static int mnum = 0; //魔導士が何人生成されたか
 ② static int surv = 0; //生きている魔導士は何人いるか
 ⇒p.202 静的メンバ
 ・静的メンバはクラスに所属するので、インスタンスではなくクラスで持ちたい情報は静的データメンバにすると良い
・そして、Madoshiクラスのコンストラクタで①をカウントアップし、②に代入しておこう
・これに伴って、コンストラクタの引数が不要になる
・また、Damage()において、HPが尽きた場合、②をデクリメントしよう
・これで、Main()における「どれかの魔導士のHPがある?」を「生きている魔導士がいる?」に変更できる
・しかし、生きている魔導士は何人いるかを静的データメンバで持つと、publicにする必要があり、安全性に懸念がある
・そこで、生きている魔導士いるかどうかをbool型で返す静的プロパティをMadoshiクラスに追加しよう

作成例

//オブジェクト指向演習 RPG演習8 3人の魔導士 ver.3
using System;
class Madoshi { //魔導士を表すクラス(部品)
    int mp; //MP
    int hp; //HP
    int id; //魔導士番号
    static int mnum = 0; //【追加】魔導士が何人生成されたか
    static int surv = 0; //【追加】生きている魔導士は何人いるか
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
    public Madoshi () { //【変更】コンストラクタ
        mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
        hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
        mnum++; //【追加】魔導士が何人生成されたかをカウントアップ
        this.id = mnum; //【変更】何人目の魔導士かを得て魔導士番号を設定
        surv = mnum; //【追加】生きている魔導士の数に格納
    }
    public int HP { //HPを返すプロパティ
        get { return hp; } //getのみなので外部からのhpの書換を禁止
    }
    public static bool isSurv { //【以下追加】生きている魔導士がいるかを返すプロパティ
        get { return surv > 0; } //生きている魔導士がいればtrue、いなければfalseを返す
    }
    public void DispInfo() { //魔導士の情報を表示する
        Console.Write("魔道士{0}(HP={1} MP={2})", id, 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~5を返す(攻撃終了)
        }
    }
    public void Damage() { //魔道士があなたからダメージをくらう
        int k = 5 + rnd.Next(5); //あなたの攻撃力は5~9の乱数
        Console.WriteLine("あなたの攻撃!");
        DispInfo(); //魔導士の情報を表示する(攻撃を受けた後の魔道士のHPを表示)
        Console.WriteLine("に" + k + "のダメージを与えた!");
        hp -= k; //魔道士のHPをダウン
        if (hp <= 0) { //【以下追加】倒された?
            surv--; //生きている魔導士の数を減らす
        }
    }
}
class minimadou { //ゲーム本体のクラス
    public static void Main() { //ゲームを進行するメソッド
        const int N = 3; //魔導士の数
        Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
        string ans; //入力用
        // 戦闘開始
        int myhp = 20; // あなたのHP
        Madoshi[] m = new Madoshi[N]; //魔導士の配列を生成
        for (int i = 0; i < N; i++) { //魔導士の数だけ繰返す
            m[i] = new Madoshi(); //【変更】魔導士[i]を生成
            m[i].DispInfo(); //魔道士[i]の情報を表示する
            Console.WriteLine("が現れた。");
        }
        // 戦闘中(あなたが死ぬか,魔道士が死ぬまで繰り返す)
        while (myhp > 0 && Madoshi.isSurv) { //【変更】あなたのHPがあり、生きている魔導士がいる間
            Console.Write("残りHPは{0}です。どれを攻撃しますか?(1/2/3:魔導士を攻撃 0:やめる):", myhp);
            ans = Console.ReadLine(); // 攻撃するかどうかを得る
            if (ans != "0") { //攻撃する?
                int num = int.Parse(ans) - 1; //攻撃対象の魔導士の添字を得る
                m[num].Damage(); //魔道士[num]を攻撃する
                if (Madoshi.isSurv) { //【変更】生きている魔導士がいる?
                    for (int i = 0; i < N; i++) { //魔導士の数だけ繰返す
                        myhp -= m[i].Fight(); //魔道士[i]の攻撃!あなたのHPをマイナス
                    }
                } else { //魔道士のHPがもうない?
                    Console.WriteLine("魔道士を倒した!");
                }
            } else { // やめる?
                if (rnd.Next(2) == 0) { //確率50%で
                    Console.WriteLine("逃げられない!");
                    for (int i = 0; i < N; i++) { //魔導士の数だけ繰返す
                        myhp -= m[i].Fight(); //魔道士[i]の攻撃!あなたのHPをマイナス
                    }
                } else {
                    Console.WriteLine("逃げることができた");
                    break; // 繰り返し終了
                }
            }
            if (myhp <= 0) { //あなたのHPがもうない?
                Console.WriteLine("あなたは死にました。");
            }
        }
    }
}

RPG演習9 3人の魔導士 ver.4

・問題点を1つずつ解決しよう
・乱数オブジェクトを各オブジェクトで持っているので無駄であり、しかも、生成タイミングが一致して同じ乱数系列になりやすい。
・よって、乱数を持つ変数も静的データメンバにしてクラスで1個にし、各オブジェクトで使いまわそう。
・また、せっかく魔導士の数を定数化したのに、表示部分「どれを攻撃しますか?(1/2/3:魔導士を攻撃 0:やめる)」が
 3人固定になっているのも改良しよう
・これは魔導士の数に応じて「1」「1/2」「1/2/3」「1/2/3/4」…の文字列を生成して返すメソッドを作ると良い
・ついでに、プレイヤーの初期HPを魔導士の数だけ増やそう
・また、倒されている魔導士が攻撃に参加してしまうゾンビ状態をなしにしよう
・また「魔道士を倒した!」を「魔道士●を倒した!」と「全ての魔道士を倒した!」にしよう
・そして、すでに倒されている魔導士を攻撃してしまったら「魔道士●はもういない」と表示して先に進むようにしよう

作成例

//オブジェクト指向演習 RPG演習9 3人の魔導士 ver.4
using System;
class Madoshi { //魔導士を表すクラス(部品)
    int mp; //MP
    int hp; //HP
    int id; //魔導士番号
    static int mnum = 0; //魔導士が何人生成されたか
    static int surv = 0; //生きている魔導士は何人いるか
    static Random rnd = new Random(); //【変更】乱数用のRandomクラスのインスタンスを生成
    public Madoshi () { //コンストラクタ
        mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
        hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
        mnum++; //魔導士が何人生成されたかをカウントアップ
        this.id = mnum; //何人目の魔導士かを得て魔導士番号を設定
        surv = mnum; //生きている魔導士の数に格納
    }
    public int HP { //HPを返すプロパティ
        get { return hp; } //getのみなので外部からのhpの書換を禁止
    }
    public static bool isSurv { //生きている魔導士がいるかを返すプロパティ
        get { return surv > 0; } //生きている魔導士がいればtrue、いなければfalseを返す
    }
    public void DispInfo() { //魔導士の情報を表示する
        Console.Write("魔道士{0}(HP={1} MP={2})", id, hp, mp); //表示(改行しない)
    }
    public int Fight() { //魔道士があなたを攻撃し、あなたのダメージ値を返す
        if (hp <= 0) { //【以下追加】すでに倒されていたら
            return 0; //0を返す
        }
        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~5を返す(攻撃終了)
        }
    }
    public void Damage() { //魔道士があなたからダメージをくらう
        if (hp <= 0) { //【以下追加】すでに倒されている?
            Console.WriteLine("魔道士{0}はもういない", id);
            return; //抜ける
        }
        int k = 5 + rnd.Next(5); //あなたの攻撃力は5~9の乱数
        Console.WriteLine("あなたの攻撃!");
        DispInfo(); //魔導士の情報を表示する(攻撃を受けた後の魔道士のHPを表示)
        Console.WriteLine("に" + k + "のダメージを与えた!");
        hp -= k; //魔道士のHPをダウン
        if (hp <= 0) { //倒された?
            Console.WriteLine("魔道士{0}を倒した!", id); //【追加】
            surv--; //生きている魔導士の数を減らす
        }
    }
}
class minimadou { //ゲーム本体のクラス
    const int N = 3; //【移動】魔導士の数
    static string selection() { //【以下追加】魔導士の数に応じて「1」「1/2」「1/2/3」「1/2/3/4」…の文字列を返す
        string ans = "1"; //返す文字列
        for (int i = 1; i < N; i++) { //魔導士の数だけ繰返す
            ans += "/" + (i + 1); 
        }
        return ans;
    }
    public static void Main() { //ゲームを進行するメソッド
        Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
        string ans; //入力用
        // 戦闘開始
        int myhp = 20 * N; //【変更】あなたのHP(20×魔導士の数)
        Madoshi[] m = new Madoshi[N]; //魔導士の配列を生成
        for (int i = 0; i < N; i++) { //魔導士の数だけ繰返す
            m[i] = new Madoshi(); //魔導士[i]を生成
            m[i].DispInfo(); //魔道士[i]の情報を表示する
            Console.WriteLine("が現れた。");
        }
        // 戦闘中(あなたが死ぬか,魔道士が死ぬまで繰り返す)
        while (myhp > 0 && Madoshi.isSurv) { //あなたのHPがあり、生きている魔導士がいる間
            Console.Write("残りHPは{0}です。どれを攻撃しますか?({1}:魔導士を攻撃 0:やめる):", myhp, selection()); //【変更】
            ans = Console.ReadLine(); // 攻撃するかどうかを得る
            if (ans != "0") { //攻撃する?
                int num = int.Parse(ans) - 1; //攻撃対象の魔導士の添字を得る
                m[num].Damage(); //魔道士[num]を攻撃する
                if (Madoshi.isSurv) { //生きている魔導士がいる?
                    for (int i = 0; i < N; i++) { //魔導士の数だけ繰返す
                        myhp -= m[i].Fight(); //魔道士[i]の攻撃!あなたのHPをマイナス
                    }
                } else { //魔道士のHPがもうない?
                    Console.WriteLine("全ての魔道士を倒した!"); //【変更】
                }
            } else { // やめる?
                if (rnd.Next(2) == 0) { //確率50%で
                    Console.WriteLine("逃げられない!");
                    for (int i = 0; i < N; i++) { //魔導士の数だけ繰返す
                        myhp -= m[i].Fight(); //魔道士[i]の攻撃!あなたのHPをマイナス
                    }
                } else {
                    Console.WriteLine("逃げることができた");
                    break; // 繰り返し終了
                }
            }
            if (myhp <= 0) { //あなたのHPがもうない?
                Console.WriteLine("あなたは死にました。");
            }
        }
    }
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です