2024年1月14日 星期日

Sangmo 互動技術Week18

總程式碼:加了音樂

import processing.sound.*;

SoundFile main;
SoundFile gameover;
SoundFile gamemu;
SoundFile run;
SoundFile go;




PImage plImg, enImg, mainuiImg;
PImage stbuttonImg1,stbuttonImg2,mainpic1,failimg,endimg; ///第一張圖剩下外框
PImage map1,map2,map3;
PImage gunA,gunB,gunC,gunD,gunE,gunF;

ArrayList<Enemy> ens = new ArrayList<Enemy>();
ArrayList<Bullet> bullets = new ArrayList<Bullet>();
Player pl = new Player(600 , 400);  ///遊戲角色生成座標

boolean look = false;

boolean mStarted = false;
boolean mover  = false;
boolean mgame = false;




long Tim;
int state=0;
int killedEnemies = 0;
int klevel= 0;
int shootspeed=20; ///射擊速度
int damageb=10; ///射擊子彈傷害
int playerlevel = 0;

int a=0,b=0,c=0,d=0;
int e=0,f=0,j=0,k=0;

int startT;
int Time;
int T=0,t=0,A=0,B=0;
int Y=5;

void setup(){ 
  size(1200, 800);  ///畫面大小
  frameRate(80);
  main = new SoundFile(this,"main.mp3");
  gamemu = new SoundFile(this,"gamemu.mp3");
  gameover = new SoundFile(this,"gameover.mp3");
  run = new SoundFile(this,"click.mp3");
  go = new SoundFile(this,"ru.mp3");
  
  
  startT = millis();
  stbuttonImg1 = loadImage("start1.png"); ///開始按鈕
  stbuttonImg2 = loadImage("start.png");   
  mainpic1 = loadImage("Paintmain.png");
  mainuiImg = loadImage("mainUI.png");  ///畫面圖片
  failimg = loadImage("fail.png");
  endimg = loadImage("end.png");
  map1 = loadImage("snow.png");
  map2 = loadImage("desert.png");
  map3 = loadImage("prison.png");
  plImg = loadImage("player.png"); ///角色圖片
  enImg = loadImage("enemy.png"); ///敵人圖片
  gunA = loadImage("gunA.png");
  gunB = loadImage("gunB.png");
  gunC = loadImage("gunC.png");
  gunD = loadImage("gunD.png");
  gunE = loadImage("gunE.png");
  gunF = loadImage("gunF.png");
  
 
  for (int i = 0; i < 3; i++)   ///開始敵人生成人數(目前為三
  {
    ens.add(new Enemy());
  }
}

