講義メモ

オブジェクト指向演習: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("あなたは死にました。");
            }
        }
    }
}

今週の話題

ゲームソフト販売本数ランキング:今週1位は「『OVER REQUIEMZ』(オーバーレクイエムズ:Switch)」※未更新 GO!
Nintendo Switch 2の26年度販売予想は1500万台、ソフトは4500万本。任天堂決算資料で明らかに GO!
フロム・ソフトウェアイベントはファンの愛に満ちた空間。歴代アート展示にコスプレ、クイズ大会と企画満載。幕間には『A.C.E.』などの映像も。“FROMSOFTWARE GAMES EVENT Spring 2025 in TOKYO”リポート GO!
対戦型音楽ゲーム『Heavenly Guitars』PC版リリース、ソニーのブロックチェーン「Soneium」と連携 GO!
生成AI活用の『神魔狩りのツクヨミ』がついにリリース―目指すは「中ヒットでも継続できる」ゲーム GO!

トランプ関税により米国内でのゲーム機の価格が約70%上がる可能性―全米民生技術協会が報告書を発表 GO!
ポケットペア、任天堂とポケモンの『パルワールド』訴訟について現状説明―予防的な措置として一部仕様変更も GO!
米国では16歳未満は親同意なしの『原神』ガチャ禁止に。アメリカ連邦取引委員会の訴訟の波紋は GO!

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

ゲーム開発演習(2):フォームサイズの固定化とコントールボックスの非表示、背景画像の表示 など

演習4 フォームの初期位置の指定:再掲載

・フォームの初期位置を(300, 0)にしよう

作成例

//演習4 フォームの初期位置の指定
using System; //C#標準クラス用
using System.Windows.Forms; //C#が提供するApplication、Formクラス用
using System.Drawing; //Sizeクラス用
class Program {
    static void Main() { //実行用メソッド(publicはなくてOK)
        Form f = new Form(); //Formクラスのインスタンスを生成
        f.Text = "Game"; //Form名を設定
        Size s = new Size(640, 480); //幅と高さの大きさのSizeインスタンスを生成
        f.Size = s; //インスタンスプロパティで大きさを設定
        f.StartPosition = FormStartPosition.Manual; //「手動設定」を設定
        Point p = new Point(300,0); //X座標とY座標のPointインスタンスを生成
        f.Location = p; //インスタンスプロパティで初期位置を設定
        Application.Run(f); //生成済のインスタンスを実行
    }
}

テーマ5 フォームサイズの固定化とコントロールボックスの非表示

・特に指定のないフォームはフォームサイズの変更や最大化が可能
・これは固定サイズで開発したいゲームプログラムの場合、弊害を起こすので、フォームサイズを固定化すると良い
・フォームサイズの固定化には、FormのインスタンスプロパティFormBorderStyleに、
 FormBorderStyle列挙体のFixedSingle列挙子などを代入すると良い
 → https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.formborderstyle
・フォームの最大化を防止するには、コントロールボックスを非表示にすると良い
・コントロールボックスを非表示にするには、FormのインスタンスプロパティControlBoxにfalseを代入すればOK
・ただし、フォームの閉じる「×」も非表示になるので、プログラム内にフォームのクローズ処理を記述していない場合は、
 タスクバーで右クリックし「ウィンドウを閉じる」を用いること
・そして、フォームサイズを固定化により、フォームの枠の大きさが変わるので、フォームの大きさの指定方法を変更する必要がある
・FixedSingle等を指定した後に、FormのインスタンスプロパティSizeではなく、CliantSizeに幅と高さの大きさの
 Sizeインスタンスを代入すると良い

演習5 フォームサイズの固定化とコントールボックスの非表示

・フォームのボーダーをFixedSingleにしよう
・コントロールボックスを非表示にしよう
・フォームのSizeではなくClientSizeを640×480にしよう

作成例

