#include <TFT_eSPI.h> // Library for TFT display
#include <QList.h> // Library for QList
#include <SPI.h> // SPI communication library
// Global variables
int period = 1000; // Time period for FPS calculation
unsigned long time_now = 0; // Time variable for tracking period
int fps = 0; // Frames per second counter
// TFT display object
TFT_eSPI screen = TFT_eSPI();
// Class definition for ball objects
class ball {
private:
float x; // X-coordinate of the ball
float y; // Y-coordinate of the ball
int size; // Size of the ball
int color; // Color of the ball
int health; // Health of the ball
float speed; // Speed of the ball
float direction; // Direction of movement of the ball
int type; // Type of the ball
// Private methods
void draw() {
// Draw the ball on the screen
screen.fillCircle(x, y, size, color);
screen.drawCircle(x, y, size + 1, TFT_BLACK);
screen.drawCircle(x, y, size + 2, TFT_BLACK);
}
void updateLoc() {
// Update the location of the ball based on its movement
// If the ball goes beyond the screen boundaries, wrap it around
if (x < -size) {
x = 240 + size;
color = random(0x10000);
}
if (x > (240 + size)) {
x = 0 - size;
color = random(0x10000);
}
if (y < -size) {
y = 320 + size;
color = random(0x10000);
}
if (y > (320 + size)) {
y = 0 - size;
color = random(0x10000);
}
// Update the position of the ball based on its speed and direction
x += cos(direction * 3.1415 / 180) * speed;
y += sin(direction * 3.1415 / 180) * speed;
}
public:
// Constructors
ball() {}
~ball() {
// Destructor to erase the ball from the screen when destroyed
screen.fillCircle(x, y, size + 2, TFT_BLACK);
}
ball(int type) {
// Constructor to initialize ball properties based on type
this->type = type;
switch (type) {
case 1:
size = 2;
color = TFT_RED;
health = 10;
speed = 1.1;
break;
case 2:
size = 4;
color = TFT_GREEN;
health = 2;
speed = 0.8;
break;
case 3:
size = 3;
color = TFT_YELLOW;
health = 5;
speed = 0.5;
break;
case 4:
size = 2;
color = TFT_PINK;
health = 1;
speed = 1.3;
break;
}
// Randomly initialize position and direction of the ball
direction = random(0, 369);
x = random(0, 240);
y = random(0, 160);
}
// Public method to run the ball (update and draw)
void run() {
updateLoc();
draw();
}
};
// List to hold multiple ball objects
QList<ball> ballList;
// Setup function, runs once at the start
void setup() {
Serial.begin(115200); // Initialize serial communication
screen.init(); // Initialize the TFT screen
screen.setRotation(8); // Set screen rotation
screen.fillScreen(TFT_BLACK); // Fill the screen with black color
// Initialize the ballList with 3 random balls
for (int i = 0; i < 3; i++) {
ballList.push_back(ball(random(0, 4)));
}
}
// Loop function, runs repeatedly
void loop() {
fps = fps + 1; // Increment FPS counter
// Check if a period has passed
if (millis() >= time_now + period) {
time_now += period; // Update time variable
// Display FPS and number of balls on the screen
screen.drawString("FPS = " + String(fps), 0, 0, 2);
screen.drawString("balls = " + String(ballList.size()), 0, 20, 2);
// Adjust the number of balls based on FPS
if (fps > ballList.size()) {
ballList.push_back(ball(random(0, 4))); // Add a new random ball
} else {
ballList.clear(random(0, ballList.size())); // Remove a random ball
}
fps = 0; // Reset FPS counter
}
// Run all the balls in the ballList
for (int i = 0; i < ballList.size(); i++) {
ballList.at(i).run();
}
}