void draw(){
  if (state==0 && !mStarted) {
    // 開始播放音樂
    main.play();
    mStarted = true;
  }
  if (state !=0 && mStarted){
    mStarted = false;
  }
  
  if(pl.health==2){ 
    gamemu.stop();
    gameover.play();
  }
  
  
  if(state == 0){ ///開始畫面
    StartScreen();
  }
  if(state == 5){
    chooseScreen();
  }
  
  
  if(state==1 || state == 6 ||state == 7){ ///遊戲畫面
    GameScreen();
    Timer();
    pl.move();
    pl.drawApp(); ///繪畫人物
  for (int i= 0; i < bullets.size() ; i++){  ///產生子彈
    Bullet bullet = bullets.get(i);
    bullet.move();
    bullet.drawApp();///繪畫子彈

    for (int j=0; j < ens.size() ; j++){  ///產生敵人
      Enemy enemy = ens.get(j);
      if (bullet.bump(enemy)){  ///敵人碰觸高穿透子彈時消失
        if (enemy.health <= 0) {
          ens.remove(j);
          killedEnemies++; ///觸發用
          klevel++; ///顯示等級用,最終擊殺敵人數
        }
      }
    }
    if (bullet.buloutScreen()){
      bullets.remove(i);  ///離開畫面時消除子彈
      }
    }

      if (ens.size() < 5+playerlevel){  ///敵人數量上限
      ens.add(new Enemy());
    }   
    for (Enemy en : ens){ ///簡化寫法,也能改成 for (int i = 0; i < ens.size(); i++) {Enemy en = ens.get(i);}
      en.move();
      en.drawApp(); ///繪畫敵人
    }

    if (frameCount % shootspeed == 0 && state ==1 || frameCount % shootspeed == 0 && state == 6 || frameCount % shootspeed == 0 && state == 7){
      if (bullets.size() < 10)  ///子彈3發後子彈不在射擊
      {
          bullets.add(new Bullet(pl.x,pl.y,pl.dv,damageb)); ///子彈生成屬性(x,y,速度,傷害) 會從角色開始
      }
    }
    PFont font = createFont("微軟正黑體 Bold",30);
    textFont(font);
    fill(#585454);
    text("玩家武器",50,50);
    if(e>0)image(gunA,50,55,120,100);
    if(f>0)image(gunB,50,55,120,100);
    if(j>0)image(gunC,50,55,120,100);
    if(k>0)image(gunE,50,55,120,100);
    fill(#FC3838);
    text("玩家血量"+pl.health,1000,50);
  }
  if(state==2 )EndScreen(); ///結束畫面
  if(state == 9 )choosegun(); ///選擇槍械
  if (killedEnemies % Y ==0 && killedEnemies>0) {
    state += 10;
  }
  if(state==11 || state==16 || state==17){ //升級介面
    levelmenu();
  }
  if(state==1&& look==true || state==6&& look==true || state==7 && look==true){
    skill();
  }
}

void GameScreen()
{
    if(state==1)image(map1,0,0);///遊戲場景
    if(state == 6)image(map2,0,0);
    if(state == 7)image(map3,0,0);
}

void Timer() { 
  Time = (millis() - startT) ; ///顯示時間,可以根據需要調整位置和樣式
  A=Time/1000;
  t=(Time/1000)%60; ///秒
  T=Time/60000;
}


void levelmenu() {
  noLoop();///暫停遊戲主畫面,顯示提升選項
  fill(255);
  rect(340, 100, 500, 500,28);  ///顯示選項框

  // 顯示提升選項
  fill(0);
  PFont font = createFont("微軟正黑體 Bold",40);
  textFont(font);
  fill(#A9E4FA);
  textSize(40);
  text("點擊選擇升級項目", 450, 150);
  
  fill(#7AAFF7);
  textSize(30); 

  text("移動速度Lv."+ a, 500, 250);
  
  fill(#F78484);
  textSize(30);
  text("增加傷害Lv."+ b , 500, 325);
  
  fill(#3B39F5);
  textSize(30); 
  text("射擊速度Lv."+ c, 500, 400);
  
  fill(#FFD80F);
  textSize(30); 
  text("射擊距離Lv."+ d, 500, 475);
  
  fill(#FF270F);
  textSize(30); 
  text("補血瓶", 500, 550);
}

void skill(){
  fill(#81D8FA);
  rect(450, 10, 300, 100,28);
  textSize(20);
  fill(0);
  text("移動速度:"+pl.speed,520,30);
  text("射擊傷害:"+damageb,520,60);
  text("射擊距離:"+pl.space +"格",520,90);
}
void resetS(){
  t=0;
  T=0;
  Y=5;
  pl.speed = 3;
  pl.health = 100;
  pl.space = 200;
  damageb = 10;
  shootspeed = 20;
  a=0;b=0;c=0;d=0;  
}


void chooseScreen()
{
  image(mainuiImg,0,0);
  fill(255);
  PFont font = createFont("微軟正黑體 Bold",40);
  textFont(font);
  text("地圖選擇",525,100);
  text("雪地",150,200);
  image(map1,100,250,200,200);
  fill(#FABD21);
  text("沙漠",550,200);
  image(map2,500,250,200,200);
  fill(#9D9B97);
  text("監獄",950,200);
  image(map3,900,250,200,200);
  
  fill(#A7DAFF);
  text("遊戲操作",500,550);
  fill(#43A9F5);
  text("玩家移動",50,600);
  text("上 : W鍵  "+"下 : S鍵  "+"左 : A鍵  "+"右 : D鍵  ",300,600);
  fill(#FC8787);
  textSize(20);
  text("射擊方向和移動方向相同",350,630);
  textFont(font);
  fill(#43A9F5);
  text("射擊方向反轉 : 空白鍵",300,690);
  text("屬性顯示 : TAB鍵",300,740);
  
  
  if (mouseX > 100 && mouseX < 300 && mouseY > 250 && mouseY < 450)tint(#95948F, 255);
  image(map1,100,250,200,200);
  noTint();
  if (mouseX > 500 && mouseX < 700 && mouseY > 250 && mouseY < 450)tint(#95948F, 255);
  image(map2,500,250,200,200);
  noTint();
  if (mouseX > 900 && mouseX < 1100 && mouseY > 250 && mouseY < 450)tint(#95948F, 255);
  image(map3,900,250,200,200);
  noTint();  
}

void choosegun(){
  background(#EAC566);
  
  fill(#52514C);
  PFont font = createFont("微軟正黑體 Bold",40);
  PFont font2 = createFont("微軟正黑體 Bold",20);
  textFont(font);
  fill(0);
  text("選擇槍械",525,100);
  fill(#1102F0);
  text("半自動步槍",50,220);
  text("自動步槍",320,220);
  text("衝鋒槍",680,220);
  text("狙擊步槍",950,220);
  fill(0);
  
  image(gunA,50,250,200,150); ///滑鼠移過去時會跑出槍械有什麼功能 
  if(mouseX > 50 && mouseX < 250 && mouseY > 250 && mouseY < 400){
    tint(#95948F, 255);
    image(gunA,50,250,200,150);
    noTint();
  }
  if(state==9 && mouseX > 50 && mouseX < 250 && mouseY > 250 && mouseY < 400){
    fill(255);
    rect(400,475,400,300,28);
    fill(0);
    textFont(font2);
    text("射擊速度稍微降低", 420,500);
    fill(#F77F7F);
    text("傷害稍微提升", 420,520);
    fill(0);
    text("玩家速度  "+pl.speed,420,600);
    text("玩家血量  "+pl.health,420,630);
    text("射擊傷害  15",420,660);
    text("射擊速度  每秒1.5發子彈",420,690);
    text("射擊距離  "+pl.space,420,720);
  }
  
  image(gunB,320,250,200,150);
  if(mouseX > 320 && mouseX < 520 && mouseY > 250 && mouseY < 400){
    tint(#95948F, 255);
    image(gunB,320,250,200,150);
    noTint();
  }
  if(state==9 && mouseX > 320 && mouseX < 520 && mouseY > 250 && mouseY < 400){
    fill(255);
    rect(400,475,400,300,28);
    fill(0);
    textFont(font2);
    text("屬性平均發展", 420,500);
    fill(#F77F7F);
    text("擊殺首個敵人時 立即獲得升級點", 420,520);
    fill(0);
    text("玩家速度  5",420,600);
    text("玩家血量  "+pl.health,420,630);
    text("射擊傷害  "+damageb,420,660);
    text("射擊速度  每秒3發子彈",420,690);
    text("射擊距離  "+pl.space,420,720);
  }
  image(gunC,680,250,200,150);
  if(mouseX > 680 && mouseX < 880 && mouseY > 250 && mouseY < 400){
    tint(#95948F, 255);
    image(gunC,680,250,200,150);
    noTint();
  }
  if(state==9 && mouseX > 680 && mouseX < 880 && mouseY > 250 && mouseY < 400){
    fill(255);
    rect(400,475,400,300,28);
    fill(0);
    textFont(font2);
    text("射擊距離與槍械傷害降低", 420,500);
    fill(#F77F7F);
    text("玩家速度與射擊速度皆大幅提升", 420,520);
    fill(0);
    text("玩家速度  5",420,600);
    text("玩家血量  "+pl.health,420,630);
    text("射擊傷害  8",420,660);
    text("射擊速度  每秒6發子彈",420,690);
    text("射擊距離  150.0",420,720);
  }
  image(gunE,950,250,200,150);
  if(mouseX > 950 && mouseX < 1050 && mouseY > 250 && mouseY < 400){
    tint(#95948F, 255);
    image(gunE,950,250,200,150);
    noTint();
  }
  if(state==9 && mouseX > 950 && mouseX < 1050 && mouseY > 250 && mouseY < 400){
    fill(255);
    rect(400,475,400,300,28);
    fill(0);
    textFont(font2);
    text("玩家血量與玩家速度與射擊速度降低", 420,500);
    fill(#F77F7F);
    text("射擊距離與槍械傷害大幅提升", 420,520);
    fill(0);
    text("玩家速度  2",420,600);
    text("玩家血量  50",420,630);
    text("射擊傷害  30",420,660);
    text("射擊速度  每秒1發子彈",420,690);
    text("射擊距離  500.0",420,720);
  }
}
void EndScreen(){
  image(mainuiImg,340,100,500,500);
  image(failimg,350,200,200,200);
  PFont font3 = createFont("Times New Roman",40);
  textFont(font3);
  fill(#F55454);
  text("F - A - I - L",540,200);
  PFont font = createFont("微軟正黑體 Bold",40);
  textFont(font);
  fill(255);
  text("玩家等級:"+playerlevel,550,300);
  text("時間:"+T+"分"+t+"秒",550,350);
  text("擊殺數:"+klevel,550,400);
  image(endimg,660,550,150,40);
  if(state==2 && mouseX > 660 && mouseX < 810 && mouseY > 550 && mouseY < 600){
    tint(#95948F, 255);
    image(endimg,660,550,150,40);
    noTint();
  }
}

void StartScreen()
{
  background(255);
  image(mainuiImg,0,0,width, height);
  image(mainpic1,415,100,400, 200); ///美觀主畫面用
  image(stbuttonImg1, 450, 450, 300, 100);///(x座標,y座標,寬度,高度)
  if (mouseX > 450 && mouseX < 730 && mouseY > 450 && mouseY < 560)tint(#95948F, 255);// 透明度(顏色,透明度(0 為完全透明,255 為完全不透明))
  image(stbuttonImg2, 434, 445, 327, 110);
  noTint();
}

void mousePressed()
{
  if (state == 0 && mouseX > 450 && mouseX < 730 && mouseY > 450 && mouseY < 560)
  {
    state = 9;///start畫面
    run.play();
    main.stop();
  }
  if(state==2 && mouseX > 660 && mouseX < 810 && mouseY > 550 && mouseY < 600){
    state = 0;
    resetS();
    run.play();
  }
  
  if(state==9 && mouseX > 50 && mouseX < 250 && mouseY > 250 && mouseY < 400){
    damageb= 15;
    shootspeed = 50;
    e++;
  }
  if(state==9 && mouseX > 320 && mouseX < 520 && mouseY > 250 && mouseY < 400){
    shootspeed = 25;
    killedEnemies = 1;
    f++;
  }
  if(state==9 && mouseX > 680 && mouseX < 880 && mouseY > 250 && mouseY < 400){
    shootspeed = 16;
    pl.speed = 4;
    damageb= 8;
    pl.space = 150;
    j++;
  }
  if(state==9 && mouseX > 950 && mouseX < 1050 && mouseY > 250 && mouseY < 400){
    shootspeed = 60;
    pl.speed = 1;
    damageb = 30;
    pl.space = 500;
    pl.health = 50;
    k++;
  }
 
  if(state==9 && mouseX > 50 && mouseX < 250 && mouseY > 250 && mouseY < 400)go.play();
  if(state==9 && mouseX > 320 && mouseX < 520 && mouseY > 250 && mouseY < 400)go.play();
  if(state==9 && mouseX > 680 && mouseX < 880 && mouseY > 250 && mouseY < 400)go.play();
  if(state==9 && mouseX > 950 && mouseX < 1050 && mouseY > 250 && mouseY < 400)go.play();
  
  if (state == 5 && mouseX > 100 && mouseX < 300 && mouseY > 250 && mouseY < 450){state = 1;startT=millis();gamemu.play();}///choose畫面
  if (state == 5 && mouseX > 500 && mouseX < 700 && mouseY > 250 && mouseY < 450){state = 6;startT=millis();gamemu.play();}
  if (state == 5 && mouseX > 900 && mouseX < 1100 && mouseY > 250 && mouseY < 450){state = 7;startT=millis();gamemu.play();}
  
    
  if (state > 10 && mouseX > 500 && mouseX < 500+150 && mouseY > 250-30 && mouseY < 250+20){ ///移動速度
    go.play();
    a++;
    Y += 1;
    playerlevel++;
    pl.speed += 1; 
    state -= 10;
    killedEnemies = 0;
    loop();
  }
  if (state > 10 && mouseX > 500 && mouseX < 500+150 && mouseY > 325-30 && mouseY < 325+20){ ///增加傷害
    go.play();
    b++;
    Y += 1;
    playerlevel++;
    damageb += 10;
    state -= 10;
    killedEnemies = 0;
    loop();
  }
  if (state > 10 && mouseX > 500 && mouseX < 500+150 && mouseY > 400-30 && mouseY < 400+20){ ///射擊速度
    go.play();
    c++;
    Y += 1;
    playerlevel++;
    shootspeed -= 2;
    state -= 10;
    killedEnemies = 0;
    loop();
  }
  if (state > 10 && mouseX > 500 && mouseX < 500+150 && mouseY > 475-30 && mouseY < 475+20){ ///射擊距離
    go.play();
    d++;
    Y += 1;
    playerlevel++;
    pl.space += 30;
    state -= 10;
    killedEnemies = 0;
    loop();
  } 
  if (state > 10 && mouseX > 500 && mouseX < 500+150 && mouseY > 550-30 && mouseY < 550+20){ ///玩家血量
    go.play();
    Y +=1 ;
    pl.health += 30;
    state -= 10;
    killedEnemies = 0;
    loop();
  }
}

void mouseReleased()
{
  if(state==9 && mouseX > 50 && mouseX < 250 && mouseY > 250 && mouseY < 400)state=5;
  if(state==9 && mouseX > 320 && mouseX < 520 && mouseY > 250 && mouseY < 400)state=5;
  if(state==9 && mouseX > 680 && mouseX < 880 && mouseY > 250 && mouseY < 400)state=5;
  if(state==9 && mouseX > 950 && mouseX < 1050 && mouseY > 250 && mouseY < 400)state=5;
}
void keyPressed()///鍵盤按下 空白鍵切換子彈射擊反方向
{
  if (key == TAB) {
  look=true;
  }
  if (key == 'A' || key == 'a'){
    pl.left = true;
  }else if (key == 'D' || key == 'd'){
    pl.right = true;
  }else if (key == 'W' || key == 'w'){
    pl.up = true;
  }else if (key == 'S' || key == 's'){
    pl.down = true;
  }else if (key == ' ') {
    pl.change = !pl.change; // 切換射擊方向
  }
}

void keyReleased()///鍵盤放開
{
  if (key == TAB) {
  look= false;
  }
   if (key == 'A' || key == 'a'){
    pl.left = false;
  }else if (key == 'D' || key == 'd'){
    pl.right = false;
  }else if (key == 'W' || key == 'w'){
    pl.up = false;
  }else if (key == 'S' || key == 's'){
    pl.down = false;
  }
}


玩家/敵人/子彈程式碼

class Player  ///定義人物屬性 week12
{
  float x, y;
  int speed = 3;///移動速度
  int dv = 0; ///控制子彈方向
  boolean left, right, up, down,skill;
  boolean change = false;
  int health = 100;
  float space = 200;
  

  Player(float dx, float dy){
     x = dx;
     y = dy;
   }
   
  void move(){
    if (left){
      x -= speed;
      dv = 3;
    }
    if (right){
      x += speed;
      dv = 1;
    }
    if (up){
      y -= speed;
      dv = 0;
    }
    if (down){
      y += speed;
      dv = 2;
    }
  }


  void drawApp(){
    fill(255); ///血條顏色為白色
    rect(x , y-15, health * 0.5, 5);  ///血條的長度為 health * 0.5
    image(plImg, x, y, 50, 60);
  }
}

class Enemy ///定義敵人的屬性 week12
{
  float x, y;
  float speed = 1;
  int health = 50;
  float Endv;
  
   Enemy(float vx, float vy, int dir) 
  {
   x = vx;
   y = vy;
   Endv = dir;
  }

  Enemy(){
    reset();
  }
  
  void move() ///移動時會以最短距離靠近角色
  {
    float angle = atan2(pl.y - y, pl.x - x);  ///計算玩家與敵人的角度
    x += cos(angle) * speed;
    y += sin(angle) * speed;
    
    if (dist(x, y, pl.x, pl.y) < 40) {
      pl.health -= 1;
      if(pl.health<1)state = 2;
    }
  }
  
  void drawApp() 
  { 
    image(enImg, x, y, 50, 50);
  }

  void reset() 
  { 
     x = random(pl.x+400); ///隨機傳送敵人,並與玩家有一段距離
     y = random(pl.y+400);
  }
}


class Bullet ///定義子彈的屬性
{
  float x, y;
  float speed = 30; ///移動速度
  float damage = 10;
  int dv;
  
  
  boolean bump(Enemy en) ///Enemy en為了檢查某個敵人是否被碰到(故此不能與class Enemy分開)
  {
    if(dist(x,y,en.x,en.y)< 30){
      en.health -= damage;
      return true;
  }
  return false;
  }
  
  boolean buloutScreen() 
  { 
    return (y < pl.y- pl.space || y > pl.y+pl.space || x < pl.x-pl.space || x > pl.x+pl.space);///子彈範圍
  }
  
   Bullet(float vx, float vy, int dir,float damagebullet) ///預設子彈屬性
  {
   x = vx;
   y = vy;
   if (pl.change) {
      dv = (dir + 2) % 8;  ///方向反轉
    } else {
      dv = dir;
    }
   damage = damagebullet;
  }

  void move() 
  {
   if (dv == 0 || dv == 4){ ///未移動時子彈預設向上
      y -= speed;
    }else if (dv == 3 || dv == 7){ ///向左
      x -= speed;
    }else if (dv == 1 || dv ==5 ){ ///向右
      x += speed;
    } else if (dv == 2 || dv == 6 ){ ///向下
      y += speed;
    }
  }
  
  
  void drawApp() 
  {
    if( dv==2 || dv==0 || dv==4 || dv==6){
      fill(#F7C51E);
      ellipse(x+25, y+25, 6, 22); ///子彈外觀,射擊初始位置
    }
    else if(dv==3 || dv==1 || dv==7 || dv==5){
      fill(#F7C51E);
      ellipse(x+25, y+25, 22, 6); ///子彈外觀,射擊初始位置
    }
  }
}

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(); // 停止播放音樂
  }
}

week18 UC

 期末展示

新增了剛開始的主畫面圖片,以及分數的計分,當勝利者的那一方得一分。

int boardSize = 15; 

int cellSize;       

int[][] board;      

int currentPlayer = 1; 

boolean gameStarted = false;

PImage backgroundImage; // 新增一個 PImage 物件

boolean showBackground = true; // 控制是否顯示背景圖片

int player1Score = 0;

int player2Score = 0;


void setup() {

  size(600, 600);

  cellSize = width / boardSize;

  board = new int[boardSize][boardSize];

  backgroundImage = loadImage("background.jpg"); // 載入背景圖片

  drawStartScreen();

  loop(); // 啟動 draw() 函數的連續呼叫

}


void draw() {

  background(255);

  if (gameStarted) {

    if (showBackground) {

      image(backgroundImage, 0, 0, width, height);

    }

    drawBoard();

    drawStones();

    if (checkWin()) {

      textSize(60);

      fill(0);

      textAlign(CENTER, CENTER);

      text("Player " + currentPlayer + " wins!", width / 2, height / 2);

      updateScore();

      showBackground = true; // 顯示背景圖片

      noLoop(); // 停止 draw() 函數的連續呼叫,直到重新開始遊戲

    }

    displayScores(); // 顯示分數

  } else {

    drawStartScreen();

  }

}


void drawStartScreen() {

  if (showBackground) {

    image(backgroundImage, 0, 0, width, height);

  }

  

  textAlign(CENTER, CENTER);

  textSize(32);

  fill(0);

  text("Game", width / 2, height / 2 - 50);

  textSize(20);

  text(" 'backgammon' ", width / 2, height / 2 + 50);

 

  rectMode(CENTER);

  fill(150);

  rect(width / 2, height / 2 + 100, 150, 50);

  fill(0);

  textSize(16);

  text("START", width / 2, height / 2 + 100);

}


void drawBoard() {

  for (int i = 0; i < boardSize; i++) {

    for (int j = 0; j < boardSize; j++) {

      fill(220, 180, 120); 

      stroke(0);

      rect(i * cellSize, j * cellSize, cellSize, cellSize);

    }

  }

}


void drawStones() {

  for (int i = 0; i < boardSize; i++) {

    for (int j = 0; j < boardSize; j++) {

      if (board[i][j] == 1) {

        fill(0); 

        ellipse(i * cellSize + cellSize / 2, j * cellSize + cellSize / 2, cellSize, cellSize);

      } else if (board[i][j] == 2) {

        fill(255);

        ellipse(i * cellSize + cellSize / 2, j * cellSize + cellSize / 2, cellSize, cellSize);

      }

    }

  }

}


void mousePressed() {

  if (!gameStarted && mouseX > width / 2 - 75 && mouseX < width / 2 + 75 && mouseY > height / 2 + 75 && mouseY < height / 2 + 125) {

    gameStarted = true;

    showBackground = false; // 不顯示背景圖片

  } else if (gameStarted) {

    int i = mouseX / cellSize;

    int j = mouseY / cellSize;


    if (isValidMove(i, j)) {

      board[i][j] = currentPlayer;

      if (checkWin()) {

        gameStarted = false;

        showBackground = true; // 顯示背景圖片

        loop(); // 重新啟動 draw() 函數的連續呼叫

      } else {

        currentPlayer = 3 - currentPlayer; 

      }

    }

  }

}


boolean isValidMove(int i, int j) {

  return board[i][j] == 0;

}


boolean checkWin() {

  for (int i = 0; i < boardSize; i++) {

    for (int j = 0; j < boardSize; j++) {

      if (board[i][j] != 0) {

        if (checkLine(i, j, 1, 0)) return true;

        if (checkLine(i, j, 0, 1)) return true;

        if (checkLine(i, j, 1, 1)) return true;

        if (checkLine(i, j, -1, 1)) return true;

      }

    }

  }

  return false;

}


boolean checkLine(int x, int y, int dx, int dy) {

  int count = 0;

  int player = board[x][y];

  for (int i = 0; i < 5; i++) {

    int newX = x + i * dx;

    int newY = y + i * dy;

    if (newX >= 0 && newX < boardSize && newY >= 0 && newY < boardSize && board[newX][newY] == player) {

      count++;

    }

  }

  return count == 5;

}


void updateScore() {

  if (checkWin()) {

    if (currentPlayer == 1) {

      player1Score++;

    } else if (currentPlayer == 2) {

      player2Score++;

    }

    println("Player 1 Score: " + player1Score);

    println("Player 2 Score: " + player2Score);

  }

}


void displayScores() {

  textSize(20);

  fill(0);

  textAlign(CENTER, CENTER);

  text("Player 1 Score: " + player1Score, width / 2, height - 30);

  text("Player 2 Score: " + player2Score, width / 2, height - 10);

}




好想放假 Week17

 Week17

製作期末作業-fina錄影上傳影上傳







好想放假Week16

 Week16

製作期末作業Part5

step01

開啟舊檔,修改上禮拜留下的bug



step02

增加主頁按鈕





好想放假Week15

 Week15

製作期末作業Part4

step01






step02
增加按鈕






好像放假 Week14

 Week14

製作期末作業Part3

step01

開啟舊檔,利用先前的程式碼,效仿製作第一個圖時的方式,來設定上周製作好的圖






step02

設定時間