2023年12月28日 星期四

Week 16

     希望能做出旗幟能夠幫助大家玩的時候可以標註覺得有地雷的格子和在遊戲的首頁上方再加上文字說明各關內容  在更改遊戲開始畫面的排版 ( 旗幟尚未完成 文字說明有添加了 )

<程式>:

PImage bombImage;  // 儲存炸彈的圖片
PImage grassImage;//遊戲起始畫面下面的草圖片
boolean gameover = false;
int gameoverTime;
int[][] mine; 
boolean[][] open;
int selectedLevel = 0;//0表示未選擇級別 1表示第一關 2.... 3...
int gameState = 0;  // 0表示起始畫面,1表示遊戲中,2表示Level 2
int totalMines;
void openAll(int i, int j) 
{
  if (i < 0 || j < 0 || i >= rows || j >= cols || gameover) return;
  if (open[i][j] == true) return;

  open[i][j] = true;
  //如果是炸彈,顯示所有炸彈
  if (mine[i][j] == 9) 
  {
    revealAllBombs();
    gameover = true;//遊戲結束
    gameoverTime = millis();//紀錄遊戲結束時間
  }
  //如果是0,則遞迴打開相鄰格子
  if (mine[i][j] == 0) 
  {
    openAll(i - 1, j);
    openAll(i, j - 1);
    openAll(i, j + 1);
    openAll(i + 1, j);
  }
}

void addOne(int i, int j) 
{
  if (i < 0 || j < 0 || i >= rows || j >= cols) return;//範圍外,不處理
  if (mine[i][j] == 9) return;//地雷本身不用再+1
  mine[i][j]++;//如果不是就+1
}

void revealAllBombs() 
{
  //將所有炸彈顯示為已開啟,以顯示所有炸彈
  for (int i = 0; i < rows; i++) 
  {
    for (int j = 0; j < cols; j++) 
    {
      if (mine[i][j] == 9) 
      {
        open[i][j] = true;
      }
    }
  }
}
int rows , cols;
int cellSize;

void setup() {
  size(500, 500);
  rows = 16;
  cols = 30;
  cellSize = width / cols;//根據視窗大小和格子數量計算格子大小
  int mineCount = 0;
  //載入炸彈圖片
  bombImage = loadImage("bomb.png");
  grassImage = loadImage("grass.png");
}

