#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ------------接腳名稱設定--------------
#define lBtn 2 // 左按鈕
#define rBtn 3 // 右按鈕
#define sBtn 4 // 開始按鈕
#define lLed A2 // 左LED
#define rLed A3 // 右LED
#define spk 5 // 蜂鳴器
#define SCREEN_WIDTH 128 // 螢幕寬度(像素)
#define SCREEN_HEIGHT 64 // 螢幕高度(像素)
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// 實體需改成 Adafruit_SH1106 display(-1);
// -------------SSD1306物件宣告---------------
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
//---------------變數宣告----------------------
int x0, y0, x, y, r; // 圓形半徑(r)、位置(左上角x,y)、上一個位置(左上角x0,y0)
int xl0, yl0, xl, yl, w, h; // 矩形長(h)、寬(w)、位置(左上角xl,yl)、上一個位置(左上角xl0,yl0)
int dx, dy, dxl=3; // 圓形移動速度(dx,dy)、矩形移動速度(dxl)
int startMidi[6] = {262, 294, 330, 349, 392, 0}; //C4, D4, E4, F4, G4(Do, Re, Mi, Fa, So)
int endMidi[6] = {392, 349, 330, 294, 262, 0}; //G4, F4, E4, D4, C4
// ------------------初始化---------------------
void game_init() {
display.clearDisplay();
x=SCREEN_WIDTH/2; y=SCREEN_HEIGHT/2; r=3; //讓球置於中間(x,y軸=螢幕高、寬/2)
dx = 2; dy = 1;
display.fillCircle(x, y, r, WHITE); //畫白色圓形
x0 = x; y0 = y; //紀錄目前位置
w = 24;
h = 3;
xl = SCREEN_WIDTH/2 - w/2; // 讓矩形置於中間(x軸=螢幕寬度/2-矩形寬度/2)
yl = SCREEN_HEIGHT - h - 5; //讓矩形距離底部5像素(y軸=螢幕高度-矩形高度-5)
display.fillRect(xl, yl, w, h, WHITE);
xl0 = xl; yl0 = yl;
display.display();
midi_play(startMidi);
}
// -----------------撥放音樂--------------------
void midi_play(int *midi) {
for(int i=0; midi[i]!=0; i++) {
tone(spk, midi[i], 100);
delay(100);
}
}
void setup() {
// put your setup code here, to run once:
// --------------------接腳設定---------------------------
pinMode(lBtn, INPUT_PULLUP);
pinMode(rBtn, INPUT_PULLUP);
pinMode(sBtn, INPUT_PULLUP);
pinMode(lLed, OUTPUT);
pinMode(rLed, OUTPUT);
digitalWrite(lLed, LOW);
digitalWrite(rLed, LOW);
pinMode(spk, OUTPUT);
// 實體用的韓式庫因為沒有回傳值,所以只要保留 display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
// ----------------------啟用ssd1306-------------------
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
while(true);
}
game_init(); // 初始化
}
void loop() {
// put your main code here, to run repeatedly:
delay(50);
display.fillCircle(x0,y0,r,BLACK); // 畫黑色圓形
x += dx; y += dy; // 圓形移動
x0 = x; y0 = y; // 紀錄目前位置
// --------------圓形反彈演算-----------------
if(x>SCREEN_WIDTH-r || x<r){ // 碰到水平邊界反彈
dx = -dx; // x軸轉為負向
}
if(y<r){ // 碰到上邊界反彈
dy = -dy; // y軸轉為負向
}
else if(y>SCREEN_HEIGHT-r){ // 碰到下邊界顯示"You Lose!"
display.clearDisplay(); // 清空畫面
// 設置文字大小、顏色和字體
display.setCursor(0, 0); // 設定文字位置 (x=0, y=0
display.setTextSize(2); // 文字大小(1 是最小)
display.setTextColor(SSD1306_WHITE); // 文字顏色(白色)
display.println("You Lose!");
display.display(); // 更新畫面
midi_play(endMidi); //播放結束音樂
while(1){
if(digitalRead(sBtn) == LOW){
game_init(); //初始化畫面
break;
}
delay(50);
}
}
else if(x>xl-r && x<xl+w+r && y>yl-r){ // 模擬圓碰到矩形後向上反彈(球的邊界陷入矩形,則向上移動)
dy =-2;
tone(5,523,100);
delay(50);
}
display.fillCircle(x,y,r,WHITE); // 畫白色圓形
display.fillRect(xl,yl,w,h,WHITE); // 畫白色矩形
// --------------左按鈕-----------------
if(digitalRead(lBtn) == LOW){
digitalWrite(lLed, HIGH); // 燈亮
xl -= dxl; // 往負向移動
if(xl<0){ // 碰到左側邊緣
xl=0;
}
display.fillRect(xl0, yl0, w, h, BLACK); // 根據上一個位置(xl0,yl0)畫黑色矩形
display.fillRect(xl, yl, w, h, WHITE); // 畫白色矩形
xl0 = xl; yl0 = yl; // 紀錄該矩形位置
}
else {
digitalWrite(lLed, LOW); // 燈暗
}
// -------------右按鈕-----------------
if(digitalRead(rBtn) == LOW){
digitalWrite(rLed, HIGH); // 燈亮
xl += dxl; // 往正向移動
printf(xl);
if(xl>SCREEN_WIDTH-w){ //碰到右側邊緣(目前位置>螢幕寬度-矩形寬度)
xl=SCREEN_WIDTH-w;
}
display.fillRect(xl0, yl0, w, h, BLACK);
display.fillRect(xl, yl, w, h, WHITE);
xl0 = xl; yl0 = yl;
}
else{
digitalWrite(rLed, LOW); // 燈暗
}
display.display(); // 更新畫面(很重要!)
}