Finally got the foundation for a pseudo-3D game laid out… still trying to decide which direction to take it in, not sure if i want to try for something like 3D World Runner, Mechwarrior, or maybe Battlezone since each one has their upsides and downsides when it comes to implementation… i also need to refactor the code to clean it up a bit (so i havent made a repo yet) but here it is for now:
scrollingShooterTest.ino.hex (27.7 KB)
#include <Arduboy2.h>
Arduboy2 arduboy;
const int8_t horizonY = 10;
const uint8_t numLines = 6;
const uint8_t numEnemies = 3;
const uint8_t baseEnemySize = 4;
const uint8_t enemySizeRange = 8;
float lineSpacing[numLines];
float enemyPosX[numEnemies];
uint8_t enemyLine[numEnemies];
// Setup function initializes the Arduboy, sets the frame rate, and assigns random initial positions for the enemies.
void setup() {
arduboy.begin();
arduboy.setFrameRate(30);
arduboy.initRandomSeed();
// Calculate the initial Y positions for each line.
for (uint8_t i = 0; i < numLines; ++i) {
lineSpacing[i] = (arduboy.height() - horizonY) * (i + 1) / (numLines + 1) + horizonY;
}
// Set random initial positions for the enemies.
for (uint8_t i = 0; i < numEnemies; ++i) {
enemyPosX[i] = random(arduboy.width());
enemyLine[i] = random(numLines);
}
}
// The loop function handles input, updates the game state, and renders the screen.
void loop() {
// Skip the rest of the loop if it's not time to draw the next frame.
if (!arduboy.nextFrame()) {
return;
}
// Poll for button presses.
arduboy.pollButtons();
// Clear the screen buffer.
arduboy.clear();
// Move lines up or down based on user input.
if (arduboy.pressed(UP_BUTTON)) {
for (uint8_t i = 0; i < numLines; ++i) {
lineSpacing[i] -= 1;
// Wrap the lines around if they go above the horizon.
if (lineSpacing[i] <= horizonY) {
int8_t previousLine = (i + numLines - 1) % numLines;
lineSpacing[i] = lineSpacing[previousLine] + ((arduboy.height() - horizonY) / numLines);
}
}
} else if (arduboy.pressed(DOWN_BUTTON)) {
for (uint8_t i = 0; i < numLines; ++i) {
lineSpacing[i] += 1;
// Wrap the lines around if they go below the bottom of the screen.
if (lineSpacing[i] >= arduboy.height()) {
int8_t nextLine = (i + 1) % numLines;
lineSpacing[i] = lineSpacing[nextLine] - ((arduboy.height() - horizonY) / numLines);
}
}
}
// Move enemies left or right based on user input.
if (arduboy.pressed(LEFT_BUTTON)) {
for (uint8_t i = 0; i < numEnemies; ++i) {
enemyPosX[i] -= 1;
}
} else if (arduboy.pressed(RIGHT_BUTTON)) {
for (uint8_t i = 0; i < numEnemies; ++i) {
enemyPosX[i] += 1;
}
}
// Draw the horizon line.
arduboy.drawLine(0, horizonY, arduboy.width() - 1, horizonY, WHITE);
// Draw the lines representing the ground.
for (uint8_t i = 0; i < numLines; ++i) {
// Calculate the current Y position for each line based on its spacing.
int8_t currentY = (arduboy.height() - horizonY) * pow((lineSpacing[i] - horizonY) / (arduboy.height() - horizonY), 2) + horizonY;
// Draw the line at the calculated Y position.
arduboy.drawLine(0, currentY, arduboy.width() - 1, currentY, WHITE);
}
// Draw the enemies.
for (uint8_t i = 0; i < numEnemies; ++i) {
// Calculate the enemy's Y position based on its assigned line.
float enemyPosY = (arduboy.height() - horizonY) * pow((lineSpacing[enemyLine[i]] - horizonY) / (arduboy.height() - horizonY), 2) + horizonY;
// Calculate scaling factor for the enemy based on its Y position.
float scaleFactor = (enemyPosY - horizonY) / (arduboy.height() - horizonY);
// Calculate the enemy's width and height based on the scaling factor and the size variables.
uint8_t enemyWidth = baseEnemySize + enemySizeRange * scaleFactor;
uint8_t enemyHeight = baseEnemySize + enemySizeRange * scaleFactor;
// Draw the enemy as a rectangle with the calculated width and height.
arduboy.drawRect(enemyPosX[i] - enemyWidth / 2, enemyPosY - enemyHeight / 2, enemyWidth, enemyHeight, WHITE);
// Wrap the enemy's X position around the screen boundaries.
if (enemyPosX[i] < -enemyWidth / 2) {
enemyPosX[i] = arduboy.width() - enemyWidth / 2;
}
if (enemyPosX[i] > arduboy.width() + enemyWidth / 2) {
enemyPosX[i] = -enemyWidth / 2;
}
}
arduboy.display();
}