⇒ 動作確認はこちらからどうぞ。
これまで敵の動作だけ考えていました。プレイヤーの操作ができなければゲームにならないので、そのための処理を考えます。
基本的にボタンをクリックするとゲームが進行します。自分のターンになったら選択できる行動がボタンで表示されます。終わったら敵のターンとなり、その動作結果が一行ずつ表示されます。[次へ]ボタンをおすことで次のメッセージが表示されます。
ゲーム中の状態でクリックできるボタンがかわります。そこでボタンを表示させたり隠すメソッドを示します。
これはゲームがまだ開始されていないときと終了したときに[ゲーム開始]ボタンを表示させるためのメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Index { void ShowStart() { btnStartDisplay = "inline-block"; btnNextDisplay = "none"; btnMarchDisplay = "none"; btnConscriptionDisplay = "none"; btnTaxDisplay = "none"; btnDevelopmentDisplay = "none"; btnWaitDisplay = "none"; btnRushDisplay = "none"; btnCounterattackDisplay = "none"; } } |
これは進軍、徴兵、徴税、開発、静観のコマンドボタンを表示させるためのメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public partial class Index { // 通常時のコマンドボタンを表示させる public void ShowCommand() { btnStartDisplay = "none"; btnNextDisplay = "none"; btnMarchDisplay = "inline-block"; btnConscriptionDisplay = "inline-block"; btnTaxDisplay = "inline-block"; btnDevelopmentDisplay = "inline-block"; btnWaitDisplay = "inline-block"; btnRushDisplay = "none"; btnCounterattackDisplay = "none"; } } |
敵の城を包囲しているときにターンが回ってきたら兵糧攻めを継続するか強行突入をするかを決めなければなりません。これは[突入]と[静観]のボタンを表示させるメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Index { public void ShowRushCommand() { btnStartDisplay = "none"; btnNextDisplay = "none"; btnMarchDisplay = "none"; btnConscriptionDisplay = "none"; btnTaxDisplay = "none"; btnDevelopmentDisplay = "none"; btnWaitDisplay = "inline-block"; btnRushDisplay = "inline-block"; btnCounterattackDisplay = "none"; } } |
敵が城を包囲しようとしているときやすでに包囲されているとき、城から出撃して敵と戦うことができます。以下は[反撃]ボタンを表示させるメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Index { public void ShowCounterattackCommand() { btnStartDisplay = "none"; btnNextDisplay = "none"; btnMarchDisplay = "none"; btnConscriptionDisplay = "none"; btnTaxDisplay = "none"; btnDevelopmentDisplay = "none"; btnWaitDisplay = "inline-block"; btnRushDisplay = "none"; btnCounterattackDisplay = "inline-block"; } } |
ターンが自分とは無関係な城であったり戦闘の状況が表示されているときは[次へ]ボタンしかクリックできません。これは[次へ]ボタンのみを表示させるメソッドです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Index { void HideCommand() { btnStartDisplay = "none"; btnNextDisplay = "inline-block"; btnMarchDisplay = "none"; btnConscriptionDisplay = "none"; btnTaxDisplay = "none"; btnDevelopmentDisplay = "none"; btnWaitDisplay = "none"; btnRushDisplay = "none"; btnCounterattackDisplay = "none"; } } |
次に実際にボタンがクリックされたときの処理を示します。
まず[スタート]ボタンがクリックされたときの処理を示します。
ゲームがスタートすると各城にターンが回ってくる順番をランダムに決めます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public partial class Index { private void btnGameStartClick() { isGaming = true; InitCastleStatusList(); // GetShuffledCastlesメソッドは前回と同じ CastleStatusList = GetShuffledCastles(); string s = ""; foreach (CastleStatus status in CastleStatusList) { s += " >> " + status.CastleName; } turn = s; Turn(); month = 0; yearAtring = startYear.ToString() + " 年 3 月"; } } |
ゲーム開始段階では1570年3月です。1ターン3ヵ月です。GetYearMonthメソッドはターンの回数から現在の年と月を求めます。
1 2 3 4 5 6 7 8 9 10 |
public partial class Index { string GetYearMonth(int month0) { int year = startYear + month0 / 4; int m = month0 % 4 + 1; return year + " 年 " + m * 3 + " 月"; } } |
ゲームが開始されるといきなり自分の順番になることがありますが、ほとんどの場合は他の敵のあとになります。最初は[次へ]ボタンしかクリックできません。
[次へ]ボタンをクリックするとbtnNextClickメソッドが実行されます。するとShowSituationメソッドによって、Situationオブジェクトのリストである_situationsに格納されたメッセージが次々と表示されます。ShowSituationメソッドはターンと城の状態 「信長の野望」もどきを改良するを参照してください。
1 2 3 4 5 6 7 |
public partial class Index { void btnNextClick() { ShowSituation(); } } |
Turnメソッドのなかでプレイヤーの城やプレイヤーが関与している城の処理が終わったら、その城のCastleStatusオブジェクトがCurentCastleStatusに格納されます。[次へ]ボタンを押し続けてリストのなかのメッセージがすべてなくなったらShowSituationメソッドのなかでPlayerActionメソッドが呼び出されます。
PlayerActionメソッドは以下のようになっています。城の状態が通常なのか、敵に攻め込まれようとしていたり包囲されているかでクリックできるボタンを表示して関係のないボタンを非表示にします。城の状態が通常であれば進軍できる城を選択できるようにする、城の兵数をしらべて進軍できる兵数を選択できるようにします。
長くなるのでPlayerActionというクラスを作成しました。これにともなってフィールド変数をpublicに変更しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public partial class Index { public string btnMarchDisplay = "none"; public string btnCounterattackDisplay = "none"; public string[] StringChoices1 = { "", }; public string SelectedValue1 = ""; public string[] StringChoices2 = { "", }; public string SelectedValue2 = ""; void PlayerAction() { new PlayerAction(this); } } |
PlayerActionクラスは以下のようになります。
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 |
public class PlayerAction { Index _obj = null; public PlayerAction(Index obj) { _obj = obj; if (_obj.CurentCastleStatus != null) { if (_obj.CurentCastleStatus.CastleOwner == _obj.PlayerName) { bool b = _obj.CurentCastleStatus.AttackingCorps == null && _obj.CurentCastleStatus.SiegingCorps == null if (b) PlayerCastleNormal(); // プレイヤーの城は通常の状態 else PlayerCastleDangerous(); // プレイヤーの城は危険な状態 return; } else { bool b = _obj.CurentCastleStatus.SiegingCorps != null && _obj.CurentCastleStatus.SiegingCorps.BaseCastleOwner == _obj.PlayerName; if (b) { _obj.ShowRushCommand(); // 敵の城を包囲している状態 } } } } } |
PlayerAction.PlayerCastleNormalメソッドはプレイヤーの城が通常の状態のときにターンが回ってきたときの処理をおこないます。進軍、徴兵、徴税、開発、静観のボタンをクリック可能にして進軍の対象になる城のリストを表示するとともに送ることができる兵数を選択できるようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class PlayerAction { void PlayerCastleNormal() { int i = _obj.CurentCastleStatus.SoldierCount; if (i > _obj.CurentCastleStatus.MilitaryFood / 3) i = _obj.CurentCastleStatus.MilitaryFood / 3; ShowTargetCastleList(); InsertNumber(i); _obj.ShowCommand(); if (_obj.CurentCastleStatus.SoldierCount <= 0) _obj.btnMarchDisplay = "none"; } } |
PlayerAction.PlayerCastleDangerousメソッドはプレイヤーの城が攻め込まれようとしているときや包囲されている状態のときにターンが回ってきたときの処理をおこないます。反撃、静観のボタンをクリック可能にして出撃できる兵数を選択できるようにします。
1 2 3 4 5 6 7 8 9 10 11 |
public class PlayerAction { void PlayerCastleDangerous() { InsertNumber(_obj.CurentCastleStatus.SoldierCount); _obj.ShowCounterattackCommand(); if (_obj.CurentCastleStatus.SoldierCount <= 0) _obj.btnCounterattackDisplay = "none"; } } |
進軍の対象になる城のリストを表示します。
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 |
public class PlayerAction { void ShowTargetCastleList() { List<CastleStatus> statuses0 = new List<CastleStatus>(); int[] vs = _obj.CurentCastleStatus.NextCastles; foreach (int i in vs) statuses0.Add(_obj.CastleStatusList.First(x => x.CastleID == i)); if (!_obj.isDebug) { statuses0 = _obj.CastleStatusList.Where(x => x.CastleName != _obj.CurentCastleStatus.CastleName).ToList(); } // 兵を遅れるのは自分の城 List<CastleStatus> statuses = statuses0.Where(x => x.CastleOwner == _obj.PlayerName).ToList(); // 誰も攻め込んでいない敵の城 statuses.AddRange(statuses0.Where(x => x.AttackingCorps == null && x.SiegingCorps == null)); // 自分が攻め込もうとしている城と自分が包囲している城 statuses.AddRange(statuses0.Where(x => x.AttackingCorps?.BaseCastleOwner == _obj.PlayerName)); statuses.AddRange(statuses0.Where(x => x.SiegingCorps?.BaseCastleOwner == _obj.PlayerName)); // 重複を排除してソート statuses = statuses.Distinct().OrderBy(x => x.CastleID).ToList(); // 進撃することができる城がない場合、[進軍]ボタンをクリックできないようにする if (statuses.Count == 0) _obj.btnMarchDisplay = "none"; List<string> strings1 = new List<string>(); foreach (CastleStatus status in statuses) { if (status.CastleOwner == _obj.PlayerName) { if (status.AttackingCorps == null && status.SiegingCorps == null) strings1.Add(status.CastleName + "(自軍)"); else strings1.Add(status.CastleName + "(自軍 救援)"); } else if (status.AttackingCorps != null) strings1.Add(status.CastleName + "(攻込)"); else if (status.SiegingCorps != null) strings1.Add(status.CastleName + "(包囲)"); else strings1.Add(status.CastleName); } _obj.StringChoices1 = strings1.ToArray(); if (_obj.StringChoices1.Length > 0) _obj.SelectedValue1 = _obj.StringChoices1[0]; else ClearTargetCastleList(); } } |
進軍の対象になる城のリストをクリアします。
1 2 3 4 5 6 7 8 |
public class PlayerAction { void ClearTargetCastleList() { _obj.StringChoices1 = new string[] { "", }; _obj.SelectedValue1 = _obj.StringChoices1[0]; } } |
移動、出撃できる兵数のリストを表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class PlayerAction { void InsertNumber(int x) { List<string> strings = new List<string>(); for (int i = 1; i <= x; i++) { strings.Add(i.ToString()); } _obj.StringChoices2 = strings.ToArray(); if (_obj.StringChoices2.Length > 0) _obj.SelectedValue2 = _obj.StringChoices2[0]; else ClearNumber(); } } |
移動、出撃できる兵数のリストをクリアします。
1 2 3 4 5 6 7 8 |
public class PlayerAction { void ClearNumber() { _obj.StringChoices2 = new string[] { "", }; _obj.SelectedValue2 = _obj.StringChoices2[0]; } } |
btnMarchClickメソッドは[進軍]ボタンがクリックされたときの処理をおこないます。味方の城に進軍すると移動、敵の城に進軍すれば戦争になります。
戦争を仕掛けるときは敵の城のCastleStatus.AttackingCorpsプロパティに作成した軍団オブジェクト corpsをセットします。また移動の場合は移動先の自分の城のCastleStatus.SupportCorpsに軍団オブジェクト corpsをセットします。実際に兵が移動先に到着するのは移動先の城にターンが回ってきたときです。
ボタンがクリックされると[次へ]ボタン以外はクリックできないようにして、Turnメソッドを呼び出してゲームを進めます。
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 |
public partial class Index { private void btnMarchClick() { int soldierCount = int.Parse(SelectedValue2); string castleName = SelectedValue1; // ( 以下を取り除く int index = castleName.IndexOf("("); if (index != -1) castleName = castleName.Substring(0, index); CastleStatus status = CastleStatusList.First(x => x.CastleName == castleName); if (status.CastleOwner == PlayerName) { // 移動の場合 string str = String.Format("{0}の{1}軍が{2}へ移動しました。", CurentCastleStatus.CastleName, CurentCastleStatus.CastleOwner, status.CastleName); AddSituation(str); Corps corps = CurentCastleStatus.SendingForAttack(soldierCount); // status.SupportCorps == nullならstatus.SupportCorpsにセット // すでにセットされているなら追加する if(status.SupportCorps == null) status.SupportCorps = corps; else { status.SupportCorps.SoldierCount += corps.SoldierCount; status.SupportCorps.MilitaryFood += corps.MilitaryFood; } } else { if (status.AttackingCorps == null && status.SiegingCorps == null) { // 戦争を仕掛ける場合(Corpsクラスのコンストラクタで自動的に出撃元の城の人数は差し引かれる) Corps corps = CurentCastleStatus.SendingForAttack(soldierCount); status.AttackingCorps = corps; string str = String.Format("{0}の{1}軍が{2}に攻め込むべく出陣しました。", CurentCastleStatus.CastleName, CurentCastleStatus.CastleOwner, status.CastleName); AddSituation(str); } else if (status.AttackingCorps != null && status.AttackingCorps.BaseCastleOwner == PlayerName) { // 城攻めのために応援派遣した兵数と兵糧を派遣先に追加する Corps corps = CurentCastleStatus.SendingForAttack(soldierCount); status.AttackingCorps.SoldierCount += corps.SoldierCount; status.AttackingCorps.MilitaryFood += corps.MilitaryFood; AddSituation(String.Format("{0}に攻め込んている我が軍を支援するために出陣しました。", status.CastleName)); } else if (status.SiegingCorps != null && status.SiegingCorps.BaseCastleOwner == PlayerName) { // 包囲のために応援派遣した兵数と兵糧を派遣先に追加する Corps corps = CurentCastleStatus.SendingForAttack(soldierCount); status.SiegingCorps.SoldierCount += corps.SoldierCount; status.SiegingCorps.MilitaryFood += corps.MilitaryFood; AddSituation(String.Format("{0}を包囲中の我が軍を支援するために出陣しました。", status.CastleName)); } } CurentCastleStatus.Done = true; HideCommand(); Turn(); } } |
btnConscriptionClickメソッドは[徴兵]ボタンがクリックされたときの処理をおこないます。自分の城の兵を増やします。デバッグしやすくするために自分に都合がいい数字にしています(敵は徴兵しても10も増えない)。
そのあとゲームを進める処理は上記のものと同じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Index { void btnConscriptionClick() { CurentCastleStatus.Done = true; CurentCastleStatus.SoldierCount += 10; // 正しくはこうすべき CurentCastleStatus.Conscription(); UpdateCastlesStatus(CastleStatusList); AddSituation("徴兵しました。"); HideCommand(); Turn(); } } |
「徴税」ボタンがクリックされたときの処理です。これもデバッグしやすくするために自分に都合がいい数字にしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Index { void btnTaxClick() { CurentCastleStatus.Done = true; CurentCastleStatus.MilitaryFood += 25; // 正しくはこうすべき CurentCastleStatus.TaxCollection() UpdateCastlesStatus(CastleStatusList); AddSituation("あなたは「徴税」を選択しました。"); HideCommand(); Turn(); } } |
「開発」ボタンがクリックされたときの処理です。CastleStatus.Develop()が実行されて収穫量がアップします。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public partial class Index { void btnDevelopmentClick() { CurentCastleStatus.Done = true; CurentCastleStatus.Develop(); UpdateCastlesStatus(CastleStatusList); AddSituation("あなたは「開発」を選択しました。"); HideCommand(); Turn(); } } |
btnWaitClickメソッドは「静観」ボタンがクリックされたときの処理をおこないます。ただし敵が攻め込もうとしているにもかかわらず何もしないと敵に包囲されてしまいます。勝算もないのに下手に反撃するよりは味方の援軍が到着するのを待つのもひとつの作戦かもしれません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public partial class Index { void btnWaitClick() { AddSituation("あなたは静観しました。"); // 敵が攻め込もうとしているときになにもしないと包囲されてしまう if (CurentCastleStatus.AttackingCorps != null) { Corps corps = CurentCastleStatus.AttackingCorps; CurentCastleStatus.AttackingCorps = null; CurentCastleStatus.SiegingCorps = corps; string name = CurentCastleStatus.CastleName; string sgOwner = CurentCastleStatus.SiegingCorps.BaseCastleOwner; AddSituation(String.Format("{0}は{1}軍に包囲されました。", name, sgOwner)); } UpdateCastlesStatus(CastleStatusList); CurentCastleStatus.Done = true; HideCommand(); Turn(); } } |
次に突入や反撃などのコマンドボタンが押されたときの処理を示します。
「突入」ボタンが押されたときに呼び出されるメソッドを示します。
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 |
public partial class Index { // Turnメソッドのなかでフィールド変数 EnemyCastleIfPlayerSiegingに // オブジェクトが格納されている EnemyCastleIfPlayerSieging EnemyCastleIfPlayerSieging = null; void btnRushClick() { AddSituation(String.Format("これより{0}に突入します。", CurentCastleStatus.CastleName)); string oldOwner = CurentCastleStatus.CastleOwner; string castleName = CurentCastleStatus.CastleName; if (EnemyCastleIfPlayerSieging.ForcedRush()) { AddSituation("突入作戦成功♪"); AddSituation(String.Format("{0}軍から{1}を奪い取りました♪", oldOwner, castleName)); EnemyCastleIfPlayerSieging.CastleOccupied(oldOwner); EnemyCastleIfPlayerSieging.CheckGameClearIfEnemyRuin(oldOwner); } else { AddSituation("突入作戦失敗。突入部隊は全滅しました。"); if (EnemyCastleIfPlayerSieging.RuinCheck(PlayerName)) { AddSituation(PlayerName + "家は滅亡しました・・・ゲームオーバーです・・・"); ShowSituation(); return; } } EnemyCastleIfPlayerSieging = null; CurentCastleStatus.Done = true; HideCommand(); Turn(); } } |
これは「反撃」ボタンが押されたときに関連するメソッドを示します。
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 |
public partial class Index { // Turnメソッドのなかで フィールド変数 PlayerCastleIfAttacking またはPlayerCastleIfSieging に // オブジェクトが格納されている PlayerCastleIfAttacking PlayerCastleIfAttacking = null; PlayerCastleIfSieging PlayerCastleIfSieging = null; void btnCounterattackClick() { HideCommand(); CurentCastleStatus.Done = true; int soldierCount = int.Parse(SelectedValue2); Corps defenseingCorps = CurentCastleStatus.SendingForDefense(soldierCount); string enemyName; string enemyCastle; bool canEnemyReturn; if (PlayerCastleIfAttacking != null) { enemyName = CurentCastleStatus.AttackingCorps.BaseCastleOwner; enemyCastle = CurentCastleStatus.AttackingCorps.BaseCastleName; canEnemyReturn = PlayerCastleIfAttacking.atCanReturn; } else { enemyName = CurentCastleStatus.SiegingCorps.BaseCastleOwner; enemyCastle = CurentCastleStatus.SiegingCorps.BaseCastleName; canEnemyReturn = PlayerCastleIfAttacking.sgCanReturn; } AddSituation(String.Format("{0}軍は{1}軍を撃退すべく{2}から出撃しました!", CurentCastleStatus.CastleOwner, enemyName, CurentCastleStatus.CastleName)); bool ret; if(PlayerCastleIfAttacking != null) ret = PlayerCastleIfAttacking.Counterattack(defenseingCorps); else ret = PlayerCastleIfSieging.Counterattack(defenseingCorps); if (ret) { AddSituation(String.Format("{0}軍を撃退しました♪兵糧もゲットできてウハウハです♪", enemyName)); if (canEnemyReturn) AddSituation(String.Format("{0}軍は{1}に退却しました。", enemyName, enemyCastle)); else { AddSituation(String.Format("{0}軍には退却できる城がありません。全滅です♪", enemyName, enemyCastle)); if (PlayerCastleIfAttacking != null && PlayerCastleIfAttacking.CheckGameClearIfEnemyRuin(enemyName)) return; else if (PlayerCastleIfSieging != null && PlayerCastleIfSieging.CheckGameClearIfEnemyRuin(enemyName)) return; } } else { AddSituation(String.Format( "{0}を包囲している{1}軍の前に敗退しました・・・兵糧を奪われただけで大ピンチです。", CurentCastleStatus.CastleName, enemyName)); } PlayerCastleIfAttacking = null; PlayerCastleIfSieging = null; UpdateCastlesStatus(CastleStatusList); Turn(); } } |