2023年1月11日 星期三

TC*(˙Ⱉ˙ฅ)​-week17

上周做出了白色母球如果被射進六邊的黑色球袋中,就會被扣分
這周我想把剩餘的撞球寫完,並且改良了一下玩法
如果將規則改為,在規定的時間內看看可以射出多少顆母球呢?
當然事情並不會這麼簡單,若場地上還有其他障礙物,且被碰到後會倒扣一分呢?

當然我們要先結合之前學過的知識來繼續寫遊戲,目前用到了音樂播放、布林變數、滑鼠事件、碰撞偵測等等

像是如果撞到了其他顏色的球就會死亡隨機重生在場地上,所以還要設置一個回復按鍵,我們只需要改寫上周最後一段的reset()函式
void reset(){
  ballX=random(1100);//隨機生成的x座標範圍
  ballY=random(750);//隨機生成的y座標範圍
  shooting=false;
  ballVX=0;
  ballVY=0;
}
只要是隨機就會運用到random這個函式,但範圍不要設置超出場地,因此取(1100,750)的值內

接下來還需要使用場景切換,宣告初始場景並在draw()函式執行該場景會需要做到的指令(已經先將程式碼分成兩頁,當有需要使用到分頁程式碼時在進行呼叫)

程式碼主頁
import processing.sound.*;//聲音的函式庫
SoundFile sound1;//音檔1
PImage home_img,start_img,go_img;//讀入封面,開始遊戲,點go
PImage table_img,sayrule_img,stage4_img;//讀入遊戲畫面桌子,規則說明
int w=1200,h=750,stage=1;//畫面寬度,畫面高度,當前場景編號
void setup(){//基本設定
  size(1200,900);//視窗長寬
  sound1=new SoundFile(this,"music01.mp3");//載入音樂
  sound1.play();//播放音樂
  home_img = loadImage("home.png");//載入封面圖home.png
  start_img = loadImage("start.png");//載入開始遊戲鍵start.png
  go_img = loadImage("go.png");//載入go.png
  table_img = loadImage("table.png");//載入遊戲畫面table.png
  sayrule_img = loadImage("sayrule.png");//載入規則說明sayrule.png
  stage4_img = loadImage("stage4.png");//載入stage4.png
}
void draw(){//畫圖
  if(stage==1){//初始頁面舞台1,首頁場景設定
    image(home_img,0,0,1200,900);//home圖片的x,y座標(0,0),(1200,900)是圖片寬高
    image(start_img,1000,750,150,75);//start圖片的x,y座標(1000,600),(150,75)是圖片寬高
    if(pressed_start == true)rect(1000,600,150,75);//按下開始遊戲的按鈕後
  }
  if(stage==2){//當被切換到舞台2進入遊戲畫面的設定
    image(sayrule_img,0,0,1200,900);//可以調整圖片大小,規則說明的x,y座標(0,0),(1200,900)是圖片寬高
    image(go_img,860,750,150,75);//rule圖片的x,y座標(800,600),(150,75)是圖片寬高
    if(pressed_go == true)rect(860,750,150,75);//按下go的按鈕後
  }
  if(stage==3){//當被切到舞台3時
    draw2();//執行分頁stage3的程式
  }
  if(stage==4){//當被切換到舞台4時
    image(stage4_img,0,0,1200,900);//可以調整圖片大小,規則說明的x,y座標(0,0),(1200,900)是圖片寬高
  }
}
boolean pressed_start=false;//預設按壓開始遊戲鍵為關閉狀態
boolean pressed_go=false;//預設按壓規則介紹鍵為關閉狀態
void mousePressed(){//按下滑鼠時
  if(stage==1){//當被切換到舞台1
    if(1000<mouseX && mouseX < 1000+200 && 750<mouseY && mouseY<750+100){
      //判定圖片範圍,xy座標(1000,600),1000+200就是判定範圍有多寬,600+100就是判定範圍有多高
      pressed_start=true;//如果按壓開始遊戲鍵成立
      stage=2;//切換到場景2,介紹遊戲
      pressed_start=false;//關閉按下開始鍵
    }
  }
  if(stage==2){//當被切換到舞台2
    if(860<mouseX && mouseX < 860+150 && 750<mouseY && mouseY<750+80){
      //判定圖片範圍,xy座標(1000,600),1000+200就是判定範圍有多寬,750+100就是判定範圍有多高
      pressed_go=true;//如果按壓開始遊戲鍵成立
      stage=3;//切換到場景3,開始遊戲
      pressed_go=false;//關閉按下go鍵
    }
  }
  if(stage==3){//當被切換到舞台3
    len0 = dist(ballX,ballY,mouseX,mouseY);//計算白色母球和鼠標(X,Y)座標的距離向量
  }
}
void mouseReleased(){//放開滑鼠時
  if(stage==3){//當切換到舞台3時
    len1 = dist(ballX,ballY,mouseX,mouseY);//計算白色母球和鼠標(X,Y)座標的距離向量
    float v = len1-len0;//計算兩者向量相減後的力矩
    ballVX = -v * cos(angle);//COS角度
    ballVY = -v * sin(angle);//SIN角度
    shooting=true;//打開布林變數,球可以被射出
  }
}

