2020年3月29日 星期日

Processing課程 #03_Week04 發射子彈與簡單碰撞

2020/3/27 程式設計 Processing課程內容 08160741




一.發射子彈與簡單碰撞



發射子彈其實就只是在角色的位置繪製圖片或形狀模擬子彈的樣子,再將子彈重複執行往上移動,但我自己覺得既然都要模擬發射物了,目標是一定要有的,於是我想了一下碰撞的原理。


1.宣告


  1. PImage player,monster,boom;  //宣告玩家、怪物、爆炸特效的圖片
  2. int []x = {0,0,0,0,0,0,0,0};  //子彈的X座標
  3. int []y = {0,0,0,0,0,0,0,0};  //子彈的Y座標
  4. int n = 0;  //目前的發射次數
  5. int cd = 0;  //每顆子彈的間隔時間
  6. int posX = 134,posY = 450; //玩家的座標
  7. float MposX = 100,MposY = 24; //怪物的座標
  8. int ifcollision = 0; //是否有碰撞(會解釋)
  9. int timing1 = 0,timing2 = 0; //兩個計時器
  10. int looking = 0;  //控制怪物目前的左右移動方向

2.設定


  1. void setup() 
  2. {
  3.      size(300,500);  //視窗大小
  4.      player = loadImage("player.png");  //讀取玩家圖片
  5.      monster = loadImage("monster.png");  //讀取怪物圖片
  6.      boom = loadImage("boom.png");  //讀取爆炸特效圖片
  7. }

3.偵測碰撞的函數

這邊需要稍微解釋一下,我自己覺得最簡單的碰撞判斷,基本上就是以X和Y座標去做比較,達到條件就輸出結果,解釋如下:
現在有A跟B兩個矩形,分別有最大最小X座標。
若A往前移動與B重疊的話,則A的最大X會大於B的最小X:A_maxX > B_minX
反過來則是B的最小X會大於A的最大X:B_minX > A_maxX
Y軸則同理。
  1. void Collision(float posX,float posY)  //自訂義的函數名稱,輸入浮點數posX和posY
  2. {
  3.   //以下分為兩塊,上面為邊長為15的子彈
  4.   float minX1 = posX - 15 / 2;  //最小X為自身中心X減掉邊長除2
  5.   float maxX1 = posX + 15 / 2;  //最大X為自身中心X加上邊長除2
  6.   float minY1 = posY - 15 / 2;  //同X軸
  7.   float maxY1 = posY + 15 / 2;
  8.   //計算方式都一樣,下面為怪物的
  9.   float minX2 = MposX - 33 / 2;
  10.   float maxX2 = MposX + 33 / 2;
  11.   float minY2 = MposY - 24 / 2;
  12.   float maxY2 = MposY + 24 / 2;
  13.   //將上面圖文解釋的條件全部加上去的總條件,必須達成以下全部條件才會回傳
  14.   if (minX1 > minX2 && maxX2 > minX1 && maxY1 > minY2 && maxY2 > minY1)
  15.   {
  16.     ifcollision++;  //達成條件,回傳1
  17.   }
  18. }

4.描繪

  1. void draw()
  2. {
  3.   background(0);  //黑色背景
  4.   for (int i = 0;i < 8;i++)  //發射子彈
  5.   {
  6.      square(x[i],y[i],15);  //子彈為15X15的正方形
  7.      y[i] -= 8;  //重複往上移動8
  8.      Collision(x[i],y[i]);  //用函數判斷碰撞
  9.   }
  10.   image(player,posX,posY,33,24);  //繪製玩家圖片
  11.   //以下為繪製怪物圖片的條件
  12.   if (ifcollision == 0)  //如果沒有被子彈打到的話
  13.   {  
  14.      if (looking == 0 && timing1 < 50)  //看右邊和計時器1小於50
  15.      {
  16.        MposX += 2;  //怪物往右邊移動2
  17.        timing1++;  //計時器開始計時
  18.        if (timing1 == 50) looking = 1;  //如果計了50次,則轉向左邊
  19.      }
  20.      else if (looking == 1)  //如果轉向了左邊
  21.      {
  22.        MposX -= 2;  //怪物往左邊移動2
  23.        timing1--;  //計時器開始倒數
  24.       if (timing1 == 0) looking = 0;  //如果倒數完了,既怪物已回到原點,則轉向右邊
  25.      }
  26.      image(monster,MposX,MposY,33,24);  //如果沒有被子彈打到的話,繪製怪物圖片
  27.   }
  28.   else  //如果被子彈打到的話
  29.   {
  30.       if (timing2 < 100)  //計時器最多計時100次
  31.       {
  32.           if (timing2 % 20 > 10) image(boom,MposX,MposY,33,24);  //繪製爆炸特效
  33.           timing2++;  //計時一次
  34.       }
  35.   }
  36.   if (keyPressed && keyCode == RIGHT)  //按右鍵往右走
  37.   {
  38.       if ((posX + 5) < 267) posX += 5;
  39.   }
  40.   if (keyPressed && keyCode == LEFT)  //按左鍵往左走
  41.   {
  42.       if ((posX - 5) > 0) posX -= 5;
  43.   }
  44.   if (cd > 0) cd--;  //使用過子彈的話,則進行冷卻時間倒數
  45. }

4.鍵盤按壓

  1. void keyPressed()
  2. {
  3.   if (key == 'z' && cd == 0)  //如果按了鍵盤上的Z鍵且子彈沒有進入冷卻時間
  4.    {
  5.      x[n] = posX + 8;  //以玩家的座標為基準往上發射
  6.      y[n] = posY - 5;
  7.      n = (n+1)%8;  //回收子彈
  8.      cd = 10;  //進入CD時間
  9.    }
  10. }

5.最後成品



二.心得感想

雖然老師目前教的部分不多,但其實真的以目前所教過的東西就可以延伸成一個簡易的小遊戲,不過我認為應該還有更好的方式去縮短程式碼,程式最重要的不是寫得出來樣子,最重要的是要節省不必要的計算、減少計算的負擔



沒有留言:

張貼留言