Contents
餌を表示する
これまではフィールドに餌がありませんでしたが、今回は餌を食べさせます。まずは餌を表示させましょう。
各セルを調べて必要であればドットを表示させます。はじめから餌がない場所やすでにパックマンが通過した場所であれば表示させる必要はありません。
表示させる場合はセルの真ん中に直径4ピクセルで表示させます。
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 |
public partial class Form1 : Form { void DrawMaze(Graphics g) { this.BackColor = Color.Black; for(int y = 0; y < FIELD_ROW; y++) { for(int x = 0; x < FIELD_COLUM; x++) { Rectangle rect = GetMazeCell(x, y); Image image = GetCellImage(x, y); if(image != null) { // 画像の元のサイズは32ピクセル g.DrawImage(image, rect, new Rectangle(0, 0, 32, 32), GraphicsUnit.Pixel); if(IsShowDot(x, y)) ShowDot(g, x, y); } } } } void ShowDot(Graphics g, int colum, int row) { Rectangle rect = GetMazeCell(colum, row); // 餌の大きさは直径4ピクセルとする // rectはひとつひとつのセルの矩形 int x = rect.X; int y = rect.Y; int dotPosX = x + (rect.Width - 4) / 2; int dotPosY = y + (rect.Height - 4) / 2; Rectangle dotRect = new Rectangle(new Point(dotPosX, dotPosY), new Size(4, 4)); SolidBrush brush = new SolidBrush(Color.White); g.FillEllipse(brush, dotRect); } } |
IsShowDotメソッド
IsShowDotメソッドは餌を表示するかどうかを判定するメソッドです。はじめから餌が存在しない場所やパックマンが通過した場所には餌を表示させません。
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 |
public partial class Form1 : Form { bool IsShowDot(int colum, int row) { // パックマンが通過したセルには餌を表示させない if(passedPacman[row, colum]) return false; // はじめから餌が存在しない場所には表示させない if(row == 16 && colum == 10) return false; if(row == 8 && (7 <= colum && colum <= 13)) return false; if(row == 12 && (7 <= colum && colum <= 13)) return false; if(row == 10 && colum != 5 && colum != 15) return false; if(row == 7 && colum != 5 && colum != 15) return false; if(7 == colum && (9 <= row && row <= 13)) return false; if(13 == colum && (9 <= row && row <= 13)) return false; return true; } } |
これはパックマンが通過したセルかどうかがわかるようにするために作成した二元配列です。
bool[,] passedPacman = new bool[FIELD_ROW, FIELD_COLUM];
最初とステージクリア時にはすべてfalseにしておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Form1 : Form { bool[,] passedPacman = new bool[FIELD_ROW, FIELD_COLUM]; void ClearPassedPacman() { for(int y = 0; y < FIELD_ROW; y++) { for(int x = 0; x < FIELD_COLUM; x++) { passedPacman[y, x] = false; } } } } |
パックマンが通過したらフラグをセットします。
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 |
public partial class Form1 : Form { async Task<bool> MovePacmanDirect(Direct direct) { if(CanPacmanMoveDirect(direct)) { if(direct == Direct.North) pacCellY--; if(direct == Direct.South) pacCellY++; if(direct == Direct.East) pacCellX++; if(direct == Direct.West) pacCellX--; for(int i = 0; i < 4; i++) { if(direct == Direct.North) pacPosY -= CELL_HEIGHT / 4; if(direct == Direct.South) pacPosY += CELL_HEIGHT / 4; if(direct == Direct.East) pacPosX += CELL_WIDTH / 4; if(direct == Direct.West) pacPosX -= CELL_WIDTH / 4; Invalidate(); await Task.Delay(PACMAN_DELAY); } Rectangle newRect = GetMazeCell(pacCellX, pacCellY); pacPosX = newRect.X; pacPosY = newRect.Y; // 追加部分はここだけ OnPacmanMoved(pacCellX, pacCellY); } return true; } void OnPacmanMoved(int cellX, int cellY) { passedPacman[cellY, cellX] = true; } } |
パワー餌の表示
それから餌のなかにはパワー餌があり、これを食べるとこれまで自分を追いかけていたモンスターを食べることができるようになります。
パワー餌を表示させるために先ほど作成したShowDotメソッドに処理を追加します。
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 |
public partial class Form1 : Form { bool IsPowerFoodCell(int cellX, int cellY) { if((cellX == 1 || cellX == 19) && (cellY == 2 || cellY == 16)) return true; else return false; } void ShowDot(Graphics g, int colum, int row) { Rectangle rect = GetMazeCell(colum, row); int x = rect.X; int y = rect.Y; int dotPosX = x + (rect.Width - 4) / 2; int dotPosY = y + (rect.Height - 4) / 2; Rectangle dotRect = new Rectangle(new Point(dotPosX, dotPosY), new Size(4, 4)); SolidBrush brush = new SolidBrush(Color.White); g.FillEllipse(brush, dotRect); // 追加部分 // この位置はパワー餌にする if(IsPowerFoodCell(colum, row)) { dotPosX = x + (rect.Width - 12) / 2; dotPosY = y + (rect.Height - 12) / 2; dotRect = new Rectangle(new Point(dotPosX, dotPosY), new Size(12, 12)); SolidBrush brush1 = new SolidBrush(Color.Red); g.FillEllipse(brush1, dotRect); } } } |
得点の表示
餌を食べたら点数が増えます。得点を表示させてみましょう。
ゲーム開始のためのメニューを追加しました。Label1の位置に得点が表示されます。得点が増えるのはパックマンが移動してそこに餌があった場合です。(他にもモンスターを食べたとき、デザートを食べたときああるが、ここでは省略)
これでよさそうですが、ダメです。最初から餌が置かれていない場所があり、そこをはじめて通るときも得点になってしまいます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Form1 : Form { int score = 0; void OnPacmanMoved(int cellX, int cellY) { if(passedPacman[cellY, cellX] == false) { passedPacman[cellY, cellX] = true; score += 10; label1.ForeColor = Color.White; label1.Text = "Score " + score.ToString(); } } } |
「餌が置かれていない場所は決まっているので、その部分であれば点数を加算しない」というのはどうでしょうか?
はじめから餌が存在しない場所は以下の部分です。
1 2 3 4 5 6 7 |
(cellY == 16 && cellX == 10) || (cellY == 8 && (7 <= cellX && cellX <= 13)) || (cellY == 12 && (7 <= cellX && cellX <= 13)) || (cellY == 10 && cellX != 5 && cellX != 15) || (cellY == 7 && cellX != 5 && cellX != 15) || (7 == cellX && (9 <= cellY && cellY <= 13)) || (13 == cellX && (9 <= cellY && cellY <= 13)) |
そこで最初から餌が置かれていない場所を通過した場合は点数を加算しないようにしています。
それから通常の餌を食べたときとパワー餌を食べたときではこのあとの処理が違ってくるので区別して処理をしています。
IsFoodlesBeginningCellメソッドの作成とOnPacmanMovedメソッドの変更
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 { bool IsFoodlesBeginningCell(int cellX, int cellY) { if( (cellY == 16 && cellX == 10) || (cellY == 8 && (7 <= cellX && cellX <= 13)) || (cellY == 12 && (7 <= cellX && cellX <= 13)) || (cellY == 10 && cellX != 5 && cellX != 15) || (cellY == 7 && cellX != 5 && cellX != 15) || (7 == cellX && (9 <= cellY && cellY <= 13)) || (13 == cellX && (9 <= cellY && cellY <= 13)) ) return true; else return false; } void OnPacmanMoved(int cellX, int cellY) { if(IsFoodlesBeginningCell(cellX, cellY)) return; if(passedPacman[cellY, cellX] == false) { passedPacman[cellY, cellX] = true; // 普通の餌なら10点加算。パワー餌なら50点加算 if(!IsPowerFoodCell(cellX, cellY)) score += 10; else score += 50; label1.ForeColor = Color.White; label1.Text = "Score " + score.ToString(); } } } |
IsFoodlesBeginningCellメソッドをつかってIsShowDotメソッドも書き直してしまいましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public partial class Form1 : Form { bool IsShowDot(int colum, int row) { if(passedPacman[row, colum]) return false; if(IsFoodlesBeginningCell(colum, row)) return false; return true; } } |
ステージクリアの判定
餌を全部食べてしまったらステージクリアとなるわけですが、餌をすべて食べ尽くしてしまったことはどうやって判定すればいいのでしょうか?
DrawMazeメソッドのなかでShowDotが一度も実行されない場合と考えました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
void DrawMaze(Graphics g) { this.BackColor = Color.Black; bool for(int y = 0; y < 23; y++) { for(int x = 0; x < 21; x++) { Rectangle rect = GetMazeCell(x, y); Image image = GetCellImage(x, y); if(image != null) { g.DrawImage(image, rect, new Rectangle(0, 0, 32, 32), GraphicsUnit.Pixel); if(IsShowDot(x, y)) { // この部分が一度も実行されない ShowDot(g, x, y); } } } } } |
だったらこれでいいのではないでしょうか?
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 |
public partial class Form1 : Form { bool IsStageClear = false; void DrawMaze(Graphics g) { this.BackColor = Color.Black; bool isStageClear = true; for(int y = 0; y < FIELD_ROW; y++) { for(int x = 0; x < FIELD_COLUM; x++) { Rectangle rect = GetMazeCell(x, y); Image image = GetCellImage(x, y); if(image != null) { g.DrawImage(image, rect, new Rectangle(0, 0, 32, 32), GraphicsUnit.Pixel); if(IsShowDot(x, y)) { ShowDot(g, x, y); isStageClear = false; } } } } if(isStageClear) { IsStageClear = true; } } private async void Timer_Tick(object sender, EventArgs e) { if(ignoreTick) return; ignoreTick = true; Task<bool> pacTask = MovePacmanDirect(pacDirect); Task<bool> monstarsTask = MoveMonstars(); await pacTask; await monstarsTask; ignoreTick = false; if(IsStageClear) { timer.Stop(); MessageBox.Show("ステージクリア!"); } } } |