Statek kosmiczny

Typ_projektu
Arduino
Zdjecie główne
Krótki opis projektu

Gra na arduino Statek kosmiczny.

Niezbędne elementy

[przykładowe - prosimy o edycję]

1. Płytka Arduino UNO

2. 3 przyciski,

3. ekranik OLED 0.96''

Opis projektu

Gra statki kosmiczne nawiązuje mechaniką do gry z starych konsol w której należy unikać spadających asteroid statkiem kosmicznym. Do dyspozycji statek ma pociski którymi możemy zniszczyć asteroidy, w magazynku możemy mieć trzy serie pocisków (każda seria to dwa pociski, jeden wylatujący z lewej drugi z prawej strony statku) i mają z góry narzucony czas odnawiania. Sterowanie statkiem i strzelanie kontrolowane jest przez 3 przyciski. Statek porusza się tylko po poziomej osi. Gracz przegrywa gdy statek zderzy się z asteroidą. Liczba asteroid rośnie wraz z biegiem czasu, na początku jest ich 8 i co każde 10 sekund dodaje się kolejna. Asteroidy mają losowo generowany rozmiar, prędkość i miejsce z którego wylatują.

Projekt stworzony przy pomocy AI.

kod programu

 

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

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

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

// Define triangle vertices (upside-down)
int triangleTopX = SCREEN_WIDTH / 2;
int triangleTopY = 50; // Moved to the top
int triangleBaseX1 = triangleTopX - 5;
int triangleBaseX2 = triangleTopX + 5;
int triangleBaseY = triangleTopY + 10; // Adjusted to maintain triangle size

// Define button pins
const int leftButtonPin = 10;
const int rightButtonPin = 8;
const int spawnButtonPin = 7;

// Define dot structure
struct Dot {
 int x;
 int y;
 float speed; // Change speed type to float for better precision
 int size; // Size of the dot
};

// Maximum and minimum number of dots
const int minDots = 7;
const int maxDots = 20;

// Array to store dots
Dot dots[maxDots];

// Rectangle properties
int rectWidth = 2; // Width of the rectangle
int rectHeight = 6; // Height of the rectangle

struct Rectangle {
 int x; // X position of the rectangle
 int y; // Y position of the rectangle
 bool spawned; // Flag to indicate if the rectangle has been spawned
};

const int maxRectangles = 6; // Maximum number of rectangles
Rectangle rectangles[maxRectangles]; // Array to store rectangles

// Flag to indicate game over
bool gameOver = false;

// Counter for the number of dots
int dotCounter = 0;

unsigned long previousDotUpdateMillis = 0;
unsigned long previousCollisionCheckMillis = 0;
const unsigned long dotUpdateInterval = 100; // Update dot positions every 100 milliseconds
const unsigned long collisionCheckInterval = 1000; // Check for collisions every 1000 milliseconds

// Global variable to store the elapsed time in seconds
unsigned long previousTimeUpdateMillis = 0;
int czas = 0;

void setup() {
 // Setup OLED display
 if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
   Serial.println(F("SSD1306 allocation failed"));
   for (;;);
 }
 Serial.begin(9600);
 display.setRotation(2); // Rotate the display upside-down
 display.display();
 delay(500); // Pause for 1 second before dots start spawning
 
 // Clear the display
 display.clearDisplay();
 
 // Setup buttons
 pinMode(leftButtonPin, INPUT_PULLUP);
 pinMode(rightButtonPin, INPUT_PULLUP);
 pinMode(spawnButtonPin, INPUT_PULLUP);
 
 // Initialize dots after the initial delay
 initializeDots();
}

// Define button 7 properties
const int button7Pin = 7;
int availablePresses = 3; // Initially, button 7 can be pressed 3 times

void loop() {
 unsigned long currentMillis = millis();
 
 if (!gameOver) {
   // Check if left button is pressed
   if (digitalRead(leftButtonPin) == LOW) {
     // Move triangle to the left (1.5 times faster)
     triangleTopX -= 4;
     triangleBaseX1 -= 4;
     triangleBaseX2 -= 4;
     
     // Wrap triangle position around when it reaches the left edge
     if (triangleTopX < 0) {
       triangleTopX = SCREEN_WIDTH - 1;
       triangleBaseX1 = triangleTopX - 5;
       triangleBaseX2 = triangleTopX + 5;
     }
   }
 
   // Check if right button is pressed
   if (digitalRead(rightButtonPin) == LOW) {
     // Move triangle to the right (1.5 times faster)
     triangleTopX += 4;
     triangleBaseX1 += 4;
     triangleBaseX2 += 4;
     
     // Wrap triangle position around when it reaches the right edge
     if (triangleTopX >= SCREEN_WIDTH) {
       triangleTopX = 0;
       triangleBaseX1 = triangleTopX - 5;
       triangleBaseX2 = triangleTopX + 5;
     }
   }

   // Check if spawn button is pressed
   if (digitalRead(spawnButtonPin) == LOW && availablePresses > 0) {
     // Find an available slot for the rectangle
     for (int i = 0; i < maxRectangles; i++) {
       if (!rectangles[i].spawned) {
         // Spawn rectangle
         rectangles[i].x = triangleBaseX1; // Spawn at the side of the screen where the triangle is
         rectangles[i].y = triangleBaseY; // Move the spawn point 5 pixels to the top
         rectangles[i].spawned = true;
         i = i + 1;
         rectangles[i].x = triangleBaseX2; // Spawn at the side of the screen where the triangle is
         rectangles[i].y = triangleBaseY; // Move the spawn point 5 pixels to the top
         rectangles[i].spawned = true;
         availablePresses--; // Decrease available presses
         break; // Exit loop after spawning a rectangle
       }
     }
   }
 
   // Update dots at regular intervals
   if (currentMillis - previousDotUpdateMillis >= dotUpdateInterval) {
     updateDots();
     previousDotUpdateMillis = currentMillis;
   }
 
   // Clear display
   display.clearDisplay();
 
   // Draw upside-down triangle
   display.fillTriangle(triangleTopX, triangleTopY,
                        triangleBaseX1, triangleBaseY,
                        triangleBaseX2, triangleBaseY, SSD1306_WHITE);
 
   // Draw rectangles
   for (int i = 0; i < maxRectangles; i++) {
     if (rectangles[i].spawned) {
       display.fillRect(rectangles[i].x, rectangles[i].y, rectWidth, rectHeight, SSD1306_WHITE);

       // Move rectangle
       rectangles[i].y -= 6; // Move the rectangle upwards at three times the speed
       
       // Check if rectangle reaches the top of the screen
       if (rectangles[i].y <= 0) {
         rectangles[i].spawned = false; // Reset rectangle spawn flag
       }
     }
   }

   // Check for collision between dots and rectangles
   for (int i = 0; i < maxDots; i++) {
     if (dots[i].speed != 0) {
       for (int j = 0; j < maxRectangles; j++) {
         if (rectangles[j].spawned) {
           if (dotRectangleCollision(dots[i].x, dots[i].y, dots[i].size, rectangles[j].x, rectangles[j].y, rectWidth, rectHeight)) {
             dots[i].speed = 0; // Set dot's speed to zero
             rectangles[j].spawned = false; // Reset rectangle spawn flag
             spawnDot(); // Spawn a new dot
             break; // Exit the loop once a collision is detected for this dot
           }
         }
       }
     }
   }
 
   // Draw dots
   dotCounter = 0; // Reset dot counter
   for (int i = 0; i < maxDots; i++) {
     if (dots[i].speed != 0) { // Only draw dots that are initialized
       int dotSize = dots[i].size; // Get the size of the dot
       display.fillCircle(dots[i].x, dots[i].y, dotSize, SSD1306_WHITE);
       dotCounter++; // Increment dot counter
     }
   }
   
   // Display dot counter
   display.setTextSize(1);
   display.setTextColor(SSD1306_WHITE);
   display.setCursor(0, 15); // Set cursor to top-left corner
   display.print("Dots: ");
   display.println(dotCounter);

   // Display available button 7 presses as small squares
   int squareSize = 6; // Size of each square
   for (int i = 0; i < availablePresses; i++) {
       // Calculate position of each square
       int squareX = SCREEN_WIDTH / 2 - 60 + i * (squareSize + 2); // Adjusted position for the squares
       int squareY = 55; // Adjusted Y position

       // Draw the square
       display.fillRect(squareX, squareY, squareSize, squareSize, SSD1306_WHITE);
   }

   // Display time in seconds
   display.setTextSize(1);
   display.setTextColor(SSD1306_WHITE);
   display.setCursor(0,0); // Adjust position for the counter
   display.print("Time: ");
   display.print(czas);
   
 } else {
   // Display "Game Over" when the game is over
   display.setTextSize(2);
   display.setTextColor(SSD1306_WHITE);
   display.setCursor(10, 20);
   display.println("Game Over");
   
   // Show display buffer
   display.display();
   
   // Stop the program
   while (true) {
     // Empty loop
   }
 }
 
 // Show display buffer
 display.display();
 
 // Update the time value every second
 if (currentMillis - previousTimeUpdateMillis >= 1000) {
   czas++; // Increment the time value
   previousTimeUpdateMillis = currentMillis; // Update the previous update time
   
   // Increase available presses for button 7 every 5 seconds up to the maximum limit
   if (czas % 5 == 0 && availablePresses < 3) {
     availablePresses++;
   }

   // Increase dot count every 10 seconds
   if (czas % 10 == 0) {
     increaseDots();
   }
 }
 
 // Delay for visual effect
 delay(100);
}


// Initialize dots
void initializeDots() {
 int numDots = random(minDots, 8 + 1); // Generate a random number of dots between minDots and maxDots
 for (int i = 0; i < numDots; i++) {
   if (i < numDots) {
     dots[i].x = random(0, SCREEN_WIDTH);
     dots[i].y = SCREEN_HEIGHT; // Start dots from the bottom of the screen
     dots[i].speed = random(3.0, 6.0); // Randomize speed between 1 and 2 times faster
     dots[i].size = random(2, 7); // Randomize dot size (2 or 3 times bigger)
   } else {
     // Set the remaining dots outside the screen to avoid drawing them
     dots[i].x = -1;
     dots[i].y = -1;
     dots[i].speed = 0;
     dots[i].size = 0;
   }
 }
}

// Update dot positions
void updateDots() {
 for (int i = 0; i < maxDots; i++) {
   if (dots[i].speed != 0) {
     // Move dots towards the bottom edge
     dots[i].y += dots[i].speed;

     // Wrap dot position around when it reaches the bottom edge
     if (dots[i].y >= SCREEN_HEIGHT + 10) {
       dots[i].y = 0;
       // Respawn dot at a random position at the top edge
       dots[i].x = random(0, SCREEN_WIDTH);
       dots[i].speed = random(3.0, 6.0); // Randomize speed between 1 and 2 times faster
       dots[i].size = random(2, 7); // Randomize dot size (2 or 3 times bigger)
     }

     // Check for collision with the triangle
     if (triangleCollision(triangleTopX, triangleTopY, triangleBaseX1, triangleBaseX2, triangleBaseY, dots[i].x, dots[i].y, dots[i].size)) {
       gameOver = true; // Collision detected, set game over flag
       break; // Exit the loop early
     }
   }
 }
}

// Function to check collision between triangle and dot
bool triangleCollision(int tx, int ty, int bx1, int bx2, int by, int dx, int dy, int dotSize) {
 // Calculate the coordinates of the vertices of the triangle
 int t1x = tx;
 int t1y = ty;
 int t2x = bx1;
 int t2y = by;
 int t3x = bx2;
 int t3y = by;

 // Calculate the coordinates of the center of the dot
 int cx = dx;
 int cy = dy;

 // Check if any edge of the dot intersects with any edge of the triangle
 if (lineIntersect(t1x, t1y, t2x, t2y, cx, cy, dotSize) ||
     lineIntersect(t2x, t2y, t3x, t3y, cx, cy, dotSize) ||
     lineIntersect(t3x, t3y, t1x, t1y, cx, cy, dotSize)) {
   return true; // Collision detected
 }

 return false; // No collision
}

// Function to check if a line segment intersects with a circle
bool lineIntersect(int x1, int y1, int x2, int y2, int cx, int cy, int r) {
 // Compute the squared distance from the circle center to the line segment
 int dx = x2 - x1;
 int dy = y2 - y1;
 int len2 = dx * dx + dy * dy;
 int dot = (cx - x1) * dx + (cy - y1) * dy;
 float t = float(dot) / len2;

 // Clamp t to the range [0, 1]
 t = max(0.0f, min(1.0f, t));

 // Compute the closest point on the line segment to the circle center
 int closestX = x1 + int(t * dx);
 int closestY = y1 + int(t * dy);

 // Check if the closest point is within the circle's radius, considering the dot's size
 int distance2 = (cx - closestX) * (cx - closestX) + (cy - closestY) * (cy - closestY);
 return distance2 <= (r * r + 1); // Added 1 to account for small size differences
}

// Function to check collision between dot and rectangle
bool dotRectangleCollision(int dx, int dy, int dotSize, int rx, int ry, int rw, int rh) {
 int margin = 2; // Margin around the dot
 // Check if dot is inside the rectangle
 if (dx + margin >= rx && dx - margin <= rx + rw && dy + margin >= ry && dy - margin <= ry + rh) {
   return true; // Collision detected
 }

 // Check if dot is at the edge of the rectangle
 if ((dx + dotSize + margin >= rx && dx + dotSize - margin <= rx + rw && dy + margin >= ry && dy - margin <= ry + rh) || // Right edge
     (dx - dotSize + margin >= rx && dx - dotSize - margin <= rx + rw && dy + margin >= ry && dy - margin <= ry + rh) || // Left edge
     (dx + margin >= rx && dx - margin <= rx + rw && dy + dotSize + margin >= ry && dy + dotSize - margin <= ry + rh) || // Bottom edge
     (dx + margin >= rx && dx - margin <= rx + rw && dy - dotSize + margin >= ry && dy - dotSize - margin <= ry + rh)) { // Top edge
   return true; // Collision detected
 }

 return false; // No collision
}

// Function to spawn a new dot
void spawnDot() {
 // Find an available slot for the dot
 for (int i = 0; i < maxDots; i++) {
   if (dots[i].speed == 0) {
     // Respawn dot at a random position at the top edge
     dots[i].x = random(0, SCREEN_WIDTH);
     dots[i].y = SCREEN_HEIGHT+10; // Start dot from the bottom of the screen
     dots[i].speed = random(3.0, 6.0); // Randomize speed between 1 and 2 times faster
     dots[i].size = random(2, 7); // Randomize dot size (2 or 3 times bigger)
     break; // Exit loop after spawning a dot
   }
 }
}

// Increase the number of dots

void increaseDots() {

 // Increase the number of dots if not already at maximum

 if (dotCounter < maxDots) {

   for (int i = 0; i < maxDots; i++) {

     if (dots[i].speed == 0) {

       // Respawn dot at a random position at the top edge

       dots[i].x = random(0, SCREEN_WIDTH);

       dots[i].y = SCREEN_HEIGHT+10; // Start dot from the bottom of the screen

       dots[i].speed = random(3.0, 6.0); // Randomize speed between 1 and 2 times faster

       dots[i].size = random(2, 7); // Randomize dot size (2 or 3 times bigger)

       dotCounter++; // Increment dot counter

       break; // Exit loop after spawning a dot

     }

   }

 }
Youtube
Tagi
gra statek kosmiczny arduino projekt