//演習5 フォームサイズの固定化とコントールボックスの非表示
using System; //C#標準クラス用
using System.Windows.Forms; //C#が提供するApplication、Formクラス用
using System.Drawing; //Sizeクラス用
class Program {
    static void Main() { //実行用メソッド(publicはなくてOK)
        Form f = new Form(); //Formクラスのインスタンスを生成
        f.Text = "Game"; //Form名を設定
        //Size s = new Size(640, 480); //【削除】幅と高さの大きさのSizeインスタンスを生成
        //f.Size = s; //【削除】インスタンスプロパティで大きさを設定
        f.StartPosition = FormStartPosition.Manual; //「手動設定」を設定
        Point p = new Point(300,0); //X座標とY座標のPointインスタンスを生成
        f.Location = p; //インスタンスプロパティで初期位置を設定
        f.FormBorderStyle = FormBorderStyle.FixedSingle; //【追加】フォームサイズの固定化
        f.ControlBox = false; //【追加】コントールボックスの非表示
        f.ClientSize = new Size(640, 480); //【追加】クライアントサイズの幅と高さを指定
        Application.Run(f); //生成済のインスタンスを実行
    }
}

テーマ6 フォーム上の描画の基礎

・フォームアプリケーションにおいては、プログラム側からの描画だけでなく、システム側からの必要に応じた再描画を行う必要がある
・例えば、フォームの一部が画面の外部になってから内部に戻された場合、システム側で再描画を行う
・C#のフォームアプリケーションはこのことに対応するメソッド protected void OnPaint(PaintEventArgs)メソッドを提供している
・このメソッド内に記述された内容が、システム側からの必要に応じた再描画で自動的に用いられる
・プログラム側からの描画内容をこのメソッド内に記述するには:
 ① プログラムのクラスをFormクラスの派生クラスにする
 ② protected void OnPaint(PaintEventArgs e)メソッドをオーバライドする
 ③ オーバライドの冒頭で、元のメソッドの内容を「base.OnPaint(e);」で呼び出して、基本的な描画処理を行う
 ④ ③の後に、プログラム側からの描画内容を記述する

演習6 プログラム側からの描画内容を記述する準備

・下記の手順。なお、実行結果は(まだ)変わらない
① ProgramクラスをFormクラスの派生クラスにする
② protected void OnPaint(PaintEventArgs e)メソッドのオーバライドメソッドを追記
③ ②の中に、元のメソッドの内容を呼び出す「base.OnPaint(e);」を記述

作成例

//演習6 プログラム側からの描画内容を記述する準備
using System; //C#標準クラス用
using System.Windows.Forms; //C#が提供するApplication、Formクラス用
using System.Drawing; //Sizeクラス用
class Program : Form { //【変更】Formクラスの派生クラス
    protected override void OnPaint(PaintEventArgs e) { //【以下追加】描画処理のオーバライド
        base.OnPaint(e); //元のメソッドの内容を呼び出す
    }
    static void Main() { //実行用メソッド(publicはなくてOK)
        Program f = new Program(); //【変更】自クラスのインスタンスを生成
        f.Text = "Game"; //Form名を設定
        f.StartPosition = FormStartPosition.Manual; //「手動設定」を設定
        Point p = new Point(300,0); //X座標とY座標のPointインスタンスを生成
        f.Location = p; //インスタンスプロパティで初期位置を設定
        f.FormBorderStyle = FormBorderStyle.FixedSingle; //フォームサイズの固定化
        f.ControlBox = false; //コントールボックスの非表示
        f.ClientSize = new Size(640, 480); //クライアントサイズの幅と高さを指定
        Application.Run(f); //生成済のインスタンスを実行
    }
}

提出:演習6 プログラム側からの描画内容を記述する準備

講義メモ

オブジェクト指向演習:プロパティの導入とゲーム性の向上&重複の防止
ゲーム開発演習:フォームサイズの固定化とコントールボックスの非表示、背景画像の表示 など

オブジェクト指向演習(2)

【ha243 解説編より】プロパティ:再掲載

