Загрузка данных
#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();
}