-
Notifications
You must be signed in to change notification settings - Fork 0
/
arduinoFlappyBirds.ino
295 lines (260 loc) · 7.85 KB
/
arduinoFlappyBirds.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#include <Wire.h>
#include <LiquidCrystal.h>
// #include <LiquidCrystal_I2C.h>
// LiquidCrystal_I2C lcd(0x27, 16, 2);
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // Initialize the LCD display
#define buttonPin 8 // Define the button pin, tells the arduino what pin the button is connected to
// The pipe object is defined as an array of bytes.
// It represents a custom character that will be displayed on an LCD screen.
// The pipe array is initialized with 8 elements, each representing a row of the character.
// Each row is defined using a binary number that represents the pattern of pixels in that row.
// The binary numbers are written in the form of 0bXXXXXXXX, where each X represents a pixel.
// For example, the first row of the pipe character is defined as 0b11111, which means that all 5 pixels in that row are turned on.
// The second row is also 0b11111, indicating that all 5 pixels in that row are turned on as well.
// The following rows have a similar pattern, forming the shape of a pipe.
// By defining the pipe character in this way, it can be easily displayed on the LCD screen by sending the corresponding byte values to the LCD library.
// The LCD library will interpret these byte values and display the custom character accordingly.
byte pipe[8] = { // Define the pipe obstacle
0b00000,
0b11111,
0b11111,
0b01110,
0b01110,
0b01110,
0b01110,
0b01110};
byte pipeTop[8] = {
0b01110,
0b01110,
0b01110,
0b01110,
0b01110,
0b11111,
0b11111,
0b00000};
byte bird[8] = { // Define the bird character
0b00000,
0b00110,
0b10111,
0b11110,
0b11110,
0b01100,
0b00000,
0b00000};
byte birdAnim[8] = { // Bird animation/shifted y -2
0b00000,
0b00000,
0b00110,
0b10111,
0b11110,
0b11110,
0b01100,
0b01000};
byte hit[8] = { // Define the hit marker
0b10001,
0b11011,
0b01010,
0b00100,
0b00100,
0b01010,
0b11011,
0b10001};
byte heart[8] = { // Define the heart symbol
0b00000,
0b01010,
0b11111,
0b11111,
0b11111,
0b01110,
0b00100,
0b00100};
byte coin[8] = { // Define the coin symbol
0b00000,
0b01110,
0b11011,
0b11111,
0b11011,
0b11011,
0b01110,
0b00000};
int pipes[16]; // Array to store the pipe positions
int topPipes[16] = {0}; // Array to store the Top pipe positions
int coins[16] = {0}; // Array to store the coin positions
int birdY = 2; // Initial bird position on the Y-axis
int birdX = 7; // Initial bird position on the X-axis
int score = 0; // Current score
int speed = 600; // Speed of pipes
int life = 3; // Number of lives
void setup()
{
// lcd.backlight(); only needed for I2C use
Serial.begin(9600); // Start the serial communication, used for debugging,
// not needed for the game,
// but can be useful to see the score in the serial monitor
lcd.begin(16, 2); // Initialize the LCD display with 16 columns and 2 rows
lcd.createChar(0, pipe); // Create the pipe character
lcd.createChar(1, bird); // Create the bird character
lcd.createChar(2, hit); // Create the hit character
lcd.createChar(3, heart); // Create the heart character
lcd.createChar(4, birdAnim); // Create the bird animation character
lcd.createChar(5, pipeTop); // Create the Top pipe character
lcd.createChar(6, coin); // Create the coin character
pinMode(buttonPin, INPUT_PULLUP); // Set the button pin as an input and enable the internal pull-up resistor
}
void birdfly()
{
int buttonValue = digitalRead(buttonPin); // Read the button value
int charId = 0;
if (buttonValue == LOW)
{ // If the button is pressed
birdY = 0; // Move the bird up
charId = 1; // Set the character ID to display the bird
}
else
{
birdY = 1; // Move the bird down
charId = 1; // Set the character ID to display the bird
}
if (birdY == 0)
{
lcd.setCursor(birdX, birdY);
lcd.write(1); // Display the bird
}
else
{
lcd.setCursor(birdX, birdY);
lcd.print(' '); // Clear the previous bird position
birdY = 1;
lcd.setCursor(birdX, birdY);
lcd.write(1); // Display the bird
}
}
void checkCollision()
{
if ((pipes[birdX] == 1 && birdY != 0) || (topPipes[birdX] == 1 && birdY == 0))
{ // if the bird has hit a pipe,
// either a regular one when it's not at the bottom,
// or a top one when it is at the bottom.
lcd.setCursor(birdX, birdY);
lcd.write(2); // Display the hit marker
life--; // Decrease the number of lives
score -= 5; // Decrease the score by 5
}
else if (coins[birdX] == 1)
{ // If the bird hits a coin
lcd.setCursor(birdX, birdY);
lcd.write(1); // Display the bird
coins[birdX] = 0; // Remove the coin
score += 5; // Increase the score by 2
}
}
void movePipes()
{
// Move the pipes, top pipes, and coins to the left
for (int i = 1; i < 16; i++)
{
pipes[i - 1] = pipes[i];
topPipes[i - 1] = topPipes[i];
coins[i - 1] = coins[i];
}
// Generate new pipes, top pipes, and possibly a coin at the right side of the screen
// Ensure there is at least one space between the regular and top pipes
if (pipes[14] == 0 && topPipes[14] == 0)
{
if(random(2) == 0) {
pipes[15] = random(0, 2); // 50% chance to generate a regular pipe
topPipes[15] = 0;
} else {
topPipes[15] = random(0, 2); // 50% chance to generate a top pipe
pipes[15] = 0;
}
// Generate a coin only if there is no pipe or top pipe at the same position
if(pipes[15] == 0 && topPipes[15] == 0) {
coins[15] = random(0, 2); // 50% chance to generate a coin
} else {
coins[15] = 0;
}
}
else
{
pipes[15] = 0;
topPipes[15] = 0;
coins[15] = 0;
}
// Draw the pipes, top pipes, and coins
for (int i = 0; i < 16; i++)
{
lcd.setCursor(i, 0);
if (topPipes[i] == 1) {
lcd.write((byte)5); // Display the top pipe
} else if (coins[i] == 1) {
lcd.write((byte)6); // Display the coin
} else {
lcd.write(' '); // No top pipe or coin
}
lcd.setCursor(i, 1);
if (pipes[i] == 1) {
lcd.write((byte)0); // Display the pipe
} else {
lcd.write(' '); // No pipe
}
}
}
void showLives()
{
int i;
for (i = 0; i < life; i++)
{
lcd.setCursor(i, 0); // Set the cursor position on the LCD display
lcd.write((byte)3); // Display the heart character
}
}
void showScore()
{
lcd.setCursor(3, 0); // Set the cursor position on the LCD display
lcd.print(score); // Display the score
}
bool gameStarted = false;
void loop()
{
lcd.clear(); // Clear the LCD display
if (!gameStarted)
{
// Display the start screen
lcd.setCursor(1, 0);
lcd.write(4); // Display the bird
delay(300); // in milliseconds
lcd.setCursor(3, 0); // Set the cursor position on the LCD display
lcd.print("Flappy Bird"); // Display "Flappy Bird"
lcd.setCursor(0, 1); // Set the cursor position on the LCD display
lcd.print("Press the button"); // Display "Press the button"
lcd.setCursor(1, 0);
lcd.write(1); // Display the bird animation
delay(100);
// Check if the button is pressed
if (digitalRead(buttonPin) == LOW)
{
// If the button is pressed, start the game
gameStarted = true;
}
}
else if (life > 0)
{ // If there are lives remaining
movePipes();
birdfly();
showLives();
showScore();
checkCollision();
score++;
speed--; // Decrease the speed level
}
else
{
lcd.setCursor(3, 0); // Set the cursor position on the LCD display
lcd.print("GAME OVER");
lcd.setCursor(3, 1); // Set the cursor position on the LCD display
lcd.print("Score: ");
lcd.print(score); // Display the final score
}
delay(speed); // Delay for the specified speed level
}