Загрузка данных


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// --- ПИНЫ ---
#define JOY_X A0
#define JUMP_BTN 2
#define BUZZER 8

// --- ИГРОК ---
struct Player {
  float x, y;
  float vx, vy;
  int w, h;
  bool onGround;
  bool alive;
};
Player player;

// --- ПЛАТФОРМЫ ---
struct Platform {
  int x, y, w;
};
const int NUM_PLATFORMS = 8;
Platform platforms[NUM_PLATFORMS];

// --- ФИЗИКА ---
const float GRAVITY = 0.4;
const float JUMP_FORCE = -6.0;
const float MOVE_SPEED = 2.0;
const float FRICTION = 0.85;

// --- СОСТОЯНИЯ ---
enum GameState { STATE_PLAYING, STATE_DEAD, STATE_WIN };
GameState currentState = STATE_PLAYING;

// --- ТАЙМЕРЫ ---
unsigned long lastUpdate = 0;
int lastJumpState = HIGH;
int currentLevel = 0;

void setup() {
  Serial.begin(9600);
  pinMode(JUMP_BTN, INPUT_PULLUP);
  pinMode(BUZZER, OUTPUT);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println(F("PLATFORMER v1.0"));
  display.println(F("Joystick + Jump"));
  display.display();
  delay(2000);

  loadLevel(0);
}

void loop() {
  if (millis() - lastUpdate < 16) return;
  lastUpdate = millis();

  switch (currentState) {
    case STATE_PLAYING:
      handleInput();
      updatePhysics();
      checkCollisions();
      checkWinCondition();
      render();
      break;
    case STATE_DEAD:
      display.clearDisplay();
      display.setCursor(25, 25);
      display.setTextSize(2);
      display.print(F("GAME OVER"));
      display.display();
      delay(2000);
      loadLevel(currentLevel);
      break;
    case STATE_WIN:
      display.clearDisplay();
      display.setCursor(30, 25);
      display.setTextSize(2);
      display.print(F("YOU WIN!"));
      display.display();
      delay(2000);
      currentLevel++;
      if (currentLevel >= 3) currentLevel = 0;
      loadLevel(currentLevel);
      break;
  }
}

void loadLevel(int level) {
  currentState = STATE_PLAYING;
  player.x = 10;
  player.y = 40;
  player.vx = 0;
  player.vy = 0;
  player.w = 6;
  player.h = 8;
  player.onGround = false;
  player.alive = true;

  // Сброс платформ
  for (int i = 0; i < NUM_PLATFORMS; i++) platforms[i] = {0, 0, 0};

  if (level == 0) {
    platforms[0] = {0, 56, 30};
    platforms[1] = {40, 48, 30};
    platforms[2] = {80, 40, 40};
  } else if (level == 1) {
    platforms[0] = {0, 56, 25};
    platforms[1] = {35, 50, 25};
    platforms[2] = {70, 44, 25};
    platforms[3] = {100, 36, 28};
  } else {
    platforms[0] = {0, 56, 20};
    platforms[1] = {30, 50, 20};
    platforms[2] = {60, 44, 20};
    platforms[3] = {90, 38, 20};
    platforms[4] = {110, 30, 18};
  }

  Serial.print(F("[LEVEL] "));
  Serial.println(level);
}

void handleInput() {
  int x = analogRead(JOY_X);

  if (x < 300) player.vx = -MOVE_SPEED;
  else if (x > 700) player.vx = MOVE_SPEED;
  else player.vx *= FRICTION;

  int jumpReading = digitalRead(JUMP_BTN);
  if (jumpReading == LOW && lastJumpState == HIGH && player.onGround) {
    player.vy = JUMP_FORCE;
    player.onGround = false;
    tone(BUZZER, 800, 100);
  }
  lastJumpState = jumpReading;
}

void updatePhysics() {
  player.vy += GRAVITY;
  player.x += player.vx;
  player.y += player.vy;

  if (player.x < 0) player.x = 0;
  if (player.x + player.w > SCREEN_WIDTH) player.x = SCREEN_WIDTH - player.w;

  if (player.y > SCREEN_HEIGHT) {
    player.alive = false;
    currentState = STATE_DEAD;
    tone(BUZZER, 200, 500);
    Serial.println(F("[DEAD] Fell"));
  }
}

void checkCollisions() {
  player.onGround = false;

  for (int i = 0; i < NUM_PLATFORMS; i++) {
    if (platforms[i].w == 0) continue;

    if (player.x + player.w > platforms[i].x &&
        player.x < platforms[i].x + platforms[i].w) {
      int platformTop = platforms[i].y;
      if (player.vy >= 0 &&
          player.y + player.h >= platformTop &&
          player.y + player.h <= platformTop + 8) {
        player.y = platformTop - player.h;
        player.vy = 0;
        player.onGround = true;
      }
    }
  }
}

void checkWinCondition() {
  if (player.x + player.w >= SCREEN_WIDTH - 5) {
    currentState = STATE_WIN;
    tone(BUZZER, 1500, 300);
    Serial.println(F("[WIN] Level complete!"));
  }
}

void render() {
  display.clearDisplay();

  for (int i = 0; i < NUM_PLATFORMS; i++) {
    if (platforms[i].w == 0) continue;
    display.fillRect(platforms[i].x, platforms[i].y, platforms[i].w, 2, SSD1306_WHITE);
  }

  display.fillRect((int)player.x, (int)player.y, player.w, player.h, SSD1306_WHITE);

  // Флаг
  display.drawLine(SCREEN_WIDTH - 5, 0, SCREEN_WIDTH - 5, SCREEN_HEIGHT, SSD1306_WHITE);
  display.fillTriangle(SCREEN_WIDTH - 5, 5, SCREEN_WIDTH - 5, 15, SCREEN_WIDTH - 15, 10, SSD1306_WHITE);

  // HUD
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print(F("Lvl:"));
  display.print(currentLevel + 1);

  display.display();
}