Initial implementation of HeisserDraht buzz wire game
ESP32-C3 based hot wire game with WS2812B LED effects, SSD1306 OLED display, debounced touch detection, and full game state machine (IDLE → COUNTDOWN → PLAYING → GAME_OVER). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
164
display.cpp
Normal file
164
display.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
#include "display.h"
|
||||
#include "config.h"
|
||||
#include "game_logic.h"
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
|
||||
static Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
|
||||
static unsigned long lastUpdateMs = 0;
|
||||
|
||||
// ── Screens ─────────────────────────────────────────────────────────
|
||||
|
||||
static void screenSplash() {
|
||||
oled.clearDisplay();
|
||||
oled.setTextColor(SSD1306_WHITE);
|
||||
|
||||
oled.setTextSize(2);
|
||||
oled.setCursor(8, 10);
|
||||
oled.print("HEISSER");
|
||||
oled.setCursor(20, 30);
|
||||
oled.print("DRAHT");
|
||||
|
||||
oled.setTextSize(1);
|
||||
oled.setCursor(48, 52);
|
||||
oled.print(VERSION_STR);
|
||||
|
||||
oled.display();
|
||||
}
|
||||
|
||||
static void screenIdle() {
|
||||
oled.clearDisplay();
|
||||
oled.setTextColor(SSD1306_WHITE);
|
||||
|
||||
oled.setTextSize(2);
|
||||
oled.setCursor(8, 5);
|
||||
oled.print("HEISSER");
|
||||
oled.setCursor(20, 23);
|
||||
oled.print("DRAHT");
|
||||
|
||||
// Blinking "Druecke START"
|
||||
if ((millis() / 500) % 2 == 0) {
|
||||
oled.setTextSize(1);
|
||||
oled.setCursor(12, 50);
|
||||
oled.print("Druecke START");
|
||||
}
|
||||
|
||||
oled.display();
|
||||
}
|
||||
|
||||
static void screenCountdown() {
|
||||
GameData& gd = gameGetData();
|
||||
oled.clearDisplay();
|
||||
oled.setTextColor(SSD1306_WHITE);
|
||||
|
||||
if (gd.countdownValue > 0) {
|
||||
oled.setTextSize(4);
|
||||
oled.setCursor(52, 16);
|
||||
oled.print(gd.countdownValue);
|
||||
} else {
|
||||
oled.setTextSize(3);
|
||||
oled.setCursor(36, 20);
|
||||
oled.print("GO!");
|
||||
}
|
||||
|
||||
oled.display();
|
||||
}
|
||||
|
||||
static void screenPlaying() {
|
||||
GameData& gd = gameGetData();
|
||||
oled.clearDisplay();
|
||||
oled.setTextColor(SSD1306_WHITE);
|
||||
|
||||
// Timer MM:SS
|
||||
unsigned long remainMs = 0;
|
||||
unsigned long totalMs = (unsigned long)GAME_DURATION_S * 1000UL;
|
||||
if (gd.elapsedMs < totalMs) remainMs = totalMs - gd.elapsedMs;
|
||||
uint8_t mins = (remainMs / 1000) / 60;
|
||||
uint8_t secs = (remainMs / 1000) % 60;
|
||||
|
||||
oled.setTextSize(1);
|
||||
oled.setCursor(0, 0);
|
||||
oled.print("Zeit: ");
|
||||
if (mins < 10) oled.print('0');
|
||||
oled.print(mins);
|
||||
oled.print(':');
|
||||
if (secs < 10) oled.print('0');
|
||||
oled.print(secs);
|
||||
|
||||
// Strikes
|
||||
oled.setCursor(0, 14);
|
||||
oled.print("Fehler: ");
|
||||
oled.print(gd.strikes);
|
||||
oled.print('/');
|
||||
oled.print(MAX_STRIKES);
|
||||
|
||||
// Score (large)
|
||||
oled.setTextSize(3);
|
||||
oled.setCursor(10, 34);
|
||||
oled.print(gd.score);
|
||||
|
||||
oled.display();
|
||||
}
|
||||
|
||||
static void screenGameOver() {
|
||||
GameData& gd = gameGetData();
|
||||
oled.clearDisplay();
|
||||
oled.setTextColor(SSD1306_WHITE);
|
||||
|
||||
oled.setTextSize(1);
|
||||
oled.setCursor(20, 0);
|
||||
oled.print(gd.won ? "GESCHAFFT!" : "GAME OVER!");
|
||||
|
||||
// Final score
|
||||
oled.setTextSize(2);
|
||||
oled.setCursor(10, 14);
|
||||
oled.print("Score:");
|
||||
oled.print(gd.score);
|
||||
|
||||
// Stats
|
||||
oled.setTextSize(1);
|
||||
unsigned long totalSec = gd.elapsedMs / 1000;
|
||||
oled.setCursor(0, 36);
|
||||
oled.print("Zeit: ");
|
||||
oled.print(totalSec);
|
||||
oled.print("s Fehler: ");
|
||||
oled.print(gd.strikes);
|
||||
|
||||
// Restart hint (blinking)
|
||||
if ((millis() / 600) % 2 == 0) {
|
||||
oled.setCursor(8, 54);
|
||||
oled.print("START = Nochmal");
|
||||
}
|
||||
|
||||
oled.display();
|
||||
}
|
||||
|
||||
// ── Public API ──────────────────────────────────────────────────────
|
||||
|
||||
void displayInit() {
|
||||
Wire.begin(PIN_SDA, PIN_SCL);
|
||||
|
||||
if (!oled.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
|
||||
Serial.println("[OLED] Init FAILED");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("[OLED] Init OK");
|
||||
screenSplash();
|
||||
delay(1500);
|
||||
}
|
||||
|
||||
void displayUpdate() {
|
||||
unsigned long now = millis();
|
||||
if (now - lastUpdateMs < DISPLAY_UPDATE_MS) return;
|
||||
lastUpdateMs = now;
|
||||
|
||||
GameData& gd = gameGetData();
|
||||
switch (gd.state) {
|
||||
case STATE_IDLE: screenIdle(); break;
|
||||
case STATE_COUNTDOWN: screenCountdown(); break;
|
||||
case STATE_PLAYING: screenPlaying(); break;
|
||||
case STATE_GAME_OVER: screenGameOver(); break;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user