おもしろそうな動画をみつけたので真似をしてC#で「信長の野望」もどきを作ってみます。
面白いかどうかは別にして乱数をつかって敵を動作させればゲームっぽいものは簡単にできそうです。プログラミングを覚えた当初は嬉々としてこんなプログラムを作成して、周囲の人をあきれさせていました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
int a = 50; int b = 50; Random random = new Random(); while (true) { int r = random.Next(10); b -= r; MessageBox.Show(String.Format("Aの攻撃! Bに{0}のダメージ", r)); if (b < 0) break; r = random.Next(10); a -= r; MessageBox.Show(String.Format("Bの攻撃! Aに{0}のダメージ", r)); if (a < 0) break; } if (a > 0) MessageBox.Show("Aは勝ちました。正義は勝つ!"); else MessageBox.Show("Aは負けました。次こそ勝つ!"); |
もちろんBの名前は嫌いな人の名前にします。どうです?最悪でしょう。
いまからつくる「信長の野望」もどきはブラウザアプリでもつくってみたいのでメッセージボックスやダイアログがでてくるようなものにはしたくありません。自分の行動を決めるときだけ必要なボタンをおして、あとはEnterキーをおすとメッセージがひとつずつでてくるファミコンのようなゲームをつくってみたいと考えています。
そこでこのようなコードを作成してみました。
攻撃ボタンをおすと乱数が生成され、これが敵に対するダメージになります。自分の攻撃がおわると敵の攻撃です。やはり乱数を生成して、これを自分に対するダメージとします。また防御すると体力が10回復します。
処理の結果、表示するメッセージはstringのリストであるMessagesのなかにAddしていきます。自分の行動を決定すると表示するメッセージがすべて表示されてしまうまで次のコマンドの入力できないようにしています。
「次へ」のボタンをおすと自作メソッド ShowFirstMessage()が呼び出されます。ShowFirstMessageメソッドでは一番最初にAddされたメッセージから表示されます。表示されたメッセージはリストから取り除かれます。メッセージリストが空になったらお互いのLifeが0以下になっていないか調べます。もしどちらかが0以下になっていれば戦闘は終了です。対戦結果と「闘いは終わった!」というメッセージを表示させます。
どちらもLifeが0よりも大きい値の場合は戦闘継続です。コマンド入力後、いったん非表示にしていた「攻撃」「防御」ボタンを表示させ、つぎの行動をユーザーに入力させます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); } int yourLife = 100; int enemyLife = 100; Random random = new Random(); List<string> Messages = new List<string>(); private void Form1_Load(object sender, EventArgs e) { label1.Text = String.Format("あなた:{0} 敵:{1}", yourLife, enemyLife); label2.Text = ""; } private void buttonAttack_Click(object sender, EventArgs e) { this.buttonAttack.Visible = false; this.buttonGuard.Visible = false; int r = random.Next(20); enemyLife -= r; Messages.Add(String.Format("あなたの攻撃。敵に{0}のダメージを与えた!", r)); if (enemyLife > 0) { r = random.Next(20); yourLife -= r; Messages.Add(String.Format("敵の攻撃。あなたは{0}のダメージを受けた!", r)); } ShowFirstMessage(); } private void buttonGuard_Click(object sender, EventArgs e) { this.buttonAttack.Visible = false; this.buttonGuard.Visible = false; yourLife += 10; Messages.Add("あなたは防御した。あなたの体力が10回復した!"); int r = random.Next(10); r = random.Next(10); yourLife -= r; Messages.Add(String.Format("敵の攻撃。あなたは{0}のダメージを受けた!", r)); ShowFirstMessage(); } private void buttonNext_Click(object sender, EventArgs e) { ShowFirstMessage(); } void ShowFirstMessage() { if (Messages.Count > 0) { string str = Messages[0]; Messages.RemoveAt(0); label2.Text = str; } else { // リストのなかのメッセージをすべて表示したとき、 // 一方が全滅している場合があるかもしれない。 if (yourLife < 0) yourLife = 0; if (enemyLife < 0) enemyLife = 0; label1.Text = String.Format("あなた:{0} 敵:{1}", yourLife, enemyLife); // どちらも全滅していない。戦闘継続するため[攻撃][防御]のボタンを表示させる if (yourLife > 0 && enemyLife > 0) { this.buttonAttack.Visible = true; this.buttonGuard.Visible = true; } else { // 一方が全滅した。戦闘継続はないので[攻撃][防御]のボタンは表示させない if (enemyLife == 0) label2.Text = String.Format("あなたは敵を倒した!闘いは終わった!"); if (yourLife == 0) label2.Text = String.Format("あなたは敵に敗北した!闘いは終わった!"); } } } } |
ところで攻撃にしても防御にしてもおたがいのLifeは最後にならないと表示されません。自分が攻撃した結果が表示されたときに表示されている敵のLifeが減り、敵に攻撃されたときにはその結果が表示されたといに自分のLifeが減るようにしたいものです。
これを実装するためにはMessagesからメッセージのリストを表示するときにそのときの状態を表示する仕様にしなければなりません。Messagesに格納するのは文字列だけでなく、自分と敵の状態もそのときに格納しておかないといけないということになります。
そこでフィールド変数の
1 2 |
List<string> Messages = new List<string>(); // このフィールド変数は廃止する |
はやめて、ほかの方法を考えます。
Situationsというクラスを作成します。いま状況を表示するうえで必要なのは、自分と敵のLife、表示するメッセージだけです。そこでこんなクラスを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Situation { public Situation(string message, int yourLife, int enemyLife) { Message = message; YourLife = yourLife; EnemyLife = enemyLife; } public string Message = ""; public int YourLife = 0; public int EnemyLife = 0; } |
そしてフォームクラスにおける以下のようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); } int yourLife = 100; int enemyLife = 100; Random random = new Random(); List<Situation> Situations = new List<Situation>(); private void Form2_Load(object sender, EventArgs e) { label1.Text = String.Format("敵に襲われた。あなた:{0} 敵:{1}", yourLife, enemyLife); label2.Text = ""; // 最初は[次へ]ボタンはクリックされてはいけないので非表示にする this.buttonNext.Visible = false; } private void buttonAttack_Click(object sender, EventArgs e) { // 攻撃結果がすべて表示されるまでに[攻撃][防御]ボタンはクリックされてはいけないので非表示にする // 代わりに[次へ]ボタンはクリックできるようにする this.buttonAttack.Visible = false; this.buttonGuard.Visible = false; this.buttonNext.Visible = true; int r = random.Next(20); enemyLife -= r; // 負数になった場合はゼロにする if (enemyLife < 0) enemyLife = 0; Situations.Add(new Situation(String.Format("あなたの攻撃。敵に{0}のダメージを与えた!", r), yourLife, enemyLife)); if (enemyLife > 0) { r = random.Next(20); yourLife -= r; // 負数になった場合はゼロにする if (yourLife < 0) yourLife = 0; Situations.Add(new Situation(String.Format("敵の攻撃。あなたは{0}のダメージを受けた!", r), yourLife, enemyLife)); } ShowFirstMessage(); } private void buttonGuard_Click(object sender, EventArgs e) { // 防御結果がすべて表示されるまでに[攻撃][防御]ボタンはクリックされてはいけないので非表示にする // 代わりに[次へ]ボタンはクリックできるようにする this.buttonAttack.Visible = false; this.buttonGuard.Visible = false; this.buttonNext.Visible = true; yourLife += 10; Situations.Add(new Situation("あなたは防御した。あなたの体力が10回復した!", yourLife, enemyLife)); int r = random.Next(10); r = random.Next(10); yourLife -= r; if (yourLife < 0) yourLife = 0; Situations.Add(new Situation(String.Format("敵の攻撃。あなたは{0}のダメージを受けた!", r), yourLife, enemyLife)); ShowFirstMessage(); } private void buttonNext_Click(object sender, EventArgs e) { ShowFirstMessage(); } void ShowFirstMessage() { if (Situations.Count > 0) { Situation situation = Situations[0]; Situations.RemoveAt(0); label1.Text = String.Format("あなた:{0} 敵:{1}", situation.YourLife, situation.EnemyLife); label2.Text = situation.Message; } else { if (yourLife > 0 && enemyLife > 0) { // ユーザーに次の行動を選択させる // [攻撃][防御]ボタンはクリックできるようにするにする // [次へ]ボタンは非表示にしてクリックできないようにする label1.Text = String.Format("あなた:{0} 敵:{1}。次の行動を決めてください。", yourLife, enemyLife); this.buttonAttack.Visible = true; this.buttonGuard.Visible = true; this.buttonNext.Visible = false; } else { label1.Text = String.Format("あなた:{0} 敵:{1}。", yourLife, enemyLife); if (enemyLife <= 0) label2.Text = String.Format("あなたは敵を倒した!闘いは終わった!"); if (yourLife <= 0) label2.Text = String.Format("あなたは敵に敗北した!闘いは終わった!"); } } } } |
今回はアプリケーションの準備作業であり、信長の野望とはぜんぜん関係ない内容でした。次回からは信長の野望っぽいものをつくります。