Sunday, 29 September 2024

ChatGPT4 + ESP32 = Space Invaders game!


Now that the new version of OpenAI's GPT-4 is available, I thought I would give it a test and see how well it can write code for the ESP32 modules. There were a few rules imposed so that I could judge how much better the new version is compared to the last.

Here are the prerequisites:

  • Only one prompt allowed to request the writing of the game. No editing of prompt once request has been uploaded
  • Code must be copied and pasted directly from ChatGPT-4 directly to Arduino IDE 2.2  No code review or code adjustments.
  • ESP32 to be wired as per ChatGPT-4's code
  • Installation of missing libraries will be allowed
  • Code must upload to ESP32 device without errors and game must run without major problems

Lets dive in and see how OpenAI's GPT-4 did when asked to create a Space Invaders retro game for an ESP32 device.

1. The Prompt:

The prompt needed to worded with as much information needed so that OpenAI's GPT-4 knows exactly what the goal is, what hardware is available and which platform the Space Invaders game will run on.

Below in quotes is the original, once off prompt:

"Write me a small space invader game in C or C++ that can run on an esp32 with a 128×64 pixel oled screen attached and one joystick as a controller. Can also use one button for firing missiles at the space invaders"

As you can see, the hardware is defined as an EP32 module without specifying which version or chip. Define the size of the OLED screen in pixels. Use a joystick to move the ship around and use a button to fire. Some joysticks do have a built in switch, but I left it up to ChatGPT-4 to decide on the button wiring. Either by using the joystick built in switch or by wiring a separate switch, depending on the code that will be spat out.

2. ChatGPT-4's response:

Creating a simple "Space Invader" game for an ESP32 with a 128x64 OLED screen and a joystick involves several key steps, including handling the display, joystick input, and game logic. You can use libraries like U8g2 or Adafruit_GFX for OLED rendering and the built-in Wire library for I2C communication with the OLED display.

Here's a minimal version of the game written in C++ for an ESP32 using the U8g2 library for drawing on the screen. The joystick will control the player's movement, and a button will fire missiles.
Hardware setup:

    OLED Display: Connected to ESP32 via I2C (SCL and SDA).
    Joystick: Analog joystick with two axes (X and Y) connected to analog pins.
    Button: Connected to a digital pin for firing.

Required Libraries:

    U8g2 for the OLED display: U8g2
    Wire for I2C communication with the display.

Game Overview:

    The player moves a small ship left or right using the joystick.
    Pressing the button fires a missile toward the invading aliens.
    Simple alien sprites move horizontally and descend slowly.

3. ChatGPT-4´s code:

#include <Arduino.h>
#include <U8g2lib.h>

// OLED Display (128x64) using I2C
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE, /* clock=*/SCL, /* data=*/SDA);

// Joystick Pins
const int joystickX = 34; // X-axis pin (ADC)
const int buttonPin = 35; // Fire button pin (Digital)

// Constants
const int screenWidth = 128;
const int screenHeight = 64;
const int shipWidth = 10;
const int shipHeight = 4;
const int alienWidth = 8;
const int alienHeight = 5;
const int maxAliens = 5;

// Player variables
int playerX = screenWidth / 2 - shipWidth / 2;
int missileX = -1, missileY = -1; // No missile initially
bool missileActive = false;

// Alien variables
int alienX[maxAliens], alienY[maxAliens];
int alienDirection = 1; // 1 for right, -1 for left
int alienSpeed = 1; // Speed of alien movement

// Button and joystick state
int lastButtonState = LOW;
int joystickValueX = 0;

// Initialize aliens at the top of the screen
void initAliens() {
for (int i = 0; i < maxAliens; i++) {
alienX[i] = i * (alienWidth + 10);
alienY[i] = 10;
}
}

// Setup function
void setup() {
u8g2.begin(); // Initialize the display
pinMode(buttonPin, INPUT);
initAliens();
}

