chatGPT creates Arduboy Game

AI generated Arduboy Game!
chatGPT.ino-arduboy.hex (19.0 KB)

If you haven’t seen already the same people behind the image generator DallE2, open AI they released a chat bot that’s pretty clever and can produce code examples:

Well, I asked it to make me an Arduboy game!

It’s… something! At least it knows to use the Arduboy 2 library.

I had to try the prompt a few times actually, the first result which you may notice tries to redefine a const:

image

6 Likes

Were Doomed GIFs | Tenor

Had it write a poem! What the actual f

6 Likes

Yes, it’s amazing. For chat i have a question. Quality of generated code is very good with comments asw… I like but i have ask for example for a Tetris code. I have all the beginning of the code but it’s cut due to the size of the message i think. Any solution to have all the generated code ?

You can say “keep going” and it will add the rest of the code, but things fall apart pretty quickly after that it seems.

1 Like

When i try below the partial code, i have the 3 moving dots but no answer. It’s too bad, because it’s code creation is amazing good…

It has no idea what it is doing, it’s just spitting out someone else code it stole from the internet.

1 Like

Let’s be honest, that poem is better than what 99% of the human population could write (including me). We are screwed.

Hmm,
I asked it to write Gallaga for me and got this. Certainly, it created the skell.

#include <Arduboy2.h>

// Arduboy object
Arduboy2 arduboy;

// Constants for game dimensions
const int SCREEN_WIDTH = 128;
const int SCREEN_HEIGHT = 64;

// Player position variables
int playerX;
int playerY;

// Enemy position variables
int enemyX;
int enemyY;

// Enemy movement direction
int enemyDir;

void setup() {
  // Initialize the Arduboy
  arduboy.begin();
  arduboy.setFrameRate(60);

  // Initialize player and enemy positions
  playerX = SCREEN_WIDTH / 2;
  playerY = SCREEN_HEIGHT - 8;
  enemyX = SCREEN_WIDTH / 2;
  enemyY = 8;
  enemyDir = 1;
}

void loop() {
  // Clear the screen
  arduboy.clear();

  // Check for input
  if (arduboy.pressed(LEFT_BUTTON) && playerX > 0) {
    playerX--;
  }
  if (arduboy.pressed(RIGHT_BUTTON) && playerX < SCREEN_WIDTH - 8) {
    playerX++;
  }
  if (arduboy.justPressed(A_BUTTON)) {
    // Fire a bullet
  }

  // Draw the player
  arduboy.drawRect(playerX, playerY, 8, 8, WHITE);

  // Move the enemy
  enemyX += enemyDir;
  if (enemyX <= 0 || enemyX >= SCREEN_WIDTH - 8) {
    enemyDir *= -1;
    enemyY += 8;
  }

  // Draw the enemy
  arduboy.drawRect(enemyX, enemyY, 8, 8, WHITE);

  // Update the screen
  arduboy.display();
}

@fredster,

When posting code in this forum please enclose it in code tags:
start with a line containing three backtics and cpp to indicate C++ code and end with a line containing three backticks:
```cpp
(your code goes here)
```

I done this for you in the above post but in the future please do it yourself.


This thing is awesome.

It tries to say like “I’m not programmed to insult things” but if you redo it enough times, it’ll usually do it.

The Playdate is cool and all but it’s even more expensive than the Arduboy and feels a bit more professional and less community-driven.

1 Like

I asked GPT4 to help me write an Arduboy game. I have no previous arduboy experience (I bought the device because it looked cool and I liked the form factor), and only a tiny bit of Arduino experience (just toying around with stuff like blinking LEDs). I wrote 0 code and only used prompts. The only edits to the code I made were adjusting some constants at the behest of GPT.

It’s a “falling blocks” style game that started out very basic (a square catching falling squares), and I kept adding features (other object shapes, a title and game over screen, better player controls) by prompting GPT. It’s not a particularly fun game, but it works amazingly well. I’m kind of in shock at how well it was able to iterate on the boilerplate code and add features. The whole conversation is pretty long, but the code is below. I’ll see if I can find a decent way to share the whole conversation if anyone is interested.

#include <Arduboy2.h>

class GameObject {
public:
  byte x, y;
  byte width, height;
  byte speed;
  bool isSquare;

  GameObject(byte x, byte y, byte width, byte height, byte speed, bool isSquare) {
    this->x = x;
    this->y = y;
    this->width = width;
    this->height = height;
    this->speed = speed;
    this->isSquare = isSquare;
  }

  void update() {
    y += speed;

    if (y > 64 - height) {
      respawn();
    }
  }

  void respawn() {
    y = 0;
    x = random(0, 128 - width);
    isSquare = random(0, 2); // Randomly assign the object's type (square or circle)
  }
};


Arduboy2 arduboy;

// Game variables
byte playerX = 56;
byte playerWidth = 8;
byte playerHeight = 8;
const byte playerSpeed = 4; // Adjust this value to make the player move faster or slower

const byte numObjects = 3;
GameObject objects[numObjects] = {
  GameObject(random(0, 128 - 8), 0, 8, 8, 1, random(0, 2)),
  GameObject(random(0, 128 - 8), 20, 8, 8, 1, random(0, 2)),
  GameObject(random(0, 128 - 8), 40, 8, 8, 1, random(0, 2))
};

enum GameState {
  GAME_RUNNING,
  GAME_OVER,
  TITLE_SCREEN
};

