Wow, now this is just amazing… so i’ve focused my (current) efforts on developing the pseudo 3D scrolling shooter i posted above, however ive still just been messing around with GPT4 in general (curious what sort of output it produces) and toying with other game ideas… and i simply gave it the prompt “Code the basis for a pseudo 3D Arduboy game”, then “continue coding the aforementioned parts” (when it described what else i would need to complete the rendering engine) and it gave me a 3D raycasting engine… and a remarkably simple one, no less… Granted, initially it was much too slow to be useful for anything, but i told it to optimize the code and it did improve.
Heres the code… it isnt perfect, as i mentioned above it uses int where it should use more specific data types (and i dont really feel like taking the time to edit that when im not currently using it for anything), plus im sure there are probably other Arduboy-specific things that may be incorrect, but still amazing that it works nonetheless (although i am curious to hear others’ thoughts on this as well)…
And for anyone curious, the sketch only uses 8858 bytes of program storage space (30%) and only 1274 bytes (49%) of dynamic memory
#include <Arduboy2.h>
#include <math.h>
Arduboy2 arduboy;
// Game variables
float playerX = 1.5;
float playerY = 1.5;
float playerAngle = 0;
// Map data
const int mapWidth = 8;
const int mapHeight = 8;
const uint8_t mapData[mapWidth * mapHeight] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1
};
// Function prototypes
void handleInput();
void raycast();
uint8_t getMapTile(int x, int y);
void handleInput() {
float moveSpeed = 0.05;
float rotationSpeed = 0.03;
if (arduboy.pressed(LEFT_BUTTON)) {
playerAngle -= rotationSpeed;
}
if (arduboy.pressed(RIGHT_BUTTON)) {
playerAngle += rotationSpeed;
}
if (arduboy.pressed(UP_BUTTON)) {
playerX += cos(playerAngle) * moveSpeed;
playerY += sin(playerAngle) * moveSpeed;
}
if (arduboy.pressed(DOWN_BUTTON)) {
playerX -= cos(playerAngle) * moveSpeed;
playerY -= sin(playerAngle) * moveSpeed;
}
}
void raycast() {
int screenWidth = arduboy.width();
int screenHeight = arduboy.height();
int rayStep = 4; // Increase the step to skip columns and speed up rendering
for (int x = 0; x < screenWidth; x += rayStep) {
float rayAngle = playerAngle + (x / float(screenWidth) - 0.5) * M_PI / 3;
float cosRayAngle = cos(rayAngle);
float sinRayAngle = sin(rayAngle);
float currentX = playerX;
float currentY = playerY;
float maxRayDistance = 5.0f; // Limit the ray distance to avoid infinite loops
for (float distance = 0; distance < maxRayDistance; distance += 0.05) {
currentX += cosRayAngle * 0.05;
currentY += sinRayAngle * 0.05;
if (getMapTile(int(currentX), int(currentY)) != 0) {
int wallHeight = screenHeight / distance * 1.2;
int startY = (screenHeight - wallHeight) / 2;
int endY = startY + wallHeight;
if (startY < 0) {
startY = 0;
}
if (endY > screenHeight) {
endY = screenHeight;
}
arduboy.drawFastVLine(x, startY, endY - startY, WHITE);
break;
}
}
}
}
uint8_t getMapTile(int x, int y) {
if (x < 0 || y < 0 || x >= mapWidth || y >= mapHeight) {
return 1;
}
return mapData[y * mapWidth + x];
}
void setup() {
arduboy.begin();
arduboy.setFrameRate(30);
}
void loop() {
if (!arduboy.nextFrame()) {
return;
}
arduboy.pollButtons();
handleInput();
arduboy.clear();
raycast();
arduboy.display();
}