// Draw the player ship
void drawShip(int x) {
u8g2.drawBox(x, screenHeight - shipHeight - 2, shipWidth, shipHeight);
}

// Draw aliens
void drawAliens() {
for (int i = 0; i < maxAliens; i++) {
if (alienY[i] >= 0) { // Only draw aliens that are alive
u8g2.drawBox(alienX[i], alienY[i], alienWidth, alienHeight);
}
}
}

// Draw missile if active
void drawMissile() {
if (missileActive) {
u8g2.drawPixel(missileX, missileY);
}
}

// Update alien positions
void updateAliens() {
for (int i = 0; i < maxAliens; i++) {
alienX[i] += alienDirection * alienSpeed;
}

// Change direction when an alien hits the screen edge
for (int i = 0; i < maxAliens; i++) {
if (alienX[i] <= 0 || alienX[i] + alienWidth >= screenWidth) {
alienDirection *= -1;
for (int j = 0; j < maxAliens; j++) {
alienY[j] += 5; // Move aliens down
}
break;
}
}
}

// Update missile position
void updateMissile() {
if (missileActive) {
missileY -= 2; // Move missile up
if (missileY < 0) {
missileActive = false; // Missile goes off screen
}

// Check for collision with aliens
for (int i = 0; i < maxAliens; i++) {
if (alienY[i] >= 0 && missileX >= alienX[i] && missileX <= alienX[i] + alienWidth &&
missileY >= alienY[i] && missileY <= alienY[i] + alienHeight) {
alienY[i] = -1; // Alien hit, remove it
missileActive = false; // Missile disappears
}
}
}
}

// Update player position based on joystick
void updatePlayer() {
joystickValueX = analogRead(joystickX);
playerX = map(joystickValueX, 0, 4095, 0, screenWidth - shipWidth);
}

// Handle button press to fire missile
void handleButton() {
int buttonState = digitalRead(buttonPin);

if (buttonState == HIGH && lastButtonState == LOW && !missileActive) {
// Fire a missile
missileX = playerX + shipWidth / 2;
missileY = screenHeight - shipHeight - 3;
missileActive = true;
}

lastButtonState = buttonState;
}

// Main loop
void loop() {
// Update game state
updatePlayer();
updateAliens();
updateMissile();
handleButton();

// Draw everything
u8g2.clearBuffer();
drawShip(playerX);
drawAliens();
drawMissile();
u8g2.sendBuffer(); // Refresh the screen

delay(50); // Control the game speed
}

 


The above code was then copied and pasted directly to the Arduino IDE 2.2. The only change to the Arduino IDE 2.2 that I needed to make was to install the U8g2, which is available in the Arduino library manager.

All comments and descriptions were automatically added by ChatGPT-4, no changes were made between copying and pasting this code into the Arduino IDE. 

There are other OLED libraries available for the type of screen defined in the prompt but this is what ChatGPT-4 specified in the code and therefore the library was downloaded and used without any changes.


4. The Results:

The ESP32 and other hardware were then wired as per the pins used in the code onto a breadboard. The ESP32 was connected with a USB C cable to a computer and the code was uploaded via the Arduino IDE. No errors were reported and the code was uploaded successfully to the ESP32 module.

Here is a video of the Space Invaders game in action:

Conclusion

Does it work....YES! 

Is it playable without any modification...YES!  

For ChatGPT-4 to be able to code a game from a short prompt in a few seconds is a vast improvement on the previous versions. The game obviously needs some tweaking, and can be made to look and handle better with some code changes. The size of the screen greatly limits what can be shown and affects the quality and shapes of the graphics but that is not a fault from ChatGPT-4's side.

Sorry for the shaky camera work in the video, it was a bit difficult recording with one hand while moving the joystick with the other, all while looking at the OLED screen. Hope you enjoyed the blog, Cheers!




No comments:

Post a Comment

The Great Inference Adventure: From Debugging Despair to Deployment Delight

Background, Be Gone: Running Inference with ONNX and U2Net Ever looked at an image and thought, “The background really ties this mess to...