・プロパティは特殊なメソッドで、データメンバを安全に扱う仕組みを提供する
・データメンバをpublicにしておくと、外部から想定外の値を代入されたり、想定外の用途に使われてしまう可能性がある
 例:身長に負の数。計算で決まるはずのプレイヤーの経験値を直接操作。
・そこで、重要なデータメンバはprivate(または無指定でprivate扱い)にする
・データメンバの値を得ることをget、値を書き換えることをsetといい、合わせてアクセッサという
・プロパティはgetとsetのどちらかまたは両方を記述して、publicではないデータメンバを扱う仕組みを外部に提供する
・最も基本的な定義例:
 private 型 データメンバ名;
 public 型 プロパティ名 {
  set { データメンバ名 = value; }
  get { return データメンバ名; }
 }
・このように定義すると、外部から「データメンバ名 = 値;」の代わりに「プロパティ名 = 値;」とすることで、
 データメンバに代入できる。
・この時、プロパティのsetが動作し、値はvalueに渡される。
・また「Console.WriteLine(プロパティ名 )」などとすることでデータメンバの値を表示できる。
・この時、プロパティのgetが動作し、データメンバの値がreturnされる。
・この仕掛けを用いて、setを省略することで、変更不能のデータメンバにできる
 private 型 データメンバ名;
 public 型 プロパティ名 {
  get { return データメンバ名; }
 }
・また、この仕掛けを用いて、setに条件を記述できる
 private 型 データメンバ名;
 public 型 プロパティ名 {
  set { 
   if (value >= 0) {
    データメンバ名 = value;
   }
  }
  get { return データメンバ名; }
 }

RPG演習3

・MadoshiクラスのHPを返すメソッドをプロパティHPにしよう
・また、魔導士の情報を表示するメソッドにMPの表示を追加しよう

作成例

//オブジェクト指向演習 RPG演習3
using System;
class Madoshi { //魔導士を表すクラス(部品)
    int mp; //MP
    int hp; //HP
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
    public Madoshi () { //コンストラクタ
        mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
        hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
    }
    public int HP { //【以下変更】HPを返すプロパティ
        get { return hp; } //getのみなので外部からのhpの書換を禁止
    }
    public void DispInfo() { //魔導士の情報を表示する
        Console.Write("魔道士(HP={0} MP={1})", hp, mp); //【変更】HPMPを表示(改行しない)
    }
    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() { //ゲームを進行するメソッド
        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; // 繰り返し終了
            }
        }
    }
}

ゲーム性の向上&重複の防止

・「0:やめる」を選んだ場合がゲーム終了になるのではなく、終了するか魔導士の攻撃になるかの分岐にすると、ゲーム性が向上する。
・この分岐の確率をどうするかはゲームデザインの一つになるが、特に必要なければ確率5割で良い。
・なお、「0:やめる」を選んだ後に、魔導士の攻撃ターンを挟まずに再度選択に進むようなことにならないように注意。
・このような改良により、同じ処理が2か所できてしまうことが多いので、ロジックを見直して1か所にまとめられるように工夫すると
 ミスの防止や保守性(改良しやすさ)の向上につながる

RPG演習3

・「攻撃しますか?」で「0:やめる」を選んだ場合、確率5割で「逃げられない」か「逃げることができた」のどちらかを
 表示するようにしよう。
・そして「逃げられない」を表示した場合、魔導士の攻撃ターンに進もう。
・「逃げることができた」を表示した場合、繰返し終了としよう。
・また「あなたのHPがもうない?」のチェックが重複しないように、判断の位置を見直そう。
・なお、魔導士の攻撃ターンの重複はそのままでOK(この後の改造に関連するので)。

作成例:途中(重複の防止をする前まで)