void draw() 
{
  background(210,233,255);
  image(grassImage,width / 4 -125, height / 2 + 100, width / 2 + 250, 150);//150是圖片縱向長度 前面的width/height是畫布的長寬
  if (gameState == 0) 
  {
    //遊戲首頁文字說明中的標題踩地雷遊戲
    fill(0,0,0);
    textAlign(CENTER,CENTER);//字置中
    PFont font = createFont("微軟正黑體 Bold",30);//改字型
    textFont(font);
    text("踩地雷遊戲",width / 2, height / 20);
    
    textSize(20);//踩地雷遊戲第一關文字說明
    fill(0,0,0);
    textAlign(CENTER,CENTER);//字置左
    text("第一關:  10*10的格子  9 個地雷",width / 2 - 20 , height / 6);//調x軸的值 字可以到最左邊
    
    textSize(20);//踩地雷第二關文字說明
    fill(0,0,0);
    textAlign(CENTER,CENTER);//字置左
    text("第二關:  16*16的格子  30個地雷",width / 2 - 10 , height / 4);//調x軸的值 字可以到最左邊
    
    textSize(20);//踩地雷第三關文字說明
    fill(0,0,0);
    textAlign(CENTER,CENTER);//字置左
    text("第三關:  16*30的格子  60個地雷",width / 2 - 10, height / 3);//調x軸的值 字可以到最左邊
    
    // 起始畫面 level1 按鈕
    fill(100, 100, 200);//按鈕的顏色
    rect(width / 4, height / 2 - 25, width / 2, 50);
    fill(255);//字的顏色 白色
    textSize(20);
    textAlign(CENTER, CENTER);
    text("LEVEL1", width / 2, height / 2 - 5);

    // level2 按鈕
    fill(100, 100, 200);
    rect(width / 4, height / 2 + 25, width / 2, 50);
    fill(255);
    textSize(20);
    textAlign(CENTER, CENTER);
    text("LEVEL2", width / 2, height / 2 + 45);

    // level3 按鈕
    fill(100, 100, 200);
    rect(width / 4, height / 2 + 75, width / 2, 50);
    fill(255);
    textSize(20);
    textAlign(CENTER, CENTER);
    text("LEVEL3", width / 2, height / 2 + 95);
  } 
  else if (gameState == 1 || gameState == 2) 
  {
    // 踩地雷遊戲
    for (int i = 0; i < rows; i++) 
    {
      for (int j = 0; j < cols; j++) 
      {
        if (open[i][j]) 
        {
          if (mine[i][j] == 0) 
          {
            fill(150);//沒有地雷也沒有數字的空白格子 顏色是深灰色
          } 
          else 
          {
            fill(200);//有數字的格子 顏色是淡灰色
          }
          rect(j * cellSize, i * cellSize, cellSize, cellSize);

          if (mine[i][j] == 0) continue;//如果格子為空就繼續

          if (mine[i][j] == 1) //如果數字為1
          {
            textSize(20);
            fill(0, 0, 255);
            textAlign(CENTER, CENTER);
            text("" + mine[i][j], j * cellSize + cellSize / 2, i * cellSize + cellSize / 2);
          } 
          else if (mine[i][j] == 2) //如果數字為2
          {
            textSize(20);
            fill(24, 123, 29);
            textAlign(CENTER, CENTER);
            text("" + mine[i][j], j * cellSize + cellSize / 2, i * cellSize + cellSize / 2);
          } 
          else if (mine[i][j] == 3) //如果數字為3
          {
            textSize(20);
            fill(255, 0, 0);
            textAlign(CENTER, CENTER);
            text("" + mine[i][j], j * cellSize + cellSize / 2, i * cellSize + cellSize / 2);
          } 
          else if (mine[i][j] == 9) //如果是踩到地雷
          {
            image(bombImage, j * cellSize, i * cellSize, cellSize, cellSize);
          }
        } 
        else 
        {
          fill(200);//沒有被打開的格子 顏色是淡灰色
          rect(j * cellSize, i * cellSize, cellSize, cellSize);
        }
      }
    }
  }

  if (gameover && millis() - gameoverTime > 5000) {//最後遊戲結束的畫面 若遊戲結束/遊戲結束時間超過2000毫秒(2秒) 
    background(0);//背景黑色
    textSize(50);
    fill(255, 0, 0);//紅色的字
    textAlign(CENTER, CENTER);
    text("Game Over", width / 2, height / 2);

    fill ( 100,100,200 );//restart的按鈕
    rect( width/4 , height /2 +50 ,width / 2 , 50);
    fill( 255 );
    textSize(20);
    textAlign(CENTER,CENTER);
    text("RESTART", width / 2 , height / 2 +75);
  }
}

void mousePressed() 
{
  if (gameState == 0) //在遊戲一開始的畫面檢查哪一個按鈕被按
  {
    // level1 按鈕
    if (mouseX > width / 4 && mouseX < width / 4 + width / 2 && mouseY > height / 2 - 25 && mouseY < height / 2 + 25) 
    {
      selectedLevel = 1;//選擇第一關的按鈕
      gameState = 1;//遊戲狀態
      initializeGame();//初始化遊戲
    }
    // level2 按鈕
    else if ( mouseX > width / 4 && mouseX < width / 4 + width / 2 && mouseY > height / 2 + 25 && mouseY < height / 2 + 75 ) 
    {
      selectedLevel = 2;
      gameState = 1;//遊戲狀態
      initializeLevel2();
    }
    // level3 按鈕
    else if (  mouseX > width / 4 && mouseX < width / 4 + width / 2 && mouseY > height / 2 + 75 && mouseY < height / 2 + 125 ) 
    {
      selectedLevel = 3;
      gameState = 1;
      initializeLevel3();
    }
  } 
  else if (gameState == 1 || gameState == 2) 
  {
    // 獲取滑鼠點擊的位子
    int i = mouseY / cellSize;
    int j = mouseX / cellSize;
    //格子沒有被打開
    if (!open[i][j]) 
    {//就打開
      openAll(i, j);
    }
    
    //遊戲結束且結束過5秒後 看有沒有點restart鍵
    if (gameover && millis() - gameoverTime > 4000) 
    {
      if (mouseX > width / 4 && mouseX < width / 4 + width / 2 && mouseY > height / 2 + 50 && mouseY < height / 2 + 100) 
      {
        restartGame();
      }
    }
  }
}

