殺されたカードは使えない
殺しの七並べでは殺されたカードは使うことができません。ところが前回までに作成したゲームでは殺されたカードも使えてしまいます。これではよくないのでルールに対応するように作り直します。
実際のルールでは殺されたカードは自分の下に置く
(相手に死んだカードの枚数がわかるようにする)
というルールと殺されたことを申告しなくてよいというルールがあります。
また死んだカードがなにか見えるように置くルールと伏せた状態で置くというルールがあります。このあたりはローカルルールです。
今回は殺されたカードは伏せて本来あるべき位置におくことにします。またどのプレーヤーが何枚殺されたのかも表示させます。
殺されたカードをテーブルのうえに表示させる
まず殺されたカードをテーブルのうえに表示させます。カードの表示はイベントハンドラ Form1_Paintで以下のようにしていました。
1 2 3 4 5 6 7 8 9 10 |
public partial class Form1 : Form { private void Form1_Paint(object sender, PaintEventArgs e) { foreach(Card card in cards) card.ShowCard(e.Graphics); ShowMyCards(e.Graphics); } } |
CardクラスのShowCardメソッドはこのようになっています。isExistsプロパティがtrueかfalseで表示するかどうか決めていました。
1 2 3 4 5 6 7 8 9 10 11 |
class Card { public void ShowCard(Graphics g) { if(isExists) { Rectangle rect = new Rectangle(Point, Size); g.DrawImage(Bitmap, rect); } } } |
そこでCardクラスに少し手を加えて、カードが生きているかどうかを示すプロパティを作ります。
1 2 3 4 5 6 7 8 |
class Card { public bool IsLive { get; set; } } |
そして裏の状態でテーブルに出すためのメソッドを作成します。
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 |
class Card { public void ShowIfDeadCard(Graphics g) { if(!isLive) { Rectangle rect = new Rectangle(Point, Size); g.DrawImage(BackBitmap, rect); } } static Bitmap _BackBitmap = null; public Bitmap BackBitmap { get { if(_BackBitmap == null) _BackBitmap = GetBackBitmap(); return _BackBitmap; } } Bitmap GetBackBitmap() { Bitmap bitmap = new Bitmap(Size.Width, Size.Height); var image = Properties.Resources.cardimage; int x = 382 * 2; int y = 2400; Rectangle srcRect = new Rectangle(new Point(x, y), new Size(354, 490)); Graphics graphics = Graphics.FromImage(bitmap); graphics.DrawImage(image, new Rectangle(0, 0, Size.Width, Size.Height), srcRect, GraphicsUnit.Pixel); graphics.Dispose(); return bitmap; } } |
これでイベントハンドラ Form1_Paintのなかで以下のようにすれば、殺されてしまったカードが裏向きに表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public partial class Form1 : Form { private void Form1_Paint(object sender, PaintEventArgs e) { foreach(Card card in cards) card.ShowCard(e.Graphics); foreach(Card card in cards) card.ShowIfDeadCard(e.Graphics); ShowMyCards(e.Graphics); } } |
カードのIsLiveプロパティを切り替えるのはカードの死が確定したときでよいと思われます。
殺されたカードを裏向きでテーブルの上に出すとともに、殺した数と殺された数をカウントさせます。
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 Form1 : Form { int[] deadCount = new int[4]; // 殺された数 int[] killCount = new int[4]; // 殺した数 void ShowIfDead(Card card, int i) { List<Card> deadCards = GetDeadCard(card); if(deadCards.Count > 0) { string str = ""; str = String.Format("{0} により{1}枚殺されました。", i, deadCards.Count); MessageBox.Show(str); foreach(Card card0 in deadCards) { card0.IsLive = false; int victim = 0; foreach(List<Card> playerCards in playersCards) { if(playerCards.Remove(card0)) break; victim++; } if(victim < playersCards.Length) deadCount[victim]++; killCount[i]++; ShowPlayerInfo(victim); ShowPlayerInfo(i); } Invalidate(); } } } |
それから新しく作ったカードのプロパティを変更した場合はもう一度ゲームを開始するときはリセットしなければなりません。
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 |
public partial class Form1 : Form { void GameStart() { for(int i = 0; i< passCounts.Length; i++) passCounts[i] = 0; // 殺されたカードと殺したカードの枚数をリセットする for(int i = 0; i < deadCount.Length; i++) deadCount[i] = 0; for(int i = 0; i < killCount.Length; i++) killCount[i] = 0; isAgari = false; // ゲームスタート前の段階なのでだれもカードは持っていない。 // 全プレイヤーのカードをリセットする playersCards[0].Clear(); playersCards[1].Clear(); playersCards[2].Clear(); playersCards[3].Clear(); foreach(Card card in cards) { card.isExists = false; card.IsLive = true; // カードは生きている状態に戻す } Invalidate(); // テーブル上のカードをクリア // ここから下は前のものと同じ // カードを配って7があれば出す HandoutCards(); Takeout7(); ShowPlayerInfo(0); ShowPlayerInfo(1); ShowPlayerInfo(2); ShowPlayerInfo(3); // まずは自分の手番でゲームスタート IsMyTurn = true; // だがほんとうにカードは出せるのか? if(!CanPlayerTakeoutCard(0)) { MyPass(); OnRivalsTurn(); } } } |
プレーヤー情報を表示させる
ShowPlayerInfoで各プレイヤーの情報を表示するのですが、残りのカード数、パスの回数のほかにも表示させることがあるのでステータスバーに表示するのはやめます。またカードが大きすぎるので小さめのサイズに変更しました。
カードサイズを変更
1 2 3 4 5 6 7 8 9 |
class Card { // カードサイズを変更 static Size size = new Size(50, 75); static public Size Size { get { return size; } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public partial class Form1 : Form { int MYCARD_POSITION_Y = 400; // カードサイズを変更したため、このメソッドも一部変更 Rectangle GetMyCardRectangle(int index) { int i = 20 + index * (Card.Size.Width+10); Point pt = new Point(i, 450); Size size = Card.Size; return new Rectangle(pt, size); } } |
プレイヤー情報はデザイナで作成したラベルに表示させます。
見やすくするために黒字で表示されていますが、アプリをスタートさせるとフォームの背景が緑色になるので、プレイヤー情報は白地で表示させます。
コンストラクタが実行されるときに白地にします。
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 |
public partial class Form1 : Form { public Form1() { // これより上は以前と変わらず // 省略 // フォームの背景を緑に BackColor = Color.Green; // プレーヤー情報の文字を白文字に label0.ForeColor = Color.White; label1.ForeColor = Color.White; label2.ForeColor = Color.White; label3.ForeColor = Color.White; labelCardCount0.ForeColor = Color.White; labelPassCount0.ForeColor = Color.White; labelDeadCount0.ForeColor = Color.White; labelKillCount0.ForeColor = Color.White; labelCardCount1.ForeColor = Color.White; labelPassCount1.ForeColor = Color.White; labelDeadCount1.ForeColor = Color.White; labelKillCount1.ForeColor = Color.White; labelCardCount2.ForeColor = Color.White; labelPassCount2.ForeColor = Color.White; labelDeadCount2.ForeColor = Color.White; labelKillCount2.ForeColor = Color.White; labelCardCount3.ForeColor = Color.White; labelPassCount3.ForeColor = Color.White; labelDeadCount3.ForeColor = Color.White; labelKillCount3.ForeColor = Color.White; } } |
以下はプレーヤーの情報を表示するメソッドです。
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 |
public partial class Form1 : Form { void ShowPlayerInfo(int player) { if(player == 0) { labelCardCount0.Text = String.Format("カード残り {0} 枚", playersCards[0].Count); labelPassCount0.Text = String.Format("パス残り {0} 回", PASS_MAX - passCounts[0]); labelDeadCount0.Text = String.Format("殺されたカードの数 {0}", deadCount[0]); labelKillCount0.Text = String.Format("殺したカードの数 {0}", killCount[0]); } if(player == 1) { labelCardCount1.Text = String.Format("カード残り {0} 枚", playersCards[1].Count); labelPassCount1.Text = String.Format("パス残り {0} 回", PASS_MAX - passCounts[1]); labelDeadCount1.Text = String.Format("殺されたカードの数 {0}", deadCount[1]); labelKillCount1.Text = String.Format("殺したカードの数 {0}", killCount[1]); } if(player == 2) { labelCardCount2.Text = String.Format("カード残り {0} 枚", playersCards[2].Count); labelPassCount2.Text = String.Format("パス残り {0} 回", PASS_MAX - passCounts[2]); labelDeadCount2.Text = String.Format("殺されたカードの数 {0}", deadCount[2]); labelKillCount2.Text = String.Format("殺したカードの数 {0}", killCount[2]); } if(player == 3) { labelCardCount3.Text = String.Format("カード残り {0} 枚", playersCards[3].Count); labelPassCount3.Text = String.Format("パス残り {0} 回", PASS_MAX - passCounts[3]); labelDeadCount3.Text = String.Format("殺されたカードの数 {0}", deadCount[3]); labelKillCount3.Text = String.Format("殺したカードの数 {0}", killCount[3]); } } } |