//オブジェクト指向演習 RPG演習4(途中まで)
using System;
class Madoshi { //魔導士を表すクラス(部品)
    int mp; //MP
    int hp; //HP
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
    public Madoshi () { //コンストラクタ
        mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
        hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
    }
    public int HP { //HPを返すプロパティ
        get { return hp; } //getのみなので外部からのhpの書換を禁止
    }
    public void DispInfo() { //魔導士の情報を表示する
        Console.Write("魔道士(HP={0} MP={1})", hp, mp); //HPMPを表示(改行しない)
    }
    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() { //ゲームを進行するメソッド
        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をマイナス
                    if (myhp <= 0) { // あなたのHPがもうない?
                        Console.WriteLine("あなたは死にました。");
                    }
                } else { // 魔道士のHPがもうない?
                    Console.WriteLine("魔道士を倒した!");
                }
            } else { // やめる?
                if (rnd.Next(2) == 0) { //【以下追加】確率50%で
                    Console.WriteLine("逃げられない!");
                    myhp -= m.Fight(); // 魔道士の攻撃!あなたのHPをマイナス:重複
                    if (myhp <= 0) { // あなたのHPがもうない?:以下重複
                        Console.WriteLine("あなたは死にました。");
                    }
                } else { //【追加】
                    Console.WriteLine("逃げることができた"); //【追加】
                    break; // 繰り返し終了
                }
            }
        }
    }
}

作成例

//オブジェクト指向演習 RPG演習4
using System;
class Madoshi { //魔導士を表すクラス(部品)
    int mp; //MP
    int hp; //HP
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
    public Madoshi () { //コンストラクタ
        mp = rnd.Next(10); //0~9の間のランダムな整数を得てMPの初期値とする
        hp = 10 + rnd.Next(10); //10~19の間のランダムな整数を得てHPの初期値とする
    }
    public int HP { //HPを返すプロパティ
        get { return hp; } //getのみなので外部からのhpの書換を禁止
    }
    public void DispInfo() { //魔導士の情報を表示する
        Console.Write("魔道士(HP={0} MP={1})", hp, mp); //HPMPを表示(改行しない)
    }
    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() { //ゲームを進行するメソッド
        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をマイナス
                    // if (myhp <= 0) { //【ここから移動】あなたのHPがもうない?
                    //    Console.WriteLine("あなたは死にました。");
                    // }
                } else { // 魔道士のHPがもうない?
                    Console.WriteLine("魔道士を倒した!");
                }
            } else { // やめる?
                if (rnd.Next(2) == 0) { //【以下追加】確率50%で
                    Console.WriteLine("逃げられない!");
                    myhp -= m.Fight(); // 魔道士の攻撃!あなたのHPをマイナス
                } else { //【追加】
                    Console.WriteLine("逃げることができた"); //【追加】
                    break; // 繰り返し終了
                }
            }
            if (myhp <= 0) { //【ここへ移動】あなたのHPがもうない?
                Console.WriteLine("あなたは死にました。");
            }
        }
    }
}

「3人の魔導士」に向けて

・魔導士の人数を複数化したい
・まずは「1人の魔導士」として開発し、Madoshiクラスの実装を確認しよう
・Madoshiクラスの改造ポイント
 ①魔導士番号のint型インスタンス変数idを追加する
 ②コンストラクタにint型引数idを追加し、生成時に魔導士番号を指定できるようにする
 ③魔導士の情報を表示するメソッドで魔導士番号も表示しよう

RPG演習5 3人の魔導士 ver.0

・上記の「Madoshiクラスの改造ポイント」を実装し、動作を確認しよう

作成例:

//オブジェクト指向演習 RPG演習5
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() { //ゲームを進行するメソッド
        Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
        string ans; //入力用
        // 戦闘開始
        int myhp = 20; // あなたのHP
        Madoshi m = new Madoshi(1); //【変更】魔道士1を生成
        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("逃げられない!");
                    myhp -= m.Fight(); // 魔道士の攻撃!あなたのHPをマイナス
                } else {
                    Console.WriteLine("逃げることができた");
                    break; // 繰り返し終了
                }
            }
            if (myhp <= 0) { //あなたのHPがもうない?
                Console.WriteLine("あなたは死にました。");
            }
        }
    }
}

続「3人の魔導士」に向けて

・インスタンスオブジェクトを複数化して、同じ処理を行わせるので、インスタンスオブジェクトの配列にすると良い

