・オブジェクト指向演習①
・ゲーム開発演習:フォームの表示と設定
オブジェクト指向演習①
・コンソールアプリケーションによる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 データメンバ名; }
}