Files
HeisserDraht/display.cpp
Jan Remmer Siebels 01e79a4eb2 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>
2026-02-22 00:24:52 +01:00

165 lines
3.8 KiB
C++

#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;
}
}