補足:インスタンスオブジェクトの配列について

・初期化と同時に配列を生成する書式と、配列名を要素の数を指定して用意して、各インスタンスを生成する書式がある
・今回は後者を用いよう
① クラス名[] 配列名 = new クラス名[要素数];
② 配列名[添字] = new クラス名(引数); を、全要素について繰り返す

RPG演習6 3人の魔導士 ver.1

・1人の魔導士のままで、魔導士オブジェクトを長さ1の配列で扱うようにしよう
・配列の生成はMain()メソッドで行う

作成例:

//オブジェクト指向演習 RPG演習6 3人の魔導士 ver.1
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() { //ゲームを進行するメソッド
        Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
        string ans; //入力用
        // 戦闘開始
        int myhp = 20; // あなたのHP
        Madoshi[] m = new Madoshi[1]; //【追加】魔導士の配列を生成 
        m[0] = new Madoshi(1); //【変更】魔道士1を魔導士[0]に生成
        m[0].DispInfo(); //【変更】魔道士[0]の情報を表示する
        Console.WriteLine("が現れた。");
        // 戦闘中(あなたが死ぬか,魔道士が死ぬまで繰り返す)
        while (myhp > 0 && m[0].HP > 0) { //【変更】あなたのHPがあり、魔導士[0]のHPがある間
            Console.Write("残りHPは{0}です。攻撃しますか?(1:はい 0:やめる):", myhp);
            ans = Console.ReadLine(); // 攻撃するかどうかを得る
            if (ans == "1") { // はい?
                m[0].Damage(); //【変更】魔道士[0]を攻撃する
                if (m[0].HP > 0) { //【変更】魔道士[0]は死んでない?
                    myhp -= m[0].Fight(); //【変更】魔道士[0]の攻撃!あなたのHPをマイナス
                } else { //魔道士のHPがもうない?
                    Console.WriteLine("魔道士を倒した!");
                }
            } else { // やめる?
                if (rnd.Next(2) == 0) { //確率50%で
                    Console.WriteLine("逃げられない!");
                    myhp -= m[0].Fight(); //【変更】魔道士[0]の攻撃!あなたのHPをマイナス
                } else {
                    Console.WriteLine("逃げることができた");
                    break; // 繰り返し終了
                }
            }
            if (myhp <= 0) { //あなたのHPがもうない?
                Console.WriteLine("あなたは死にました。");
            }
        }
    }
}

今週の話題

ゲームソフト販売本数ランキング:今週1位は「『OVER REQUIEMZ』(オーバーレクイエムズ:Switch)」GO!
任天堂、スイッチ2需要に追いつかず「深くお詫び」 抽選販売に220万人応募、落選者は二次抽選に自動応募 GO!
【Switch2】セブンネットショッピングで予約抽選が開始。応募条件はいまから1000円以上買う&メルマガ登録 GO!
スイッチ2はPS4/XB1と比べメモリやパフォーマンス良好で助かった―『サイバーパンク2077』移植についてCDPRコメント GO!

スイッチ2抽選結果のメールは“URLが記載されていない”ことに注意!結果報告がSNS上にてトレンドをにぎわすなかサポートより注意喚起 GO!
海外大手Modサイト、『オブリビオン』リマスターのキャラクタ性別選択肢復活Modを削除、アカウント停止措置まで。「タイプ1・2」を「男性・女性」に戻す投稿の「意図」問題視 GO!

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

ゲーム開発演習:フォームの表示と設定

解説:フォームプログラミング

・グラフィックス、サウンドと、マウスなどのポインティングディバイスを用いるプログラムをC#で開発するには、
 フォームアプリケーションのプロジェクトを用いると良い