void initializeGame() {
  int mineCount = 0;

  if (selectedLevel == 1)
  {
    rows = 10;
    cols = 10;
    totalMines = 9;
    cellSize = width / cols;
    surface.setSize(cols * cellSize, rows * cellSize);
  }
  else if (selectedLevel == 2)
  {
    rows = 16;
    cols = 16;
    totalMines = 30;
    cellSize = width / cols;
    surface.setSize(cols * cellSize, rows * cellSize);
  }
  else if (selectedLevel == 3)
  {
    rows = 16;
    cols = 30;
    totalMines = 60;
    cellSize = width / cols;
    surface.setSize(cols * cellSize, rows * cellSize);
  }
  
  mine = new int[rows][cols];
  open = new boolean[rows][cols];
  
  while (mineCount < totalMines) {
    int i = int(random(rows)), j = int(random(cols));
    if (mine[i][j] != 9) {
      mine[i][j] = 9;
      mineCount++;
    }
  }

  
  
  for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
      if (mine[i][j] == 9) {
        addOne(i - 1, j - 1);
        addOne(i - 1, j);
        addOne(i - 1, j + 1);
        addOne(i, j - 1);
        addOne(i, j + 1);
        addOne(i + 1, j - 1);
        addOne(i + 1, j);
        addOne(i + 1, j + 1);
      }
    }
  }
}

void initializeLevel2() {
  int mineCount = 0;

  rows = 16;
  cols = 16;
  totalMines = 30;
  cellSize = width / cols; // 根據視窗大小和格子數量計算格子大小

  mine = new int[rows][cols];
  open = new boolean[rows][cols];

  while (mineCount < totalMines) {
    int i = int(random(rows)), j = int(random(cols));
    if (mine[i][j] != 9) {
      mine[i][j] = 9;
      mineCount++;
    }
  }
  
  surface.setSize(cols * cellSize, rows * cellSize);

  for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
      if (mine[i][j] == 9) {
        addOne(i - 1, j - 1);
        addOne(i - 1, j);
        addOne(i - 1, j + 1);
        addOne(i, j - 1);
        addOne(i, j + 1);
        addOne(i + 1, j - 1);
        addOne(i + 1, j);
        addOne(i + 1, j + 1);
      }
    }
  }
}

void initializeLevel3() {
  int mineCount = 0;

  rows = 16;
  cols = 30;
  totalMines = 60;
  cellSize = 30;

  mine = new int[rows][cols];
  open = new boolean[rows][cols];

  for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
      open[i][j] = false;
    }
  }
  
  while (mineCount < totalMines) {
    int i = int(random(rows)), j = int(random(cols));
    if (mine[i][j] != 9) {
      mine[i][j] = 9;
      mineCount++;
    }
  }
  
  surface.setSize(cols * cellSize, rows * cellSize);

  for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
      if (mine[i][j] == 9) {
        addOne(i - 1, j - 1);
        addOne(i - 1, j);
        addOne(i - 1, j + 1);
        addOne(i, j - 1);
        addOne(i, j + 1);
        addOne(i + 1, j - 1);
        addOne(i + 1, j);
        addOne(i + 1, j + 1);
      }
    }
  }
}

void restartGame() {
  gameState = 0;//初始化遊戲狀態
  gameover = false;//重置遊戲結束為false
  gameoverTime = 0;//重置遊戲結束時間
  
  for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
      open[i][j] = false;
      mine[i][j] = 0;
    }
  }
}


沒有留言:

張貼留言