程式碼分頁(stage3)
float [] holeX={50,600,1148,50,600,1151};//48,600,1150,65,600,1150
float [] holeY={52,46,57,692,703,695};//50,50,60,690,700,700
float ballX=180,ballY=200,ballVX=0,ballVY=0,angle=0;//設定球一開始出現的xy位置,以及角度初始化
float score=0;//將成績初始化歸0
float len0=0,len1=0;//距離向量歸0
boolean shooting=false;//射擊的布林變數預設關閉
void draw2(){
  image(table_img,0,0,1200,750);//可以調整圖片大小,table圖片的x,y座標(0,0),(1200,750)是圖片寬高
  fill(#2B793A);//綠色的長方形
  rect(47,47,1110,660);//測試畫長方(47,47是x,y座標/1110,660是長寬
  
  fill(#A76565);//棕色的長方形
  rect(0,750,1200,300);//測試畫長方(47,47是x,y座標/1110,660是長寬
  
  fill(#FFFFFF);//白色的球
  ellipse(ballX,ballY,30,30);//畫個20*20圓形
  angle = atan2(mouseY-ballY,mouseX-ballX);//算出角度的tan2(),這裡是公式
  
  if(shooting==false){//如果布林變數為關閉
    strokeWeight(10);//粗度為10的直線
    stroke(#FFFF00);//直線顏色是黃色
    line(ballX,ballY,ballX+cos(angle)*100,ballY+sin(angle)*100);//x,y座標固定,
    
    strokeWeight(5);//粗度為5的直線
    stroke(#0000FF);//直線顏色是藍色
    line(ballX,ballY,ballX+cos(angle)*len0,ballY+sin(angle)*len0);//x,y座標固定,
    
    strokeWeight(3);//粗度為3的直線
    stroke(#00FF00);//直線顏色是綠色
    line(ballX,ballY,ballX+cos(angle)*len0,ballY+sin(angle)*len0);//x,y座標固定,
    
    strokeWeight(1);//粗度為1的直線
    stroke(0);//直線顏色是黑色
    line(ballX,ballY,mouseX,mouseY);//x,y座標固定,mouse會隨著滑鼠移動而改變線的長度
  }
  if(ballX+ballVX>1200-5 || ballX+ballVX<10){//ballX+vx>1200控制右邊x邊界,ballX+vx<10控制左邊x邊界
    ballVX=-ballVX;//會反彈
  }
  if(ballY+ballVY>720-5 || ballY+ballVY<25){//ballY+vy>720控制下面y邊界,ballY+vy<10控制上面y邊界
    ballVY=-ballVY;//會反彈
  }
  for(int i=0;i<6;i++){//繪製六個球袋
    fill(#000000);//黑色的球袋
    ellipse(holeX[i],holeY[i],50,50);//最後面兩個數字是桌面六個圓形洞大小
    if(shooting && dist(ballX,ballY,holeX[i],holeY[i])<30){//計算白色母球和球袋的XY座標距離是否小於30
     score++;//如果母球射入球袋就會扣分
     reset();//隨機復活
     println(score);//顯示成績
    }
    ballX += ballVX/10;
    ballY += ballVY/10;
    ballVX*=0.99;//替球增加摩擦力
    ballVY*=0.99;//替球增加摩擦力
  }
}
void reset(){//隨機生成在場地上
  ballX=random(1100);//隨機X座標
  ballY=random(750);//隨機Y座標
  shooting=false;//關閉布林函數,預設非射擊狀態
  ballVX=0;//X方向的速度歸0
  ballVY=0;//Y方向的速度歸0
}

然後就可以得到這幾個頁面(會播放音樂




1.遊戲進行中,還會用到計時器的寫法
先宣告時間變數(宣告在哪頁都沒有關係)
int startTime;//遊戲開始時間
int Time;//計時

然後寫進分頁的void draw2()函式裡
  int m = (150-((millis()/1000)-(startTime/1000)))/60%60;//計時器,毫秒是千分之一秒,150秒約2:30,因為要倒數就要%60,設定分鐘
  int s = (150-((millis()/1000)-(startTime/1000)))%60;//計時器,毫秒是千分之一秒,150秒約2:30,因為要倒數就要%60,設定秒鐘
  String mm = nf(m, 2);//00,ex:01分鐘
  String ss = nf(s, 2);//00,ex:01秒鐘
  String time = "剩下"+":"+mm+":"+ss;//顯示剩餘的時間


2.若想控制字體(ex:剩餘時間的剩餘),就使用PFont font=createFont("字體名稱",字體大小);來固定
PFont font=createFont("標楷體",20);//設定創建字體,全部的字體都會被設置為標楷體 textFont(font);//文字字體

將1、2點結合起來,如程式所示
程式主頁
import processing.sound.*;//聲音的函式庫
SoundFile sound1;//音檔1
PImage home_img,start_img,go_img;//讀入封面,開始遊戲,點go
PImage table_img,sayrule_img,stage4_img;//讀入遊戲畫面桌子,規則說明
int w=1200,h=750,stage=1;//畫面寬度,畫面高度,當前場景編號
void setup(){//基本設定
  size(1200,900);//視窗長寬
  PFont font=createFont("標楷體",20);//設定創建字體,全部的字體都會被設置為標楷體
  textFont(font);//文字字體
  sound1=new SoundFile(this,"music01.mp3");//載入音樂
  sound1.play();//播放音樂
  home_img = loadImage("home.png");//載入封面圖home.png
  start_img = loadImage("start.png");//載入開始遊戲鍵start.png
  go_img = loadImage("go.png");//載入go.png
  table_img = loadImage("table.png");//載入遊戲畫面table.png
  sayrule_img = loadImage("sayrule.png");//載入規則說明sayrule.png
  stage4_img = loadImage("stage4.png");//載入stage4.png
}
void draw(){//畫圖
  if(stage==1){//初始頁面舞台1,首頁場景設定
    image(home_img,0,0,1200,900);//home圖片的x,y座標(0,0),(1200,900)是圖片寬高
    image(start_img,1000,750,150,75);//start圖片的x,y座標(1000,600),(150,75)是圖片寬高
    if(pressed_start == true)rect(1000,600,150,75);//按下開始遊戲的按鈕後
  }
  if(stage==2){//當被切換到舞台2進入遊戲畫面的設定
    image(sayrule_img,0,0,1200,900);//可以調整圖片大小,規則說明的x,y座標(0,0),(1200,900)是圖片寬高
    image(go_img,860,750,150,75);//rule圖片的x,y座標(800,600),(150,75)是圖片寬高
    if(pressed_go == true)rect(860,750,150,75);//按下go的按鈕後
  }
  if(stage==3){//當被切到舞台3時
    draw2();//執行分頁stage3的程式
  }
  if(stage==4){//當被切換到舞台4時
    image(stage4_img,0,0,1200,900);//可以調整圖片大小,規則說明的x,y座標(0,0),(1200,900)是圖片寬高
  }
}
boolean pressed_start=false;//預設按壓開始遊戲鍵為關閉狀態
boolean pressed_go=false;//預設按壓規則介紹鍵為關閉狀態
void mousePressed(){//按下滑鼠時
  if(stage==1){//當被切換到舞台1
    if(1000<mouseX && mouseX < 1000+200 && 750<mouseY && mouseY<750+100){
      //判定圖片範圍,xy座標(1000,600),1000+200就是判定範圍有多寬,600+100就是判定範圍有多高
      pressed_start=true;//如果按壓開始遊戲鍵成立
      stage=2;//切換到場景2,介紹遊戲
      pressed_start=false;//關閉按下開始鍵
    }
  }
  if(stage==2){//當被切換到舞台2
    if(860<mouseX && mouseX < 860+150 && 750<mouseY && mouseY<750+80){
      //判定圖片範圍,xy座標(1000,600),1000+200就是判定範圍有多寬,750+100就是判定範圍有多高
      pressed_go=true;//如果按壓開始遊戲鍵成立
      stage=3;//切換到場景3,開始遊戲
      pressed_go=false;//關閉按下go鍵
    }
  }
  if(stage==3){//當被切換到舞台3
    len0 = dist(ballX,ballY,mouseX,mouseY);//計算白色母球和鼠標(X,Y)座標的距離向量
  }
}
void mouseReleased(){//放開滑鼠時
  if(stage==3){//當切換到舞台3時
    len1 = dist(ballX,ballY,mouseX,mouseY);//計算白色母球和鼠標(X,Y)座標的距離向量
    float v = len1-len0;//計算兩者向量相減後的力矩
    ballVX = -v * cos(angle);//COS角度
    ballVY = -v * sin(angle);//SIN角度
    shooting=true;//打開布林變數,球可以被射出
  }
}


程式分頁(stage3)
float [] holeX={50,600,1148,50,600,1151};//48,600,1150,65,600,1150
float [] holeY={52,46,57,692,703,695};//50,50,60,690,700,700
float ballX=180,ballY=200,ballVX=0,ballVY=0,angle=0;//設定球一開始出現的xy位置,以及角度初始化
float score=0;//將成績初始化歸0
float len0=0,len1=0;//距離向量歸0
boolean shooting=false;//射擊的布林變數預設關閉
int startTime;//遊戲開始時間
int Time;//計時
void draw2(){
  //場景地圖
  image(table_img,0,0,1200,750);//可以調整圖片大小,table圖片的x,y座標(0,0),(1200,750)是圖片寬高
  fill(#2B793A);//綠色的長方形
  rect(47,47,1110,660);//測試畫長方(47,47是x,y座標/1110,660是長寬
  
  fill(#A76565);//棕色的長方形
  rect(0,750,1200,300);//測試畫長方(47,47是x,y座標/1110,660是長寬
  
  //計時器
  int m = (150-((millis()/1000)-(startTime/1000)))/60%60;//計時器,毫秒是千分之一秒,150秒約2:30,因為要倒數就要%60,設定分鐘
  int s = (150-((millis()/1000)-(startTime/1000)))%60;//計時器,毫秒是千分之一秒,150秒約2:30,因為要倒數就要%60,設定秒鐘
  String mm = nf(m, 2);//00,ex:01分鐘
  String ss = nf(s, 2);//00,ex:01秒鐘
  String time = "剩下"+":"+mm+":"+ss;//顯示剩餘的時間
  if(millis()-startTime>=150000){//如果時間超過或剛好等於兩分半,切換到場景4
    stage=4;
  }else if(millis()-startTime<=150000){//如果時間還沒超過兩分半,就還在倒數
    fill(#FFFFFF);//剩餘時間的白色字體顏色
    textSize(40);//字體大小
    text(time,20,830);//時間,X座標20,Y座標830
  }
  
  //母球相關
  fill(#FFFFFF);//白色的球
  ellipse(ballX,ballY,30,30);//畫個20*20圓形
  angle = atan2(mouseY-ballY,mouseX-ballX);//算出角度的tan2(),這裡是公式
  
  if(shooting==false){//如果布林變數為關閉
    strokeWeight(10);//粗度為10的直線
    stroke(#FFFF00);//直線顏色是黃色
    line(ballX,ballY,ballX+cos(angle)*100,ballY+sin(angle)*100);//x,y座標固定,
    
    strokeWeight(5);//粗度為5的直線
    stroke(#0000FF);//直線顏色是藍色
    line(ballX,ballY,ballX+cos(angle)*len0,ballY+sin(angle)*len0);//x,y座標固定,
    
    strokeWeight(3);//粗度為3的直線
    stroke(#00FF00);//直線顏色是綠色
    line(ballX,ballY,ballX+cos(angle)*len0,ballY+sin(angle)*len0);//x,y座標固定,
    
    strokeWeight(1);//粗度為1的直線
    stroke(0);//直線顏色是黑色
    line(ballX,ballY,mouseX,mouseY);//x,y座標固定,mouse會隨著滑鼠移動而改變線的長度
  }
  if(ballX+ballVX>1200-5 || ballX+ballVX<10){//ballX+vx>1200控制右邊x邊界,ballX+vx<10控制左邊x邊界
    ballVX=-ballVX;//會反彈
  }
  if(ballY+ballVY>720-5 || ballY+ballVY<25){//ballY+vy>720控制下面y邊界,ballY+vy<10控制上面y邊界
    ballVY=-ballVY;//會反彈
  }
  for(int i=0;i<6;i++){//繪製六個球袋
    fill(#000000);//黑色的球袋
    ellipse(holeX[i],holeY[i],50,50);//最後面兩個數字是桌面六個圓形洞大小
    if(shooting && dist(ballX,ballY,holeX[i],holeY[i])<30){//計算白色母球和球袋的XY座標距離是否小於30
     score++;//如果母球射入球袋就會扣分
     reset();//隨機復活
     println(score);//顯示成績
    }
    ballX += ballVX/10;
    ballY += ballVY/10;
    ballVX*=0.99;//替球增加摩擦力
    ballVY*=0.99;//替球增加摩擦力
  }
}
void reset(){//隨機生成在場地上
  ballX=random(1100);//隨機X座標
  ballY=random(750);//隨機Y座標
  shooting=false;//關閉布林函數,預設非射擊狀態
  ballVX=0;//X方向的速度歸0
  ballVY=0;//Y方向的速度歸0
}







成績的顯示也是依樣畫葫蘆
加在draw2()的函式內
  //成績顯示
  fill(#FFFFFF);//白色字體顏色
  textSize(40);//字體大小
  text(score,300,830);//成績




以及設置了從頭到尾都會出現的障礙物(紅球),還有不同時間會持續存在並干擾玩家的其他色球
首先都要先宣告變數
float ballX2=200,ballY2=300,ballVX2=0,ballVY2=0;//設定球一開始出現的XY位置
float ballX3=300,ballY3=400,ballVX3=0,ballVY3=0;//設定球一開始出現的XY位置
float ballX4=400,ballY4=500,ballVX4=0,ballVY4=0;//設定球一開始出現的XY位置
float ballX5=400,ballY5=500,ballVX5=0,ballVY5=0;//設定球一開始出現的XY位置
float ballX6=200,ballY6=300,ballVX6=0,ballVY6=0;//設定球一開始出現的XY位置

然後在draw2()函式中寫出對應條件
  //一直在場上的紅球
  fill(#FF6A6A);//粉色的球
  ellipse(random(1100),random(750),20,20);//畫個20*20圓形
  //frameRate(3);//每秒刷新多少幀數,一秒鐘刷新10幀
  if(shooting && dist(ballX,ballY,ballX2,ballY2)<15){//計算白色母球和橘球的XY座標距離是否小於15
     score--;//如果母球射入球袋就會扣分
     reset();//隨機復活
     println(score);//顯示成績
  }
  

    //不同時間會跑出來干擾的色球
   if(m==2 && s>0 && s<15){//在2:00~2:15秒時,會有橘色球來搗亂
    fill(#FFCB1C);//橘色的球
    ellipse(random(500),random(600),20,20);//畫個20*20圓形
    //frameRate(3);//每秒刷新多少幀數,一秒鐘刷新10幀
    if(shooting && dist(ballX,ballY,ballX6,ballY6)<20){//計算白色母球和橘球的XY座標距離是否小於20
       score--;//如果碰到就會扣分
       reset();//隨機復活
       println(score);//顯示成績
    }
   }
  
  if(m==1 && s>0 && s<59){//在1:00~1:59秒時,會有藍色球來搗亂
    fill(#93B9EA);//藍色的球
    ellipse(random(900),random(600),20,20);//畫個20*20圓形
    //frameRate(3);//每秒刷新多少幀數,一秒鐘刷新10幀
    if(shooting && dist(ballX,ballY,ballX3,ballY3)<15){//計算白色母球和藍球的XY座標距離是否小於15
       score--;//如果碰到就會扣分
       reset();//隨機復活
       println(score);//顯示成績
    }
   }
   
    if(m==1 && s>0 && s<30){//在1:00~1:30秒時,會有綠色球來搗亂
    fill(#3BB281);//綠色的球
    ellipse(random(900),random(600),20,20);//畫個20*20圓形
    //frameRate(3);//每秒刷新多少幀數,一秒鐘刷新10幀
    if(shooting && dist(ballX,ballY,ballX5,ballY5)<20){//計算白色母球和綠球的XY座標距離是否小於20
       score--;//如果碰到就會扣分
       reset();//隨機復活
       println(score);//顯示成績
    }
   }
   
   if(m==0 && s>0 && s<59){//在0:00~0:59秒時,會有藍色球來搗亂
    fill(#93B9EA);//藍色的球
    ellipse(random(800),random(300),20,20);//畫個20*20圓形
    //frameRate(3);//每秒刷新多少幀數,一秒鐘刷新10幀
    if(shooting && dist(ballX,ballY,ballX3,ballY3)<20){//計算白色母球和藍球的XY座標距離是否小於20
       score--;//如果碰到就會扣分
       reset();//隨機復活
       println(score);//顯示成績
    }
  }
 
    if(m==0 && s>0 && s<59){//在0:00~0:59秒時,會有黃色球來搗亂
    fill(#FFFCA7);//黃色的球
    ellipse(random(1000),random(800),20,20);//畫個20*20圓形
    //frameRate(3);//每秒刷新多少幀數,一秒鐘刷新10幀
    if(shooting && dist(ballX,ballY,ballX4,ballY4)<30){//計算白色母球和黃球的XY座標距離是否小於30
       score--;//如果碰到就會扣分
       reset();//隨機復活
       println(score);//顯示成績
    }
  }




沒有留言:

張貼留言