・Unityなどの専用ツールを用いる場合に比べて自由度が高くなる(ただし記述量や求められる知識は増える)
・よって、将来いろいろな開発ツールを利用できるようになるための、基礎力をつけることに向いている
・プロジェクトの作成方法
①「新しいプロジェクトの作成」
②「C#」「Windowsフォームアプリケーション(.NET Framework)」「次へ」
③ 適当なプロジェクト名、場所(USBメモリ推奨)などを指定して「作成」
④ フォームデザインが表示されるが、プログラム側で設定・制御するので、閉じてOK
⑤ 代わりに「Program.cs」を開くと、フォームアプリケーションのスケルトンが表示され、利用可能になる
⑥ このソースは冗長なので、下記のようにシンプルにできる

using System;
using System.Windows.Forms;
class Program {
    static void Main() {
        Application.Run(new Form());
    }
}

⑦「デバッグなしで開始」で実行でき、コンソールではなくフォームが表示される
⑧ 確認したらフォームの右上の「×」で必ず閉じる(開けたまま再実行するとエラーになる)

演習0 フォームアプリケーションの実行確認:作成例

//演習0 フォームアプリケーションの実行確認
using System; //C#標準クラス用
using System.Windows.Forms; //C#が提供するApplication、Formクラス用
class Program {
    static void Main() { //実行用メソッド(publicはなくてOK)
        Application.Run(new Form()); //C#が提供するFormクラスのインスタンスを生成し実行
    }
}

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

・フォームの大きさは、FormクラスのインスタンスプロパティWidthに幅のドット数、Heightに高さのドット数を与えることで設定できる
・インスタンスプロパティを用いるには、あらかじめ、Formクラスのインスタンスを生成しておくと良い
・この時、指定したインスタンス名(参照変数)を用いて、インスタンスプロパティを利用できる
・そして、指定したインスタンス名をApplication.Runに渡すようにしよう
例:
 Form インスタンス名 = new Form();
 インスタンス名.Width = 幅のドット数
 インスタンス名.Height = 高さのドット数
 Application.Run(インスタンス名); 

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

・フォームの幅を640、高さを480にしよう

作成例

//演習1 フォームサイズの指定
using System; //C#標準クラス用
using System.Windows.Forms; //C#が提供するApplication、Formクラス用
class Program {
    static void Main() { //実行用メソッド(publicはなくてOK)
        Form f = new Form(); //Formクラスのインスタンスを生成
        f.Width = 640; //インスタンスプロパティで幅を設定
        f.Height = 480; //インスタンスプロパティで高さを設定
        Application.Run(f); //生成済のインスタンスを実行
    }
}

テーマ2 フォームサイズの一括指定

・フォームの幅(Width)と高さ(Height)は、まとめて大きさ(Size)として扱うことができる
・FormクラスのインスタンスプロパティSizeに、System.Drawing.Sizeクラスのオブジェクトを与えることで一括指定が可能
・Sizeクラスの利用には「using System.Drawing;」を指定すると良い
・Sizeクラスのオブジェクトに幅と高さを与えるには、Sizeクラスのコストラクタ(int 幅, int 高さ)を用いると良い
例:
 Form インスタンス名① = new Form();
 Size インスタンス名② = new Size(幅のドット数, 高さのドット数);
 インスタンス名①.Size = インスタンス名②;
 Application.Run(インスタンス名①); 

演習2 フォームサイズの一括指定

・Sizeクラスのオブジェクトを用いて、フォームの幅を640、高さを480にしよう

作成例

//演習2 フォームサイズの一括指定
using System; //C#標準クラス用
using System.Windows.Forms; //C#が提供するApplication、Formクラス用
using System.Drawing; //Sizeクラス用
class Program {
    static void Main() { //実行用メソッド(publicはなくてOK)
        Form f = new Form(); //Formクラスのインスタンスを生成
        Size s = new Size(640, 480); //幅と高さの大きさのSizeインスタンスを生成
        f.Size = s; //インスタンスプロパティで大きさを設定
        Application.Run(f); //生成済のインスタンスを実行
    }
}

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

・フォーム名はFormクラスのインスタンスプロパティTextに文字列を代入することで設定できる
・フォーム名はWindowsからみたアプリケーション名になるので、予め設定しておくと良い

演習3 フォーム名の指定

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

