単純なゲームをつくります。フォーム上に1~25の文字が表示されていて、1から順に25までクリックするという極めて単純なものです。全部終わるまでの時間も計測します。実際にやってみると次にクリックすべき数字が見つからなくて軽いパニック状態になれます。
まずForm1クラスのコンストラクタで25個のLabelをリストに入れてしまいます。こうすればLabels[i]とやればアクセスできるようになります。label1とかlabel2とかlabel3とかいちいち書いていられません。
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 |
public partial class Form1 : Form { List<Label> Labels = new List<Label>(); public Form1() { InitializeComponent(); InitLabels(); } void InitLabels() { Labels = CreateLabelList(); SetFontLabels(Labels); SetClickEvent(Labels); } List<Label> CreateLabelList() { List<Label> labels = new List<Label>(); labels.Add(label1); labels.Add(label2); labels.Add(label3); labels.Add(label4); labels.Add(label5); labels.Add(label6); labels.Add(label7); labels.Add(label8); labels.Add(label9); labels.Add(label10); labels.Add(label11); labels.Add(label12); labels.Add(label13); labels.Add(label14); labels.Add(label15); labels.Add(label16); labels.Add(label17); labels.Add(label18); labels.Add(label19); labels.Add(label20); labels.Add(label21); labels.Add(label22); labels.Add(label23); labels.Add(label24); labels.Add(label25); return labels; } void SetFontLabels(List<Label> labels) { foreach (Label label in labels) { label.Font = new Font(label.Font.Name, 16, FontStyle.Bold); label.TextAlign = ContentAlignment.MiddleCenter; } } } |
ラベルをリストに格納したらクリックイベントを処理できるようにしてしまいましょう。デザイナでClickと書いている部分をひとつひとつクリックしていては時間がかかるだけです。ラベルをリストに格納してしまったわけですから、ループ文でやってしまいましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Form1 : Form { void SetClickEvent(List<Label> labels) { foreach (Label label in labels) { label.Click += Label_Click; } } private void Label_Click(object sender, EventArgs e) { // どう書くか? } } |
ゲームをスタートさせる処理としては、ラベル上に1~25の数字をセットします。またラベルがクリックされたことでどの数字が選択されたのかわかるようにしておきます。Label.Tagに数値をセットすればいいのではないでしょうか?
CreateRandomNumber()メソッドでは仮のリストに1~25を格納して、最大値が(仮のリストの要素数 – 1)になる乱数を発生させ、その要素を引き抜いて新しいリストに追加します。これを仮のリストの要素数が0になるまで繰り返します。
こうしてつくられた整数リストをSetRandomNumber(List<int> vs)に渡してラベルに数字を表示させます。それと同時にLabel.Tagにも数値をセットします。
最後にフィールド変数 RandomNumbersにランダムに並べ替えられた整数のリストをセットするとともに、最後にクリックされた数は0とし、これをフィールド変数 LastClickedNumber に代入します。
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 |
public partial class Form1 : Form { // ここにランダムな順番に並べ替えられた整数が入る List<int> RandomNumbers = new List<int>(); // 最後にクリックされた数 int LastClickedNumber = 0; private void Form1_Load(object sender, EventArgs e) { GameStart(); } void GameStart() { List<int> vs = CreateRandomNumber(); SetRandomNumber(vs); RandomNumbers = vs; LastClickedNumber = 0; // 最後にクリックされた数の初期値は0 } List<int> CreateRandomNumber() { List<int> vs = new List<int>(); for (int i = 1; i <= 25; i++) { vs.Add(i); } List<int> ret = new List<int>(); Random r = new Random(); while (vs.Count != 0) { int i = r.Next(vs.Count); int value = vs[i]; vs.RemoveAt(i); ret.Add(value); } return ret; } void SetRandomNumber(List<int> vs) { for (int i = 0; i < 25; i++) { Labels[i].Text = vs[i].ToString(); Labels[i].Tag = vs[i]; } } } |
ゲームがはじまったらクリックすべきラベルをクリックしたのかを判定する必要があります。ではクリックされるべき数はどのようにして求めればいいのでしょうか? それは最後にクリックされた数よりも大きくて最小のものです。
1 2 3 4 5 6 7 8 9 10 11 12 |
public partial class Form1 : Form { int GetNextNumber() { List<int> vs = RandomNumbers.Where(x => x > LastClickedNumber).ToList(); if (vs.Count == 0) return -1; int i = vs.Min(); return i; } } |
あとはラベルがクリックされたときGetNextNumber()メソッドが返す数と比較すれば正しくクリックされたことがわかります。正しくクリックされている場合はフィールド変数 LastClickedNumberの値を変更します。そして正しいクリックがされた場合と正しくないクリックがされた場合の処理をおこないます(OnGoodClick(Label label)と OnBadClick(Label label)メソッド)。
またすべて正しくクリックした場合はゲーム終了となりますが、それはどうやって判定すればいいのでしょうか? それはGetNextNumber()メソッドが-1を返したときです。そのときはOnGameClear()メソッドを呼び出し、そのなかでフィールド変数 IsClearedをtrueにします。そしてIsCleared == trueのときにラベルをクリックしてもなにもおきないようにしてしまいます。
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 |
public partial class Form1 : Form { bool IsCleared = false; private void Label_Click(object sender, EventArgs e) { if(IsCleared) return; Label label = (Label)sender; int i = (int)label.Tag; if (GetNextNumber() == i) { LastClickedNumber = i; OnGoodClick(label); if(GetNextNumber() == -1) { OnGameClear(); } } else { OnBadClick(label); } } void OnGoodClick(Label label) { int i = (int)label.Tag; Text = i.ToString() + " OK!!"; } void OnBadClick(Label label) { int i = (int)label.Tag; Text = i.ToString() + " NG!!"; } void OnGameClear() { IsCleared = true; Text = "ゲームクリア!"; MessageBox.Show("ゲームクリア!"); } } |
最後にゲームをもう一回やりたいときはメニューの[スタート]をクリックします。クリックするとIsClearedフラグがfalseに変更されて、GameStart()メソッドが実行されます。
1 2 3 4 5 6 7 8 |
public partial class Form1 : Form { private void MenuItemStart_Click(object sender, EventArgs e) { IsCleared = false; GameStart(); } } |