#include #include #include // OLED U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2( U8G2_R0, U8X8_PIN_NONE ); // Touch pins #define PIN_LEFT D1 #define PIN_RIGHT D7 #define PIN_DOWN D8 #define PIN_UP D0 #define PIN_FIRE D9 #define N_TOUCH 5 #define THRESHOLD 6 enum TouchIndex { T_LEFT = 0, T_RIGHT, T_DOWN, T_UP, T_FIRE }; const uint8_t touchPins[N_TOUCH] = { PIN_LEFT, PIN_RIGHT, PIN_DOWN, PIN_UP, PIN_FIRE }; bool touchedNow[N_TOUCH] = { false, false, false, false, false }; bool touchedBefore[N_TOUCH] = { false, false, false, false, false }; // Screen const int SCREEN_W = 128; const int SCREEN_H = 64; // Player const int PLAYER_W = 14; const int PLAYER_H = 9; int playerX = 15; int playerY = 28; // Player pixel art const char playerShip[PLAYER_H][PLAYER_W + 1] = { "..##..........", ".####.........", "######........", "##.#####......", "###########...", "##.#####......", "######........", ".####.........", "..##.........." }; // Bullets struct Bullet { int x; int y; bool active; }; const int MAX_BULLETS = 8; Bullet bullets[MAX_BULLETS]; unsigned long lastBulletUpdate = 0; const unsigned long BULLET_INTERVAL = 25; // Update touch void updateTouch() { const int maxCount = 200; for (int i = 0; i < N_TOUCH; i++) { touchedBefore[i] = touchedNow[i]; pinMode(touchPins[i], OUTPUT); digitalWrite(touchPins[i], LOW); delayMicroseconds(25); pinMode(touchPins[i], INPUT_PULLUP); int count = 0; while ( digitalRead(touchPins[i]) == LOW && count < maxCount ) { count++; } touchedNow[i] = count > THRESHOLD; } } // Touch held bool touchHeld(int index) { return touchedNow[index]; } // Touch pressed bool touchPressed(int index) { return touchedNow[index] && !touchedBefore[index]; } // Update player void updatePlayer() { if (touchHeld(T_LEFT)) { playerX -= 2; } if (touchHeld(T_RIGHT)) { playerX += 2; } if (touchHeld(T_UP)) { playerY -= 2; } if (touchHeld(T_DOWN)) { playerY += 2; } playerX = constrain( playerX, 1, SCREEN_W - PLAYER_W - 1 ); playerY = constrain( playerY, 1, SCREEN_H - PLAYER_H - 1 ); } // Fire bullet void fireBullet() { for (int i = 0; i < MAX_BULLETS; i++) { if (!bullets[i].active) { bullets[i].active = true; bullets[i].x = playerX + PLAYER_W; bullets[i].y = playerY + PLAYER_H / 2; return; } } } // Update bullets void updateBullets() { if ( millis() - lastBulletUpdate < BULLET_INTERVAL ) { return; } lastBulletUpdate = millis(); for (int i = 0; i < MAX_BULLETS; i++) { if (!bullets[i].active) { continue; } bullets[i].x += 4; if (bullets[i].x > 127) { bullets[i].active = false; } } } // Draw player void drawPlayerShip( int xPos, int yPos ) { for (int y = 0; y < PLAYER_H; y++) { for (int x = 0; x < PLAYER_W; x++) { if (playerShip[y][x] == '#') { u8g2.drawPixel( xPos + x, yPos + y ); } } } // Engine flame if ((millis() / 80) % 2 == 0) { u8g2.drawPixel( xPos - 1, yPos + 4 ); u8g2.drawPixel( xPos - 2, yPos + 4 ); } } // Draw bullets void drawBullets() { for (int i = 0; i < MAX_BULLETS; i++) { if (!bullets[i].active) { continue; } u8g2.drawLine( bullets[i].x, bullets[i].y, bullets[i].x + 4, bullets[i].y ); u8g2.drawPixel( bullets[i].x + 2, bullets[i].y - 1 ); } } // Draw game void drawGame() { u8g2.clearBuffer(); // Stars u8g2.drawPixel(20, 12); u8g2.drawPixel(40, 48); u8g2.drawPixel(61, 22); u8g2.drawPixel(78, 52); u8g2.drawPixel(91, 16); u8g2.drawPixel(110, 39); drawPlayerShip( playerX, playerY ); drawBullets(); u8g2.sendBuffer(); } // Setup void setup() { Serial.begin(115200); Wire.begin(); u8g2.begin(); for (int i = 0; i < MAX_BULLETS; i++) { bullets[i].active = false; } } // Loop void loop() { updateTouch(); updatePlayer(); // Fire once per tap if (touchPressed(T_FIRE)) { fireBullet(); } updateBullets(); drawGame(); delay(25); }