1#include <Wire.h>
2#include <Adafruit_GFX.h>
3#include <Adafruit_SSD1306.h>
4
5#define SCREEN_WIDTH 128
6#define SCREEN_HEIGHT 64
7Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
8
9// === Bird ===
10int birdX = 20;
11int birdY = 30;
12int birdR = 3;
13int velY = 0;
14int gravity = 1;
15int flapPower = -3;
16
17// === Pipe ===
18int pipeX = SCREEN_WIDTH;
19int pipeW = 15;
20int gapY = 20;
21int gapH = 25;
22
23// === Game Control ===
24#define BUTTON 2
25#define BUZZER 3
26bool buttonPressed = false;
27bool gameOver = false;
28bool gameStarted = false;
29long score = 0;
30long highScore = 0;
31int speed = 2;
32
33void setup() {
34 pinMode(BUTTON, INPUT_PULLUP);
35 pinMode(BUZZER, OUTPUT);
36
37 if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
38 for (;;);
39 }
40
41 display.clearDisplay();
42 showSplashScreen();
43 playIntroMusic();
44}
45
46void loop() {
47 if (!gameStarted) {
48 if (digitalRead(BUTTON) == LOW) {
49 resetGame();
50 gameStarted = true;
51 noTone(BUZZER);
52 delay(200);
53 }
54 return;
55 }
56
57 if (!gameOver) {
58 // === Input Tombol Flap (satu kali per tekan) ===
59 if (digitalRead(BUTTON) == LOW && !buttonPressed) {
60 velY = flapPower;
61 buttonPressed = true;
62 tone(BUZZER, 800, 100); // bunyi flap
63 } else if (digitalRead(BUTTON) == HIGH) {
64 buttonPressed = false;
65 }
66
67 // === Update Bird ===
68 birdY += velY;
69 velY += gravity;
70 if (birdY < 0) birdY = 0;
71 if (birdY > SCREEN_HEIGHT - birdR * 2) {
72 birdY = SCREEN_HEIGHT - birdR * 2;
73 gameOver = true;
74 playGameOverMusic();
75 }
76
77 // === Update Pipe ===
78 pipeX -= speed;
79 if (pipeX < -pipeW) {
80 pipeX = SCREEN_WIDTH;
81 gapY = random(10, SCREEN_HEIGHT - gapH - 10);
82 score++;
83
84 // Setiap 10 skor -> tambah kecepatan & bunyi spesial
85 if (score % 10 == 0) {
86 speed++;
87 playScoreMilestoneSound();
88 }
89 }
90
91 // === Deteksi Tabrakan ===
92 if ((birdX + birdR > pipeX && birdX - birdR < pipeX + pipeW) &&
93 (birdY < gapY || birdY + birdR * 2 > gapY + gapH)) {
94 gameOver = true;
95 playGameOverMusic();
96 }
97
98 // === Gambar Layar ===
99 display.clearDisplay();
100 display.fillCircle(birdX, birdY, birdR, SSD1306_WHITE);
101 display.fillRect(pipeX, 0, pipeW, gapY, SSD1306_WHITE);
102 display.fillRect(pipeX, gapY + gapH, pipeW, SCREEN_HEIGHT - (gapY + gapH), SSD1306_WHITE);
103
104 display.setTextSize(1);
105 display.setTextColor(SSD1306_WHITE);
106 display.setCursor(35, 0);
107 display.print("Score: ");
108 display.print(score);
109
110 display.display();
111 delay(20);
112
113 } else {
114 if (score > highScore) highScore = score;
115
116 display.clearDisplay();
117 display.setTextSize(2);
118 display.setTextColor(SSD1306_WHITE);
119 display.setCursor(15, 10);
120 display.println("GAME OVER");
121
122 display.setTextSize(1);
123 display.setCursor(25, 35);
124 display.print("Score: ");
125 display.print(score);
126
127 display.setCursor(25, 50);
128 display.print("High: ");
129 display.print(highScore);
130
131 display.display();
132
133 delay(3000);
134
135 showSplashScreen();
136 playIntroMusic();
137 gameStarted = false;
138 }
139}
140
141// === Fungsi Tambahan ===
142void resetGame() {
143 birdY = 30;
144 velY = 0;
145 pipeX = SCREEN_WIDTH;
146 gapY = 20;
147 score = 0;
148 speed = 2;
149 gameOver = false;
150}
151
152void showSplashScreen() {
153 display.clearDisplay();
154 display.setTextSize(2);
155 display.setTextColor(SSD1306_WHITE);
156 display.setCursor(30, 0);
157 display.println("FLAPPY");
158 display.setCursor(35, 20);
159 display.println("BIRD");
160
161 display.setTextSize(1);
162 display.setCursor(25, 45);
163 display.print("High: ");
164 display.print(highScore);
165
166 display.setTextSize(1);
167 display.setCursor(25, 55);
168 display.println("Press Button");
169
170 display.display();
171}
172
173// === Lagu Intro (versi lama yang kamu suka) ===
174void playIntroMusic() {
175 tone(BUZZER, 262, 150);
176 delay(150);
177 tone(BUZZER, 330, 150);
178 delay(150);
179 tone(BUZZER, 392, 150);
180 delay(150);
181 tone(BUZZER, 523, 300);
182 delay(300);
183 noTone(BUZZER);
184}
185
186// === Lagu Game Over Baru (lebih menarik) ===
187void playGameOverMusic() {
188 int melody[] = {494, 392, 330, 262, 330, 294}; // nada turun lalu naik dikit
189 int duration[] = {200, 200, 200, 300, 150, 400};
190 for (int i = 0; i < 6; i++) {
191 tone(BUZZER, melody[i], duration[i]);
192 delay(duration[i] * 1.3);
193 }
194 noTone(BUZZER);
195}
196
197// === Suara Skor Kelipatan 10 ===
198void playScoreMilestoneSound() {
199 int melody[] = {523, 659, 784};
200 int duration[] = {100, 100, 200};
201 for (int i = 0; i < 3; i++) {
202 tone(BUZZER, melody[i], duration[i]);
203 delay(duration[i] * 1.3);
204 }
205 noTone(BUZZER);