遊戲技術相關研究

2017年2月18日 星期六

【Arduino】自己的掌機自己作(2)-打磚塊遊戲

上午1:58 Posted by Channel Chung No comments
   上一篇說到要寫些小遊戲來玩玩,想了一下決定就先從打磚塊遊戲開始,依照維基百科對打磚塊的解釋如下:

打磚塊英語:Breakout clone)是一種電子遊戲。螢幕上部有若幹層磚塊,一個球在螢幕上方的磚塊和牆壁、螢幕下方的移動短板和兩側牆壁之間來回彈,當球碰到磚塊時,球會反彈,而磚塊會消失。玩家要控制螢幕下方的板子,讓「球」透過撞擊消去所有的「磚塊」,球碰到螢幕底邊就會消失,所有的球消失則遊戲失敗。把磚塊全部消去就可以破關。

以上的文字解釋很精闢的說明了打磚塊遊戲的玩法,不過為了讓大家更有印象還有簡單說明一下我們8x8板打磚塊玩法以下再以圖片解釋:
接下來開始進入實作部分,請先開啟Arduino編輯器,然後新增一個專案並命名為Game8x8_Arkanoid然後將上一篇製作的8x8遊戲機開發套件內的檔案添加進來,需要添加的檔案包含如下:
-8x8繪圖庫:Game8x8Graphics.h、 Game8x8Graphics.cpp
-8x8搖桿庫:Game8x8JoyStick.h、Game8x8JoyStick.cpp
-8x8時脈系統:Game8x8Time.h、Game8x8Time.cpp
-8x8蜂鳴器:Game8x8Tone .h、Game8x8Tone.cpp

完成後就開始動手在Game8x8_Arkanoid.ino內添加以下程式:
#include "Game8x8Tone.h"
#include "Game8x8JoyStick.h"
#include "Game8x8Time.h"
#include "Game8x8Graphics.h"

// 繪圖函數.
Game8x8Graphics game8x8Graphics = Game8x8Graphics();
// 搖桿函數.
Game8x8JoyStick game8x8JoyStick = Game8x8JoyStick();
// 蜂鳴器函數.
Game8x8Tone  game8x8Tone = Game8x8Tone();

// 繪圖更新時脈.
Game8x8Time TimeGraphicsUpdate = Game8x8Time();

// 初始.
void setup()
{
 Serial.begin(9600);
}

// 主迴圈.
void loop()
{
 // 繪圖更新時脈-FPS 30.
 if (TimeGraphicsUpdate.update(33)) {
  // 清除畫面.
  game8x8Graphics.clearDisplay(0);

  // 更新.
  game8x8Graphics.update();
        } 
 // 設定1/1000秒.
 delay(1);
}
以上程式碼是通用的遊戲骨架,如果有想要製作其他遊戲的同學可以多多利用,以下是這次主題打磚塊遊戲的所有程式碼與說明:
#include "Game8x8Tone.h"
/*打磚塊遊戲.*/
#include "Game8x8Tone.h"
#include "Game8x8JoyStick.h"
#include "Game8x8Time.h"
#include "Game8x8Graphics.h"

// 繪圖函數.
Game8x8Graphics game8x8Graphics = Game8x8Graphics();
// 搖桿函數.
Game8x8JoyStick game8x8JoyStick = Game8x8JoyStick();
// 蜂鳴器函數.
Game8x8Tone  game8x8Tone = Game8x8Tone();

// 繪圖更新時脈.
Game8x8Time TimeGraphicsUpdate = Game8x8Time();
// 移動版子更新時脈.
Game8x8Time TimeMovePaddle = Game8x8Time();
// 移動球更新時脈.
Game8x8Time TimeMoveBall = Game8x8Time();

// 磚塊.
byte brick[8][8] = {
 { 0,0,0,0,0,0,0,0 },
 { 0,1,1,1,1,1,1,0 },
 { 0,1,1,1,1,1,1,0 },
 { 0,1,1,1,1,1,1,0 },
 { 0,0,0,0,0,0,0,0 },
 { 0,0,0,0,0,0,0,0 },
 { 0,0,0,0,0,0,0,0 },
 { 0,0,0,0,0,0,0,0 },
};
// 磚塊數量.
byte brickMax = 18;

// 球初始位置.
int x = 3;
int y = 6;
// 移動像素.
int dx = 1;
int dy = 1;

// 版子.
int  paddleBegin = 2;
int  paddleEnd = 4;

// 遊戲狀態.
// 0:發球中.
// 1:遊戲中.
byte gameStatus = 0;

// 音效開關.
bool soundSwitch = true;
 