unsigned int score = 0;
GameState gameState = TITLE_SCREEN;
byte objectsCaught = 0;


void setup() {
  arduboy.begin();
  arduboy.setFrameRate(60);
  arduboy.initRandomSeed();
}

void loop() {
  if (!arduboy.nextFrame()) {
    return;
  }

  arduboy.pollButtons();

  arduboy.clear();

  if (gameState == TITLE_SCREEN) {
    // Display the title screen text
    arduboy.setCursor(10, 10);
    arduboy.print(F("Catch the falling"));
    arduboy.setCursor(25, 20);
    arduboy.print(F("diamonds"));
    arduboy.setCursor(3, 30);
    arduboy.print(F("Avoid the falling"));
    arduboy.setCursor(25, 40);
    arduboy.print(F("rocks"));

    arduboy.setCursor(10, 52);
    arduboy.print(F("Press A or B"));

    // Start the game when A or B is pressed
    if (arduboy.justPressed(A_BUTTON) || arduboy.justPressed(B_BUTTON)) {
      gameState = GAME_RUNNING;
    }
  } else if (gameState == GAME_RUNNING) {
    // Update and render the game as before
    if (arduboy.pressed(LEFT_BUTTON) && playerX > 0) {
      playerX -= playerSpeed;
    }

    if (arduboy.pressed(RIGHT_BUTTON) && playerX < (128 - playerWidth)) {
      playerX += playerSpeed;
    }

    arduboy.fillRect(playerX, 64 - playerHeight, playerWidth, playerHeight);

    for (byte i = 0; i < numObjects; i++) {
      GameObject &object = objects[i];
      object.update();

      if (object.isSquare) {
        // Draw a diamond
        arduboy.drawLine(object.x + object.width / 2, object.y, object.x, object.y + object.height / 2, WHITE);
        arduboy.drawLine(object.x, object.y + object.height / 2, object.x + object.width / 2, object.y + object.height, WHITE);
        arduboy.drawLine(object.x + object.width / 2, object.y + object.height, object.x + object.width, object.y + object.height / 2, WHITE);
        arduboy.drawLine(object.x + object.width, object.y + object.height / 2, object.x + object.width / 2, object.y, WHITE);
      } else {
        arduboy.fillCircle(object.x + object.width / 2, object.y + object.height / 2, object.width / 2);
      }

      if (arduboy.collide(Rect(playerX, 64 - playerHeight, playerWidth, playerHeight), Rect(object.x, object.y, object.width, object.height))) {
        if (object.isSquare) {
          score++;
          objectsCaught++;
        } else {
          if (score > 0) {
            score--;
          }
        }
        object.respawn();
      }
    }

    arduboy.setCursor(0, 0);
    arduboy.print(F("Score: "));
    arduboy.print(score);

    // Check if the game should end
    if (objectsCaught >= 10) {
      gameState = GAME_OVER;
    }
  } else if (gameState == GAME_OVER) {
    // Display a game over message and final score
    arduboy.setCursor(30, 20);
    arduboy.print(F("Game Over"));
    arduboy.setCursor(20, 32);
    arduboy.print(F("Final Score: "));
    arduboy.print(score);

    // Restart the game when A or B is pressed
    if (arduboy.justPressed(A_BUTTON) || arduboy.justPressed(B_BUTTON)) {
      gameState = GAME_RUNNING;
      score = 0;
      objectsCaught = 0;

      // Reset the positions and types of the objects
      for (byte i = 0; i < numObjects; i++) {
        objects[i].respawn();
      }
    }
  }

  arduboy.display();
}
2 Likes

That’s amazing!

I’ve compiled the .hex and played it in the emulator . . .

sketch_mar28a.ino-arduboy-leonardo-sh1106.hex (24.4 KB)

ArduboyRecording

Not much of a game, but pretty cool I guess!

1 Like

Not sure if it’s just me, but the emulator is just showing a bunch of scrolling nonsense. Do I have the wrong emulator? Any particular browser requirements? The game works fine on my physical Arduboy.

My bad, it was like that for me too. Seems like something is wrong with my Arduino 1.8.19 IDE. Compiled with the Arduino IDE 2 and everything was fine. Super weird though.

sketch_mar28a.ino.hex (24.4 KB)

ArduboyRecording(1)

Really cool what AI is capable of!

8 Likes

WOW this is serious improvement over gpt3!

3 Likes

I actually started using GPT4 to create an Arduboy game… its the basis for a pseudo 3D scrolling shooter. Here are the results so far:

As for my experience with it, it wasnt as simple as me telling it what i wanted and producing the correct output, rather starting with something a bit more simple and building on it piece by piece… it also took a little correcting with things like using int rather than specific data types, but once i explained the use of different data types for what ranges (uint8_t, int8_t, uint16_t, and int16_t) then it made the appropriate changes (then corrected them when it produced incorrect results). Much better to work with than GPT3 (which seemed to progressively lose track when trying to understand or produce much simpler programs).

3 Likes

Pretty impressive.

I had this beer the other night, Dainton’s Machine Mind. Its recipe and marketing blurb were created using ChatGPT allegedly. This is in Oz but assume other brewers will be doing it around the world, if not already then soon.

Pretty nice, I must say!

3 Likes

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();
}
1 Like

Ah, yes, cos and sin. Shame I haven’t learned trigonometry in school yet :broken_heart: