2024年1月12日 星期五

專題總篇集

 我們設計了一個以深度優先的隨機生成的走迷宮遊戲



genMaze(int i, int j):

目的:使用遞迴回朔算法生成迷宮。

功能:將當前儲存格標記為已經過,然後隨機選擇未經過的相鄰儲存格進行連接,直到所有相鄰儲存格都走過。

參數:起始座標(i, j)。



genMaze2(int i, int j, int ii, int jj):

目的:genMaze的輔助函式。將座標(i, j)和(ii, jj)之間的牆標記為已走過。

參數:兩個相鄰儲存格的座標(i, j)和(ii, jj)。



testVisible(int i, int j):

目的:檢查座標(i, j)的儲存格是否可見。

返回值:若儲存格越界或已被走過,有則返回true,否則返回false。




noCrossWallW(int dI):

目的:檢查目標在垂直方向(上或下)移動是否穿越了牆壁。

參數:方向 dI(-1表示上,+1表示下)。

返回值:若沒有牆壁擋住,返回true,否則返回false。

noCrossWallH(int dJ):

目的:檢查目標在水平方向(左或右)移動是否穿越了牆壁。

參數:方向 dJ(-1表示左,+1表示右)。

返回值:若沒有牆壁擋住,返回true,否則返回false。


功能:如果按下方向鍵,則將玩家朝相應方向移動。檢查玩家是否到達終點,如果是則結束遊戲。

功能:依照之前genMaze的結果生成地圖



生成首頁



生成末頁





總程式碼

int[][] maze = new int[50][50];
boolean[][] visited = new boolean[50][50];
boolean[][] isEnd = new boolean[50][50]; // 新增終點標記
import processing.sound.*;
SoundFile file;
int endI, endJ; // 終點的位置
int userI = 0, userJ = 0;
boolean gameFinished = false; // 遊戲是否結束的標記
boolean testVisible(int i, int j) { // true: nothing
  if (i < 0 || j < 0 || i >= 50 || j >= 50) return true;
  return visited[i][j]; // false 要用它 doing something
}
int[][] wallH = new int[50][49];
int[][] wallW = new int[49][50];
void genMaze2(int i, int j, int ii, int jj) {
  if (i == ii) wallH[i][min(j, jj)] = 1;
  if (j == jj) wallW[min(i, ii)][j] = 1;
  genMaze(ii, jj);
}
void genMaze(int i, int j) {
  visited[i][j] = true;
  println(i, j);
  while (true) {
    if (testVisible(i + 1, j) == false && int(random(2)) == 0) {genMaze2(i, j, i + 1, j);}
    if (testVisible(i - 1, j) == false && int(random(2)) == 0) {genMaze2(i, j, i - 1, j);}
    if (testVisible(i, j + 1) == false && int(random(2)) == 0) {genMaze2(i, j, i, j + 1);}
    if (testVisible(i, j - 1) == false && int(random(2)) == 0) {genMaze2(i, j, i, j - 1);}
    if (testVisible(i + 1, j) && testVisible(i - 1, j) && testVisible(i, j + 1) && testVisible(i, j - 1)) break;
  }
}
boolean gameStarted = false; // 新增遊戲是否已經開始的標記
int startTime; // 遊戲開始時間
int elapsedTime; // 已經經過的時間

int buttonX, buttonY, buttonWidth, buttonHeight;

void setup() {
  size(750, 750);
  genMaze(0, 0);
  // 設定終點的位置,這裡設定在右下角
  endI = 49;
  endJ = 49;
  isEnd[endI][endJ] = true;
  PFont myfont = createFont("標楷體", 50);
  textFont(myfont);
  textAlign(CENTER, CENTER);
  textSize(32);
  file = new SoundFile(this, "Gourmet Race.mp3");

  // 設定按鈕的位置和大小
  buttonX = width / 2 - 50;
  buttonY = height / 2 - 25;
  buttonWidth = 100;
  buttonHeight = 50;
}

void draw() {
  background(180, 230, 179);

  // 繪製迷宮牆壁
  for(int i=0; i<50; i++){
    for(int j=0; j<49; j++){
      if(wallH[i][j]==0) line(15+j*15, i*15, 15+j*15, 15+i*15);
    }
  }
  for(int i=0; i<49; i++){
    for(int j=0; j<50; j++){
      if(wallW[i][j]==0) line(j*15, 15+i*15, 15+j*15, 15+i*15);
    }
  }

  // 如果遊戲已經開始,繪製終點和玩家
  if (gameStarted) {
    fill(255, 255, 0);
    ellipse(endJ * 15 + 8, endI * 15 + 8, 14, 14);

    fill(255, 143, 187);
    ellipse(userJ * 15 + 8, userI * 15 + 8, 14, 14);

    // 如果遊戲結束,顯示通關畫面
    if (gameFinished) {
      background(180, 230, 179);
      fill(0);
      textSize(50);
      text("恭喜你啊!", width / 2 , height / 2);
      file.stop();
      textSize(32);
      text("用時: " + nf(elapsedTime / 1000, 0, 2) + " 秒", width / 2, height / 2 + 50);
      fill(0, 100, 200);
      rect(buttonX, buttonY+150, buttonWidth, buttonHeight);
      fill(255);
      textSize(20);
      text("重新開始", width / 2, height / 2 + 150);
      userJ=0;userI=0;
    }
  } else {
    // 繪製開始遊戲按鈕
    background(180, 230, 179);
    fill(0, 100, 200);
    rect(buttonX, buttonY, buttonWidth, buttonHeight);
    fill(255);
    textSize(20);
    text("開始遊戲", width / 2, height / 2);
    
  }
}

void mousePressed() {
  // 如果按鈕被點擊,開始遊戲
  if (!gameStarted && mouseX > buttonX && mouseX < buttonX + buttonWidth &&
    mouseY > buttonY && mouseY < buttonY + buttonHeight) {
      println("first");
    gameStarted = true;
    startTime = millis(); // 記錄遊戲開始的時間
    file.play(); // 開始播放音樂
  }
  if (gameFinished && mouseX > buttonX && mouseX < buttonX + buttonWidth &&
    mouseY > buttonY+150 && mouseY < buttonY + buttonHeight+150) {
      print("second");
    gameStarted = false;
    gameFinished =false;
    
  }
}

boolean noCrossWallW(int dI) {
  int nextI = userI + dI;
  if (nextI < 0 || nextI >= 50) return false;
  if (dI == -1 && wallW[nextI][userJ] == 1) return true;
  if (dI == +1 && wallW[userI][userJ] == 1) return true;
  return false;
}

boolean noCrossWallH(int dJ) {
  int nextJ = userJ + dJ;
  if (nextJ < 0 || nextJ >= 50) return false;
  if (dJ == -1 && wallH[userI][nextJ] == 1) return true;
  if (dJ == +1 && wallH[userI][userJ] == 1) return true;
  return false;
}

void keyPressed() {
  // 如果遊戲未開始,不處理按鍵事件
  if (!gameStarted) return;

  // 方向鍵移動玩家
  if (keyCode == UP && noCrossWallW(-1)) userI--;
  if (keyCode == DOWN && noCrossWallW(+1)) userI++;
  if (keyCode == LEFT && noCrossWallH(-1)) userJ--;
  if (keyCode == RIGHT && noCrossWallH(+1)) userJ++;

  // 檢查是否到達終點
  if (userI == endI && userJ == endJ) {
    gameFinished = true;
    elapsedTime = millis() - startTime; // 計算經過的時間
    file.stop(); // 停止播放音樂
  }
}

沒有留言:

張貼留言