⇒ 動作確認はこちらからどうぞ。
城の状態を初期化するときにInitCastleStatusListという自作メソッドを作りましたが、隣の城しか攻撃できないので内容を変える必要があります。
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 |
public partial class Index { public void InitCastleStatusList() { CastleStatusList.Clear(); CastleStatus status = new CastleStatus(); status.CastleID = 0; status.CastleName = "米沢城"; status.CastleOwner = "伊達"; status.SoldierCount = 5; status.MilitaryFood = 20; status.NextCastles = new int[] { 1, 3 }; CastleStatusList.Add(status); status = new CastleStatus(); status.CastleID = 1; status.CastleName = "春日山城"; status.CastleOwner = "上杉"; status.SoldierCount = 5; status.MilitaryFood = 20; status.NextCastles = new int[] { 0, 2, 3 }; CastleStatusList.Add(status); status = new CastleStatus(); status.CastleID = 2; status.CastleName = "躑躅ヶ崎館"; status.CastleOwner = "武田"; status.SoldierCount = 5; status.MilitaryFood = 20; status.NextCastles = new int[] { 1, 3, 4 }; CastleStatusList.Add(status); status = new CastleStatus(); status.CastleID = 3; status.CastleName = "小田原城"; status.CastleOwner = "北条"; status.SoldierCount = 5; status.MilitaryFood = 20; status.NextCastles = new int[] { 0, 1, 2, 4 }; CastleStatusList.Add(status); status = new CastleStatus(); status.CastleID = 4; status.CastleName = "岡崎城"; status.CastleOwner = "徳川"; status.SoldierCount = 5; status.MilitaryFood = 20; status.NextCastles = new int[] { 2, 3, 5, }; CastleStatusList.Add(status); status = new CastleStatus(); status.CastleID = 5; status.CastleName = "岐阜城"; status.CastleOwner = "織田"; status.SoldierCount = 5; status.MilitaryFood = 20; status.NextCastles = new int[] { 4, 6, }; CastleStatusList.Add(status); status = new CastleStatus(); status.CastleID = 6; status.CastleName = "二条城"; status.CastleOwner = "足利"; status.SoldierCount = 5; status.MilitaryFood = 20; status.NextCastles = new int[] { 5, 7, 8, }; CastleStatusList.Add(status); status = new CastleStatus(); status.CastleID = 7; status.CastleName = "吉田郡山城"; status.CastleOwner = "毛利"; status.SoldierCount = 5; status.MilitaryFood = 20; status.NextCastles = new int[] { 6, 8, 9, }; CastleStatusList.Add(status); status = new CastleStatus(); status.CastleID = 8; status.CastleName = "岡豊城"; status.CastleOwner = "長宗我部"; status.SoldierCount = 5; status.MilitaryFood = 20; status.NextCastles = new int[] { 6, 7, 9, }; CastleStatusList.Add(status); status = new CastleStatus(); status.CastleID = 9; status.CastleName = "内城"; status.CastleOwner = "島津"; status.SoldierCount = 5; status.MilitaryFood = 20; status.NextCastles = new int[] { 7, 8, }; CastleStatusList.Add(status); UpdateCastlesStatus(CastleStatusList); } } |
各城のターンを管理するTurnメソッドについてですが、城の状態は必ず以下のどれかになります。
どこからも攻め込まれていないプレイヤーの城
攻め込まれようとしているプレイヤーの城
包囲されているプレイヤーの城
プレイヤーに攻め込まれようとしている敵の城
プレイヤーに包囲されている敵の城
別の敵に攻め込まれようとしている敵の城
別の敵に包囲されている敵の城
どこからも攻め込まれていない敵の城
「攻め込まれようとしている」とは兵糧攻めが開始されるまでの状態、「包囲されている」とは兵糧攻めが開始されて以降の状態です。一応両者はわけて考えます。
ターンが始まったら「次へ」のボタンしかクリックできないようにします。まだそのターンでなにもしていない城のリストを取得してforeach文で回します。
「どこからも攻め込まれていないプレイヤーの城」であるならすべてのコマンドが使えるように、「攻め込まれようとしているプレイヤーの城」「包囲されているプレイヤーの城」は「反撃」コマンドが使えるようにするためにいったんループから抜けます。
それから「プレイヤーに包囲されている敵の城」のときも「突入」コマンドが使えるようにループから抜けてボタンを表示してクリックできるようにします。
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 |
public partial class Index { public void Turn() { CurentCastleStatus = null; // 「決定」ボタンなどをクリックできないように非表示にする // 次のメッセージを表示させるためのボタンをクリック可能にする HideCommand(); // まだそのターンでなにもしていない城のリストを取得する List<CastleStatus> Statuses = CastleStatusList.Where(x => !x.Done).ToList(); foreach (var status in Statuses) { // 城は以下のいずれかの状態なので適切な処理をする(詳細は後述) // 1.どこからも攻め込まれていないプレイヤーの城 // 2.攻め込まれようとしているプレイヤーの城 // 3.包囲されているプレイヤーの城 // 4.プレイヤーに攻め込まれようとしている敵の城 // 5.プレイヤーに包囲されている敵の城 // 6.別の敵に攻め込まれようとしている敵の城 // 7.別の敵に包囲されている敵の城 // 8.どこからも攻め込まれていない敵の城 } ShowSituation(); } } |
次にIndex.razorファイルを示します。コマンドが増えたぶんボタンも増えています。ターンと城の状態にあわせてボタンを表示させたり非表示にします。
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 |
@page "/" @if (!isGaming) { <h1>信長の野望もどき</h1> } <button class="btn btn-primary" @onclick="btnGameStartClick" style="display:@btnStartDisplay">ゲーム開始</button> <p>@yearAtring</p> <p>@turn</p> <p>@message</p> <button class="btn btn-primary" @onclick="btnNextClick" style="display:@btnNextDisplay">次</button> <button class="btn btn-primary" @onclick="btnMarchClick" style="display:@btnMarchDisplay">進軍</button> <button class="btn btn-primary" @onclick="btnConscriptionClick" style="display:@btnConscriptionDisplay">徴兵</button> <button class="btn btn-primary" @onclick="btnTaxClick" style="display:@btnTaxDisplay">徴税</button> <button class="btn btn-primary" @onclick="btnDevelopmentClick" style="display:@btnDevelopmentDisplay">開発</button> <button class="btn btn-primary" @onclick="btnRushClick" style="display:@btnRushDisplay">突入</button> <button class="btn btn-primary" @onclick="btnCounterattackClick" style="display:@btnCounterattackDisplay">反撃</button> <button class="btn btn-primary" @onclick="btnWaitClick" style="display:@btnWaitDisplay">静観</button> <button class="btn btn-primary" @onclick="btnClick" >実験</button> <select name="area" @bind="@SelectedValue1"> @foreach (string str in StringChoices1) { <option value="@str">@str</option> } </select> <select name="area" @bind="@SelectedValue2"> @foreach (string str in StringChoices2) { <option value="@str">@str</option> } </select> @if (CurentCastleStatusList != null) { <div> <table class="table"> <thead> <tr> <th scope="col">ID</th> <th scope="col">城</th> <th scope="col">城主</th> <th scope="col">兵力</th> <th scope="col">兵糧米</th> <th scope="col">兵糧攻めをしている軍の情報</th> </tr> </thead> <tbody> @foreach (CastleStatus status in CurentCastleStatusList) { <tr> <td>@status.CastleID</td> <td>@status.CastleName</td> <td>@status.CastleOwner</td> <td>@status.SoldierCount</td> <td>@status.MilitaryFood</td> @if (status.AttackingCorps != null) { <td> @status.AttackingCorps.AttackBase.CastleOwner 軍が攻撃しようとしている。, 拠点 @status.AttackingCorps.AttackBase.CastleName , 兵数 @status.AttackingCorps.SoldierCount , 兵糧 @status.AttackingCorps.MilitaryFood , </td> } @if (status.SiegingCorps != null) { <td> @status.SiegingCorps.AttackBase.CastleOwner 軍によって包囲されている。, 拠点 @status.SiegingCorps.AttackBase.CastleName , 兵数 @status.SiegingCorps.SoldierCount , 兵糧 @status.SiegingCorps.MilitaryFood , </td> } @if (status.AttackingCorps == null && status.SiegingCorps == null) { <td>なし</td> } </tr> } </tbody> </table> </div> } else { <p>開始ボタンをクリックしてください</p> } |
つぎにフィールド変数と各ボタンを表示するメソッドを示します。
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 |
public partial class Index { bool isGaming = false; string[] StringChoices1 = { "", }; string SelectedValue1 = ""; string[] StringChoices2 = { "", }; string SelectedValue2 = ""; // ボタンの表示・非表示 string btnStartDisplay = "inline-block"; string btnNextDisplay = "none"; string btnMarchDisplay = "none"; string btnConscriptionDisplay = "none"; string btnTaxDisplay = "none"; string btnDevelopmentDisplay = "none"; string btnWaitDisplay = "none"; string btnRushDisplay = "none"; string btnCounterattackDisplay = "none"; // 乱数をつくる Random random = new Random(); // 城の状態を管理 List<CastleStatus> CurentCastleStatusList = null; // ターンがまわってくる順番を表示 string turn = ""; // 表示するメッセージ string message = ""; // いま何年? 開始からの経過月 const int startYear = 1570; int month = 0; string yearAtring = ""; // プレイヤーの名前 string PlayerName = "織田"; // ターンが回ってきたときの自分の城の状態 public CastleStatus CurentCastleStatus = null; // 「次へ」ボタンを押すたびに状況を表示させるために必要 static public List<Situation> _situations = new List<Situation>(); } |
「次へ」ボタンを押すたびにゲームの状況が表示されるわけですが、以下はその状況をリストに追加していくメソッドです。
1 2 3 4 5 6 7 8 |
public partial class Index { void AddSituation(string str) { Console.WriteLine(str); _situations.Add(new Situation(str, CastleStatusList)); } } |
ゲームが進行すると表示させるべきメッセージがSituationのリストである_situationsの中に格納されていきます。その先頭をとりだしてメッセージを表示するとともに城の表示にも反映させます。それが後述するShowSituationメソッドです。
ShowSituationメソッドを実行しているときは[次へ]のボタンしか押せません。ゲームが終了していないにもかかわらず表示すべきメッセージがない場合はTurnメソッドが呼び出されます。しかしすべての城の行動が終了しているのであれば次の月のターンになります。このときはNextTurnメソッド(後述)が呼び出されます。
次に表示させるメッセージがなくなりゲームが終了しているのであればゲーム終了です。そうでないならプレイヤーに順番が回ってきたことになります。プレーヤーがコマンドボタンをクリックできるようにPlayerActionメソッド(後のページ参照)が呼び出されます。
すべてのメッセージが表示され、ゲームが終了しているのであれば終了です。終了しているかどうかは前のページの最後にあるIsGameClearメソッドとIsGameOverメソッドでおこないます。
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 |
public partial class Index { public void ShowSituation() { if (_situations.Count > 0) { string mes = _situations[0].Message; message = mes; UpdateCastlesStatus(_situations[0].CastleStatusList); _situations.RemoveAt(0); if (_situations.Count == 0) { // 次に表示させるメッセージがなくなりゲームが終了しているのであればゲーム終了 if (IsGameClear()) { message = "天下統一を達成しました♪ ゲームクリア!"; ShowStart(); isGaming = false; return; } if (IsGameOver()) { message = PlayerName + "家は滅亡しました・・・ ゲームオーバー"; ShowStart(); isGaming = false; return; } if (CurentCastleStatus != null && !CurentCastleStatus.Done) { // PlayerCastleStatusがnullではなく.Doneがtrueでないのであれば // プレイヤーに順番が回ってきたことになる PlayerAction(); } } } else { if (!CastleStatusList.Any(x => !x.Done)) { // すべての城の動作が終了したので次のターンへ NextTurn(); } else { if (!IsGameClear() && !IsGameOver()) Turn(); } } } } |
いまの月のターンがすべて終了したら次の月のターンに入ります。NextTurnメソッドはそのためのものです。時間を3ヶ月すすめ、CastleStatusListの順番をシャッフルして次のターンの順番を表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public partial class Index { void NextTurn() { // 時間を3ヶ月すすめる month++; yearAtring = GetYearMonth(month); _situations.Add(new Situation(yearAtring + " になりました。", CastleStatusList)); CastleStatusList = GetShuffledCastles(); // 次のターンの順番を表示する string s = ""; foreach (CastleStatus status in CastleStatusList) { s += " >> " + status.CastleName; } turn = s; Turn(); } } |