作成例

//演習3 フォーム名の指定
using System; //C#標準クラス用
using System.Windows.Forms; //C#が提供するApplication、Formクラス用
using System.Drawing; //Sizeクラス用
class Program {
    static void Main() { //実行用メソッド(publicはなくてOK)
        Form f = new Form(); //Formクラスのインスタンスを生成
        f.Text = "Game"; //Form名を設定
        Size s = new Size(640, 480); //幅と高さの大きさのSizeインスタンスを生成
        f.Size = s; //インスタンスプロパティで大きさを設定
        Application.Run(f); //生成済のインスタンスを実行
    }
}

補足:Formクラスについて

・APIリファレンスで仕様を確認しよう
 https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.form
・Formクラスのコンストラクタはデフォルトしかなく、引数を指定できるコンストラクタはない
・プロパティが大量にあり、Height、Size、Text、Widthが含まれている

テーマ4 フォームの初期位置の指定

・FormクラスのインスタンスプロパティStartPositionに「手動設定」を設定すると、初期位置を指定できる
・手動設定には、System.Windows.Forms.FormStartPosition列挙体のManual列挙子を用いると良い
・すると、FormクラスのインスタンスプロパティLocationに、初期位置の座標を指定できる
・座標指定には、System.Drawing.Pointクラスのコストラクタ(int X座標 int Y座標)を用いると良い
例:
 Form インスタンス名① = new Form();
 インスタンス名①.StartPosition = FormStartPosition.Manual;
 Pointインスタンス名② = new Point(X座標, Y座標);
 インスタンス名①.Location = ②;

演習4 フォームの初期位置の指定

・フォームの初期位置を(300, 0)にしよう

提出:演習4 フォームの初期位置の指定

講義メモ

・オブジェクト指向演習①
・ゲーム開発演習:フォームの表示と設定

オブジェクト指向演習①

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

予備知識:乱数の利用

・ゲームやシミュレーションなどで多用される「毎回異なる値が得られる仕掛け」を乱数(Random)という
・乱数はシステムが用意している系列によって提供されるので、系列を決める基礎値であるシード(種)が等しいと
 同じ系列になり、弊害が起こるので注意
・C#では、内部的に現在の時刻情報を数値化してシードにすることで、毎回、予測できない乱数になる
・乱数を用いるには、C#が標準で提供する System.Randomクラスのデフォルトコンストラクタでインスタンスを生成し、
 インスタンスメソッド Next(int n)を用いると、0以上n未満の整数が得られる。
例:
 using System;
 :
 System.Random r = new System.Random();
 Console.WriteLine(r.Next(3)); //0,1,2のどれかが表示される

予備知識:乱数の利用 サンプル codefile1.cs

//予備知識:乱数の利用 サンプル
using System;
class codefile1 {
    public static void Main() {
        Random r = new Random();
        Console.WriteLine(r.Next(3)); //0,1,2のどれかが表示される
    }
}

RPG演習1 仕様

・魔道士とプレイヤーが戦うゲーム
・詳細はスケルトンのコメントを読み解いて理解してください
・ソースファイル名は「rpg.cs」とします

実行例

魔道士(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 { // やめる?
                ●// 繰り返し終了
            }
        }
    }
}

【ha243 解説編より】コンストラクタ

・C#のインスタンス(オブジェクト)はクラスや構造体を設計図として用いてメモリ上の生成されたもののこと
・この生成を行うのがnew演算子
・new演算子を実行すると、その後に記述されている内容に応じてコンストラクタが呼びだされる
・例えば、Slime slalin = new Slime(); とするとコンストラクタ「Slime()」が呼び出される
・C#では、クラスや構造体を定義すると内部的に「クラス名()」「構造体名()」のコンストラクタが自動的に用意されるので(中身は空)
 記述しなくてもOK。
