#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Размеры экрана
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// Адрес дисплея и сброс
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Количество врагов
#define NUM_TRIANGLES 5
// Пины джойстика
#define JOYSTICK_X A0
#define JOYSTICK_Y A1
#define BUTTON_SINGLE_FIRE 2
#define BUTTON_BURST_FIRE 3
// Переменные
int playerX = 30;
int playerY = 30;
int score = 0;
bool gameOver = false;
// Структура для хранения координат треугольника
struct Triangle {
int x; // Координата X
int y; // Координата Y
int size; // Размер треугольника
};
#define MAX_BULLETS 3 // Очередь из 3 пуль
struct Bullet {
int x;
int y;
bool active;
};
Bullet bullets[MAX_BULLETS];
bool isBurstFire = false;
// Массив врагов
Triangle enemies[NUM_TRIANGLES];
// --- Функции ---
// Генерация врагов
void createEnemies() {
for (int i = 0; i < NUM_TRIANGLES; i++) {
enemies[i].x = random(SCREEN_WIDTH / 2, SCREEN_WIDTH - 5); // Размещение справа
enemies[i].y = random(10, SCREEN_HEIGHT - 10); // Случайная высота
enemies[i].size = random(2, 4); // Случайный размер
}
}
// Обновление врагов
void updateEnemies() {
for (int i = 0; i < NUM_TRIANGLES; i++) {
enemies[i].x -= 1; // Движение влево
// Если враг выходит за экран, перемещаем его обратно
if (enemies[i].x + enemies[i].size < 0) {
enemies[i].x = random(SCREEN_WIDTH / 2, SCREEN_WIDTH - 5);
enemies[i].y = random(10, SCREEN_HEIGHT - 10);
enemies[i].size = random(2, 4);
}
}
}
// Отрисовка врагов
void drawEnemies() {
for (int i = 0; i < NUM_TRIANGLES; i++) {
display.fillTriangle(
enemies[i].x, enemies[i].y,
enemies[i].x + enemies[i].size, enemies[i].y + enemies[i].size,
enemies[i].x + enemies[i].size, enemies[i].y - enemies[i].size,
SSD1306_WHITE
);
}
}
// Обновление позиции игрока
void updatePlayer() {
int xVal = analogRead(JOYSTICK_X);
int yVal = analogRead(JOYSTICK_Y);
// Управление
if (xVal < 400) playerX += 2; // Влево
if (xVal > 600) playerX -= 2; // Вправо
if (yVal < 400) playerY += 2; // Вверх
if (yVal > 600) playerY -= 2; // Вниз
// Ограничение позиции
playerX = constrain(playerX, 5, SCREEN_WIDTH / 2 - 5);
playerY = constrain(playerY, 10, SCREEN_HEIGHT - 5);
}
// Отрисовка игрока
void drawPlayer() {
display.fillTriangle(
playerX, playerY,
playerX - 5, playerY + 5,
playerX - 5, playerY - 5,
SSD1306_WHITE
);
}
// Отрисовка счёта
void drawScore() {
display.setCursor(0, 0);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.print(F("Score: "));
display.print(score);
}
// Проверка столкновений
void checkCollisions() {
for (int i = 0; i < NUM_TRIANGLES; i++) {
// Проверка на пересечение с врагом
if (playerX < enemies[i].x + enemies[i].size &&
playerX + 5 > enemies[i].x &&
playerY < enemies[i].y + enemies[i].size &&
playerY + 5 > enemies[i].y) {
gameOver = true; // Столкновение произошло
}
}
}
// Основная функция отрисовки
void render() {
display.clearDisplay();
drawScore(); // Отрисовка счёта
drawPlayer(); // Отрисовка игрока
drawEnemies(); // Отрисовка врагов
drawBullets();
display.display();
}
void endGame() {
display.clearDisplay();
display.setCursor(15, 20);
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.print(F("GAME OVER"));
display.display();
}
void shoot() {
if (isBurstFire) {
// Стрельба очередью
for (int i = 0; i < MAX_BULLETS; i++) {
if (!bullets[i].active) {
bullets[i].x = playerX + (i * -3); // Смещение пули в зависимости от ее индекса
bullets[i].y = playerY;
bullets[i].active = true;
break;
}
}
} else {
// Стрельба одиночной пулей
for (int i = 0; i < 1; i++) {
if (!bullets[i].active) {
bullets[i].x = playerX;
bullets[i].y = playerY;
bullets[i].active = true;
break;
}
}
}
isBurstFire = false;
}
void updateBullets() {
for (int i = 0; i < MAX_BULLETS; i++) {
if (bullets[i].active) {
bullets[i].x += 3;
if (bullets[i].x > SCREEN_WIDTH) {
bullets[i].active = false;
}
for (int j = 0; j < NUM_TRIANGLES; j++) {
if (bullets[i].x > enemies[j].x && bullets[i].x < enemies[j].x + enemies[j].size &&
bullets[i].y > enemies[j].y - enemies[j].size && bullets[i].y < enemies[j].y + enemies[j].size) {
enemies[j].x = random(SCREEN_WIDTH / 2, SCREEN_WIDTH - 5);
enemies[j].y = random(10, SCREEN_HEIGHT - 10);
enemies[j].size = random(2, 4);
bullets[i].active = false;
score += 10;
}
}
}
}
}
void drawBullets() {
for (int i = 0; i < MAX_BULLETS; i++) {
if (bullets[i].active) {
display.drawCircle(bullets[i].x, bullets[i].y, 1, SSD1306_WHITE);
}
}
}
// --- Основная программа ---
void setup() {
Serial.begin(9600);
// Инициализация дисплея
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 initialization failed"));
for (;;);
}
// Настройка джойстика
pinMode(JOYSTICK_X, INPUT);
pinMode(JOYSTICK_Y, INPUT);
pinMode(BUTTON_SINGLE_FIRE, INPUT_PULLUP);
pinMode(BUTTON_BURST_FIRE, INPUT_PULLUP);
display.clearDisplay();
createEnemies();
}
void loop() {
if (gameOver) {
endGame();
return;
}
updatePlayer();
updateEnemies();
updateBullets();
if (digitalRead(BUTTON_SINGLE_FIRE) == LOW) {
isBurstFire = false;
shoot();
}
if (digitalRead(BUTTON_BURST_FIRE) == LOW) {
isBurstFire = true;
shoot();
}
checkCollisions(); // Проверка столкновений
render(); // Отрисовка всей сцены
// Увеличение счёта каждые 50 итераций
static int counter = 0;
counter++;
if (counter > 50) {
score++;
counter = 0;
}
delay(10); // Задержка для плавного обновления
}
Loading
ssd1306
ssd1306