オブジェクト指向演習:プロパティの導入とゲーム性の向上&重複の防止
ゲーム開発演習:フォームサイズの固定化とコントールボックスの非表示、背景画像の表示 など
オブジェクト指向演習(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("あなたは死にました。");
}
}
}
}