・必要であれば、プログラマが記述することもできる
・記述する場合の目的は、準備作業であり、データメンバの値の設定やオブジェクトで行いたい処理の前処理などに用いる
・「Vector3 pos2 = new Vector3(2.0f, 4.0f, 0.0f);」のように、コンストラクタに引数を定義しておいて値を渡すことが可能。
・コンストラクタは特殊なメソッドで、名前が無く(クラス名や構造体名が名前になる)戻り値もないのが特徴。

【ha243 解説編より】break

・while/for/do-whileの繰り返しの最中に、なんらかの理由で繰り返しを終了したい場合、「break;」文を実行すると良い
・例外的な事態が発生した場合に用いる事が多い。
・または、繰り返しの継続条件が複数あり、複雑な場合、主たる継続条件をwhile/for/do-while文に書いておき、
 中断条件があれば、if文で判断してbreak文で抜けることも多い
・なお、break文の直後になんらかの文を記述すると、絶対に実行されないため、文法エラーになる
・break文は終了文ではなく、while/for/do-whileの末尾の「}」の後ろへのジャンプになり、後続の処理が実行される

作成例

//オブジェクト指向演習 RPG演習1
using System;
class Madoshi { //魔導士を表すクラス(部品)
    int mp; //MP
    int hp; //HP
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
    public Madoshi () { //コンストラクタ
        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~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() { //ゲームを進行するメソッド
        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; // 繰り返し終了
            }
        }
    }
}

RPG演習2

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

作成例

//オブジェクト指向演習 RPG演習2
using System;
class Madoshi { //魔導士を表すクラス(部品)
    int mp; //MP
    int hp; //HP
    Random rnd = new Random(); //乱数用のRandomクラスのインスタンスを生成
    public Madoshi () { //コンストラクタ
        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~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() { //ゲームを進行するメソッド
        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; // 繰り返し終了
            }
        }
    }
}

【ha243 解説編より】プロパティ

・プロパティは特殊なメソッドで、データメンバを安全に扱う仕組みを提供する
・データメンバをpublicにしておくと、外部から想定外の値を代入されたり、想定外の用途に使われてしまう可能性がある
 例:身長に負の数。計算で決まるはずのプレイヤーの経験値を直接操作。
・そこで、重要なデータメンバはprivate(または無指定でprivate扱い)にする
・データメンバの値を得ることをget、値を書き換えることをsetといい、合わせてアクセッサという
・プロパティはgetとsetのどちらかまたは両方を記述して、publicではないデータメンバを扱う仕組みを外部に提供する
・最も基本的な定義例:
 private 型 データメンバ名;
 public 型 プロパティ名 {
  set { データメンバ名 = value; }
  get { return データメンバ名; }
 }
・このように定義すると、外部から「データメンバ名 = 値;」の代わりに「プロパティ名 = 値;」とすることで、
 データメンバに代入できる。
・この時、プロパティのsetが動作し、値はvalueに渡される。
・また「Console.WriteLine(プロパティ名 )」などとすることでデータメンバの値を表示できる。
・この時、プロパティのgetが動作し、データメンバの値がreturnされる。
・この仕掛けを用いて、setを省略することで、変更不能のデータメンバにできる
 private 型 データメンバ名;
 public 型 プロパティ名 {
  get { return データメンバ名; }
 }
・また、この仕掛けを用いて、setに条件を記述できる
 private 型 データメンバ名;
 public 型 プロパティ名 {
  set { 
   if (value >= 0) {
    データメンバ名 = value;
   }
  }
  get { return データメンバ名; }
 }

基礎コース最終回の講義メモとご案内

講義メモ:memo20250315.txt

ご案内:
・このサイトは残しておきますがいつかは消えますのでご了承ください
・なお、来月からの応用コースにおいて、このサイトをそのまま用いますので、応用コースを受講しない方も閲覧可能です
(ただし、応用コースの内容に関する質問はご遠慮ください)
・【ご参考】ゲーム開発で学ぶC言語入門 プロのクリエイターが教える基本文法と開発技法 GO!
 ※来月からのヒューマンアカデミーのプログラマ専攻1年生の講義で用います(私が担当します)
・池田さん、メッセージをありがとうございました。