#include <GyverOLED.h>
GyverOLED<SSD1306_128x64, OLED_NO_BUFFER> oled; // 使用無緩衝模式
// 按鈕腳位
int buttonPin1 = 10; // 按鈕1腳位 (A玩家)
int buttonPin2 = 11; // 按鈕2腳位 (B玩家)
bool rolling = false; // 用來判斷骰子是否正在滾動
unsigned long startTime = 0; // 滾動開始的時間
const int rollDuration = 5000; // 滾動時間 (5 秒)
int previousDiceLeft = 0; // 用來追踪左側顯示的骰子數字
int previousDiceRight = 0; // 用來追踪右側顯示的骰子數字
int playerAScore = 0; // A玩家的點數
int playerBScore = 0; // B玩家的點數
bool playerATurn = true; // 判斷是否為A玩家的回合
// 定義骰子點的位置 (x, y)
int dotPositions[7][2] = {
{20, 16}, // 0: 左上
{36, 16}, // 1: 上中
{52, 16}, // 2: 右上
{36, 32}, // 3: 中間
{20, 48}, // 4: 左下
{36, 48}, // 5: 下中
{52, 48} // 6: 右下
};
// 右側骰子的位置
int dotPositionsRight[7][2] = {
{80, 16}, // 0: 右上
{96, 16}, // 1: 右中
{112, 16}, // 2: 右下
{96, 32}, // 3: 右中
{80, 48}, // 4: 右上
{96, 48}, // 5: 右中
{112, 48} // 6: 右下
};
void setup() {
Serial.begin(9600); // 初始化 Serial 通訊
oled.init(); // 初始化 OLED
oled.clear(); // 清除顯示
pinMode(buttonPin1, INPUT_PULLUP); // 設定按鈕1腳位並啟用內建上拉電阻
pinMode(buttonPin2, INPUT_PULLUP); // 設定按鈕2腳位並啟用內建上拉電阻
randomSeed(analogRead(0)); // 使用未連接的類比腳位作為隨機種子
// 顯示初始畫面
oled.setCursor(0, 0);
oled.setScale(2);
oled.print("Dice Battle");
oled.setCursor(0, 2);
oled.println(" PLAYER_A");
oled.println(" PK ");
oled.print(" PLAYER_B");
oled.update();
delay(5000); // 顯示5秒
showPushButton1(); // 顯示 "PUSH Button1"
}
void loop() {
if ((digitalRead(buttonPin1) == LOW && playerATurn) || (digitalRead(buttonPin2) == LOW && !playerATurn)) {
rolling = true; // 設置骰子滾動
startTime = millis(); // 紀錄開始時間
previousDiceLeft = 0; // 重置前一次顯示的左側骰子數字
previousDiceRight = 0; // 重置前一次顯示的右側骰子數字
oled.clear(); // 清空 OLED 畫面
drawAllDots(previousDiceLeft, false, true); // 初始化左側顯示為空心圓
drawAllDots(previousDiceRight, false, false); // 初始化右側顯示為空心圓
}
if (rolling) {
unsigned long elapsedTime = millis() - startTime; // 計算已經過的時間
// 持續滾動,快速顯示隨機點數
if (elapsedTime < rollDuration) {
int diceNumberLeft = random(1, 7); // 生成 1 到 6 的隨機數
int diceNumberRight = random(1, 7); // 生成 1 到 6 的隨機數
// 只在隨機數變更時更新顯示
if (diceNumberLeft != previousDiceLeft || diceNumberRight != previousDiceRight) {
drawAllDots(previousDiceLeft, false, true); // 將左側的前一次的點數畫成空心
drawAllDots(previousDiceRight, false, false); // 將右側的前一次的點數畫成空心
showDice(diceNumberLeft, true); // 顯示左側的骰子 OLED
showDice(diceNumberRight, false); // 顯示右側的骰子 OLED
previousDiceLeft = diceNumberLeft; // 更新左側的前一次顯示的骰子數字
previousDiceRight = diceNumberRight; // 更新右側的前一次顯示的骰子數字
Serial.print("Rolling: "); // 在 Serial Port 輸出 "Rolling: "
Serial.print("Left: "); // 輸出左側的骰子數字
Serial.print(diceNumberLeft); // 輸出左側的骰子數字
Serial.print(" | Right: "); // 輸出右側的骰子數字
Serial.println(diceNumberRight); // 輸出右側的骰子數字
}
delay(200); // 每 200 毫秒變換一次點數
} else {
// 5 秒後,骰子停止
rolling = false; // 停止滾動
int finalNumberLeft = random(1, 7); // 最後左側顯示的隨機數
int finalNumberRight = random(1, 7); // 最後右側顯示的隨機數
drawAllDots(previousDiceLeft, false, true); // 將左側最後一次的數字畫成空心
drawAllDots(previousDiceRight, false, false); // 將右側最後一次的數字畫成空心
showDice(finalNumberLeft, true); // 顯示最終左側點數
showDice(finalNumberRight, false); // 顯示最終右側點數
Serial.print("Final result: "); // 在 Serial Port 輸出 "Final result: "
Serial.print("Left: "); // 輸出左側的最終點數
Serial.print(finalNumberLeft); // 輸出左側的最終點數
Serial.print(" | Right: "); // 輸出右側的最終點數
Serial.println(finalNumberRight); // 輸出右側的最終點數
if (playerATurn) {
playerAScore = finalNumberLeft + finalNumberRight; // 記錄A玩家的點數
playerATurn = false; // 換到B玩家
showPushButton2(); // 顯示 "push button2"
} else {
playerBScore = finalNumberLeft + finalNumberRight; // 記錄B玩家的點數
showResult(); // 顯示比賽結果
delay(5000); // 顯示5秒
resetGame(); // 重置遊戲
}
}
}
}
// 根據點數在 OLED 上顯示點
void showDice(int number, bool isLeft) {
// 根據骰子的數字在 OLED 上繪製點
switch (number) {
case 1:
if (isLeft) {
drawDot(3, true); // 左側中間實心
} else {
drawDotRight(3, true); // 右側中間實心
}
break;
case 2:
if (isLeft) {
drawDot(0, true); // 左上實心
drawDot(6, true); // 左下實心
} else {
drawDotRight(0, true); // 右上實心
drawDotRight(6, true); // 右下實心
}
break;
case 3:
if (isLeft) {
drawDot(0, true); // 左上實心
drawDot(3, true); // 左中間實心
drawDot(6, true); // 左下實心
} else {
drawDotRight(0, true); // 右上實心
drawDotRight(3, true); // 右中間實心
drawDotRight(6, true); // 右下實心
}
break;
case 4:
if (isLeft) {
drawDot(0, true); // 左上實心
drawDot(2, true); // 左上右實心
drawDot(4, true); // 左下左實心
drawDot(6, true); // 左下實心
} else {
drawDotRight(0, true); // 右上實心
drawDotRight(2, true); // 右上右實心
drawDotRight(4, true); // 右下左實心
drawDotRight(6, true); // 右下實心
}
break;
case 5:
if (isLeft) {
drawDot(0, true); // 左上實心
drawDot(2, true); // 左上右實心
drawDot(3, true); // 左中間實心
drawDot(4, true); // 左下左實心
drawDot(6, true); // 左下實心
} else {
drawDotRight(0, true); // 右上實心
drawDotRight(2, true); // 右上右實心
drawDotRight(3, true); // 右中間實心
drawDotRight(4, true); // 右下左實心
drawDotRight(6, true); // 右下實心
}
break;
case 6:
if (isLeft) {
drawDot(0, true); // 左上實心
drawDot(2, true); // 左上右實心
drawDot(4, true); // 左下左實心
drawDot(6, true); // 左下實心
drawDot(5, true); // 左下右實心
} else {
drawDotRight(0, true); // 右上實心
drawDotRight(2, true); // 右上右實心
drawDotRight(4, true); // 右下左實心
drawDotRight(6, true); // 右下實心
drawDotRight(5, true); // 右下右實心
}
break;
}
}
// 繪製 OLED 上的實心或空心圓
void drawDot(int index, bool filled) {
if (filled) {
oled.circle(dotPositions[index][0], dotPositions[index][1], 5, OLED_FILL); // 繪製實心圓
} else {
oled.circle(dotPositions[index][0], dotPositions[index][1], 5, OLED_STROKE); // 繪製空心圓
}
}
// 繪製右側 OLED 上的實心或空心圓
void drawDotRight(int index, bool filled) {
if (filled) {
oled.circle(dotPositionsRight[index][0], dotPositionsRight[index][1], 5, OLED_FILL); // 繪製實心圓
} else {
oled.circle(dotPositionsRight[index][0], dotPositionsRight[index][1], 5, OLED_STROKE); // 繪製空心圓
}
}
// 繪製所有點
void drawAllDots(int number, bool filled, bool isLeft) {
for (int i = 0; i < 7; i++) {
if (isLeft) {
drawDot(i, filled); // 左側的點
} else {
drawDotRight(i, filled); // 右側的點
}
}
}
// 顯示 "push button1"
void showPushButton1() {
oled.clear();
oled.setCursor(0, 3);
oled.print(" Push BT1");
oled.update();
}
// 顯示 "push button2"
void showPushButton2() {
oled.clear();
oled.setCursor(0, 3);
oled.print(" Push BT2");
oled.update();
}
// 顯示比賽結果
void showResult() {
oled.clear();
oled.setScale(1);
oled.setCursor(0, 0);
oled.print("RESULT:");
oled.setCursor(0, 2);
oled.print("PLAYER_A:");
oled.print(playerAScore);
oled.setCursor(0, 4);
oled.print("PLAYER_B:");
oled.print(playerBScore);
oled.setCursor(0, 6);
if (playerAScore > playerBScore) {
oled.print("WINNER:PLAYER_A");
} else if (playerAScore < playerBScore) {
oled.print("WINNER:PLAYER_B");
} else {
oled.print("DRAW");
}
oled.update();
}
// 重置遊戲
void resetGame() {
playerAScore = 0;
playerBScore = 0;
playerATurn = true;
oled.clear();
oled.setCursor(0, 0);
oled.setScale(2);
oled.print("Dice Battle");
oled.setCursor(0, 2);
oled.println(" PLAYER_A");
oled.println(" PK ");
oled.print(" PLAYER_B");
oled.update();
delay(8000); // 顯示5秒
showPushButton1(); // 顯示 "push button1"
}