// 初始.
void setup()
{
 Serial.begin(9600);
}

// 主迴圈.
void loop()
{ 
 // *移動球更新時脈.
 if (TimeMoveBall.update(140) && gameStatus == 1) {
  // 判斷球碰磚塊.
  if (brick[y][x] == 1) {
   brick[y][x] = 2;
   brickMax--;
   // 播放音效.
   if (soundSwitch) {
    // 發出聲音.
    game8x8Tone.playTone(262, 33);
   }
   // 重新開始遊戲.
   if (brickMax == 0) {
    resetGame();
    return;
   }
   dy = -dy;    // 反彈
  }

  // 處理球移動.
  if (x + dx > 7 || x + dx < 0) {
   dx = -dx;
  }
  if (y + dy < 0) {
   dy = -dy;
  }
  else if (y + dy > 7) {
   // 判斷碰到底板反彈.
   if (x >= paddleBegin && x <= paddleEnd) {
    // 播放音效.
    if (soundSwitch) {
     // 發出聲音.
     game8x8Tone.playTone(494, 33);
    }
    // 碰左角.
    if (x == paddleBegin) {
     x--;
    }
    // 碰右角.
    else if (x == paddleEnd) {
     x++;
    }
    dy = -dy;
   }
   // 沒碰到底板.
   else 
   {
    // 暫停遊戲.
    gameStatus = 0;

    // 球初始位置.
    x = 3;y = 6;
    // 版子.
    paddleBegin = 2;
    paddleEnd = 4;
    return;
   }
  }
  x += dx;
  y += dy;
 }

 // *移動版子更新時脈.
 if (TimeMovePaddle.update(80)) {
  // 移動版子.
  int mx = game8x8JoyStick.getJoyX();
  if (mx != 5) {
   // 版子右移.
   if (mx < 5) {
    paddleBegin++; paddleEnd++;
    if (paddleBegin >= 5) { paddleBegin = 5; }
    if (paddleEnd >= 7) { paddleEnd= 7; }
   }
   // 版子左移.
   else
   {
    paddleBegin--; paddleEnd--;
    if (paddleBegin <= 0) { paddleBegin = 0; }
    if (paddleEnd <= 2) { paddleEnd = 2; }
   }
  }
 }

 // *發球中.
 if (gameStatus == 0) {
  // 搖桿往上發球.
  if (game8x8JoyStick.getJoyY() > 5) {
   dx = 1;
   dy = 1;
   gameStatus = 1;
  }else{
   // 讓球跟著版子跑.
   x = paddleBegin + 1;
  }
 }

 // 繪圖更新時脈-FPS 30.
 if (TimeGraphicsUpdate.update(33)) {

  // 清除畫面.
  game8x8Graphics.clearDisplay(0);

  // 畫磚塊.
  for (int y = 0; y<8; y++) {
   for (int x = 0; x<8; x++) {
    if (brick[y][x] == 1) {
     game8x8Graphics.setPixcls(x, y, 1);
    }
    else {
     game8x8Graphics.setPixcls(x, y, 0);
    }
   }
  }

  // 移動球.
  game8x8Graphics.setPixcls(x, y, 1);

  // 畫版子.
  for (byte i = paddleBegin; i <= paddleEnd; i++) {
   game8x8Graphics.setPixcls(i, 7, 1);
  }

  // 更新.
  game8x8Graphics.update();
 }

 // 設定1/1000秒.
 delay(1);
}

// 重新開始遊戲.
void resetGame()
{
 // 暫停遊戲.
 gameStatus = 0;

 // 球初始位置.
 x = 3; y = 6;

 // 版子.
 paddleBegin = 2;
 paddleEnd = 4;

 // 初始磚塊.
 for (int y = 0; y<8; y++) {
  for (int x = 0; x<8; x++) {
   if (brick[y][x] == 2) {
    brick[y][x] = 1;
   }
  }
 }
 // 磚塊數量.
 brickMax = 18;
}
完成後就可以將程式上傳至Arduino Uno板子看看執行結果,如果程式運行沒有出錯的話因該可以看到以下畫面:


將搖桿往上推可以發球,清光畫面上的所有磚塊後會自動重新開始遊戲,下面是實際遊玩影片:
 
這樣就完成了我們8x8遊戲機的第一個遊戲了,第二個遊戲還在構思中希望很快的能夠實作出來,先這樣那砸們就下次見囉。

PS:掌機接線方式請參考【Arduino】自己的掌機自己作(1)-線路圖與開發套件

點我到GitHub下載範例程式

0 意見:

張貼留言