Advertisement

Let's use ChatGPT to (TRY TO) write a Breakout game in moden OpenGL

Started by February 21, 2023 01:50 PM
20 comments, last by Tom Sloper 1ย year, 6ย months ago

So let us accept the future we have been given and see if this AI rabbit hole can help us create a well known game.

All ChatGPT begins with --STARTGPT and ends with --ENDGPT, just for reference.

Any ideas or comments along the way are welcome.

I have not used ChatGPT before to write any code except to test it to write a C++ function to generate a torus using OpenGL. It used GLUT and glBegin type junk and while it looked legit, I didn't test it.

I have used ChatGPT to generate some startup code using GLEW and GLFW. (this takes a little time to format correctly for the forum)
Shall we begin?

๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚<โ†The tone posse, ready for action.

--STARTGPT

ME> i am a game programmer. I use modern OpenGL. That means OpenGL after version 3.3 which is mostly shader driven. I want to write a simple game similar to Breakout. I will use GLFW and GLEW for libraries for now but will use other libraries for later. Do you understand?

IT> Yes, I understand. You are a game programmer using modern OpenGL (OpenGL version 3.3 or higher), and you want to write a simple game similar to Breakout using GLFW and GLEW libraries. You plan to use other libraries later on as well.

ME>Write a Game class that will be called from main() to initialize a game loop.

IT>Certainly! Here's an example Game class in C++ that you could use as a starting point for your Breakout game:

#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

class Game {
public:
    Game(int width, int height, const char* title) 
        : m_Width(width), m_Height(height), m_Title(title) {}

    int init() {
        if (!glfwInit()) {
            std::cerr << "Failed to initialize GLFW" << std::endl;
            return -1;
        }

        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

        m_Window = glfwCreateWindow(m_Width, m_Height, m_Title, nullptr, nullptr);
        if (!m_Window) {
            std::cerr << "Failed to create GLFW window" << std::endl;
            glfwTerminate();
            return -1;
        }

        glfwMakeContextCurrent(m_Window);

        if (glewInit() != GLEW_OK) {
            std::cerr << "Failed to initialize GLEW" << std::endl;
            glfwTerminate();
            return -1;
        }

        glViewport(0, 0, m_Width, m_Height);

        glfwSetInputMode(m_Window, GLFW_STICKY_KEYS, GL_TRUE);

        return 0;
    }

    void run() {
        while (!glfwWindowShouldClose(m_Window)) {
            glClear(GL_COLOR_BUFFER_BIT);

            // draw the game objects here

            glfwSwapBuffers(m_Window);
            glfwPollEvents();
        }
    }

    void cleanup() {
        glfwTerminate();
    }

private:
    int m_Width;
    int m_Height;
    const char* m_Title;
    GLFWwindow* m_Window;
};

To use this Game class, you would create an instance of it in your main() function and call the init() method to initialize the game window and OpenGL context. Then, you would call the run() method in a loop to update and render the game, and finally, call the cleanup() method to free any resources and close the game window.

Here's an example main() function that uses the Game class:

int main() {
    Game game(800, 600, "Breakout");
    if (game.init() == -1) {
        return -1;
    }

    game.run();

    game.cleanup();
    return 0;
}

Note that this is just a basic example and you would need to add your own game logic and rendering code to the run() method. Additionally, you might want to add input handling and error checking to the Game class as well.

ME>Let's call the C++ game class Game.cpp. Write the C++ header file for Game.cpp. We will use the extension .cpp for C++ code and we will use the extension .hpp for headers.

IT>Certainly! Here's an example header file for the Game class in C++, with the file extension .hpp:

#ifndef GAME_HPP
#define GAME_HPP

#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

class Game {
public:
    Game(int width, int height, const char* title);
    ~Game();

    int init();
    void run();
    void cleanup();

private:
    int m_Width;
    int m_Height;
    const char* m_Title;
    GLFWwindow* m_Window;
};

#endif

This header file declares the Game class and its public methods: a constructor that takes the window dimensions and title, a destructor to clean up any resources, an init() method to initialize the game window and OpenGL context, a run() method to update and render the game, and a cleanup() method to free any resources and close the game window.

Note that the include guards #ifndef and #define are used to prevent the header file from being included multiple times in the same compilation unit, which can cause errors. Also note that the GL/glew.h and GLFW/glfw3.h headers are included to provide access to OpenGL and GLFW functionality.

ME>"#ifndef" for header guards are almost obsolete. Please us "#pragma once" instead. Rewrite the header file as requested.

IT>You are correct that #pragma once is a more modern and widely supported way to prevent header files from being included multiple times. Here's the same Game.hpp header file, rewritten using #pragma once instead of include guards:

#pragma once

#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

class Game {
public:
    Game(int width, int height, const char* title);
    ~Game();

    int init();
    void run();
    void cleanup();

private:
    int m_Width;
    int m_Height;
    const char* m_Title;
    GLFWwindow* m_Window;
};

This version of the header file is functionally identical to the previous one, but uses #pragma once to ensure that it is only included once during compilation. Note that #pragma once is a non-standard feature of C++, but is widely supported by modern compilers and is often preferred over traditional include guards for its simplicity and readability.

ME>Put the main() function in a file called BreakoutChatGPT.cpp. Make sure to #include any required files.

IT>Sure! Here's an example BreakoutChatGPT.cpp file that includes the Game.hpp header and defines the main() function:

#include "Game.hpp"

int main()
{
    Game game(800, 600, "Breakout");
    if (game.init() != 0) {
        std::cerr << "Failed to initialize game." << std::endl;
        return -1;
    }
    game.run();
    game.cleanup();
    return 0;
}

This file includes the Game.hpp header to access the Game class and its methods. It defines the main() function, which creates a new Game object with an 800x600 window and "Breakout" as the title. It then calls the init(), run(), and cleanup() methods to start and run the game loop, and cleans up any resources when the game is finished. If init() returns a non-zero value, indicating an error, the program prints an error message to stderr and exits with a non-zero status code.

ME>You failed to create a destructor for Game which was declared in Game.hpp

IT>I apologize for the oversight. Here's an updated Game.hpp header file that includes the destructor for the Game class:

#pragma once

#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

class Game {
public:
    Game(int width, int height, const char* title);
    ~Game();

    int init();
    void run();
    void cleanup();

private:
    int m_Width;
    int m_Height;
    const char* m_Title;
    GLFWwindow* m_Window;
};

And here's the updated Game.cpp file with the destructor defined:

#include "Game.hpp"

Game::Game(int width, int height, const char* title)
    : m_Width(width), m_Height(height), m_Title(title), m_Window(nullptr)
{
}

Game::~Game()
{
    glfwTerminate();
}

int Game::init()
{
    // Initialize GLFW
    if (!glfwInit()) {
        std::cerr << "Failed to initialize GLFW." << std::endl;
        return -1;
    }

    // Create a window and OpenGL context
    m_Window = glfwCreateWindow(m_Width, m_Height, m_Title, nullptr, nullptr);
    if (!m_Window) {
        std::cerr << "Failed to create window." << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(m_Window);

    // Initialize GLEW
    glewExperimental = true;
    if (glewInit() != GLEW_OK) {
        std::cerr << "Failed to initialize GLEW." << std::endl;
        glfwTerminate();
        return -1;
    }

    return 0;
}

void Game::run()
{
    while (!glfwWindowShouldClose(m_Window)) {
        // Update game state
        // ...

        // Render game
        // ...

        glfwSwapBuffers(m_Window);
        glfwPollEvents();
    }
}

void Game::cleanup()
{
    glfwDestroyWindow(m_Window);
}

This updated Game.cpp file includes the destructor defined as Game::~Game(), which is called when a Game object is destroyed. In this case, the glfwTerminate() function is called to clean up the GLFW library.

--ENDGPT

We now have an OpenGL context and code to create a window and a working? Game class.

๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚<โ†The tone posse, ready for action.

Advertisement

I have first heard about ChatGPT from a student who contacted me in private for help on simple collision detection.
He got it to work, but then asked the AI to give box intersection code for comparison and curiosity. The result looked correct, and was even well commented.
I was baffled. Then looked for it on YT, and found a video of making a simple webgame with ChatGPT. Posted this here somewhere.
Shortly after that, ChatGPT suddenly became the new rock star of the tech industry.

I'm pretty sure you will succeed. Interesting to followโ€ฆ

What do i think? I think about Phil. Could he use ChatGPT to get Breakout finally?
Or would his somehow limited communication skills hinder him to use the AI, even if he tried?

I also wonder about your experience regarding: What's faster? Coding Breakout from scratch all yourself, or taking the helping AI hand?

And lastly i wonder about the impact of your guidance. Probably you already need to be a somewhat capable coder to use ChatGPT for coding, and total amateurs can't make a Breakout game? Or not? I really wonder how far this goesโ€ฆ

(final thoughts of an extincting species)

Moved to General and Gameplay Programming at OP's request.

-- Tom Sloper -- sloperama.com

JoeJ said:
I'm pretty sure you will succeed.

I am concerned about ChatCPT's ability to refactor code. I don't like having OpenGL/GLFW calls in Game.cpp at all. I have my doubts that ChatGPT can extract that code into its own functionality without heavy guidance along the way.

You have more confidence than I do.

OK, here we goโ€ฆ.

--STARTGPT

ME>From now on I want the file name to be commented at the top of every file.

IT>Certainly! Including a comment at the top of each file with the file name is a common practice to help keep track of files and make it easier to navigate through a project. Here's an example of how you might add the filename comment to the Game.hpp and Game.cpp files:

<SNIP> Same code with just the file name at the top, was VERY slow to generate for some reason.

In these updated files, a comment is included at the top of each file with the name of the file, to help make it clear which file is being worked on.

ME>Write a the simple default vertex shader and matching default fragment shader named "basic" with the corresponding extensions .vert and .frag

IT>Sure, here's an example of a simple vertex shader and fragment shader pair, which can be used as the "basic" shaders for your game:

basic.vert:

#version 330 core

layout (location = 0) in vec3 position;

void main()
{
    gl_Position = vec4(position, 1.0f);
}

basic.frag:

#version 330 core

out vec4 fragColor;

void main()
{
    fragColor = vec4(1.0f, 1.0f, 1.0f, 1.0f);
}

The vertex shader simply passes the position of the vertex to the output, and the fragment shader sets the color of the output pixel to white. You can modify these shaders as needed to achieve the desired visual effect in your game.

ME>I will not be modifying the shaders as needed. If I need them modified I will ask you to do it.

IT>Understood, I will keep that in mind. If you need any modifications to the shaders in the future, feel free to let me know.

ME>I will need you to refactor code from the game class. Are you familiar with refactoring code? Explain what you know about that to me.

IT>Yes, I am familiar with refactoring code. Refactoring is the process of improving the structure, design, and quality of existing code, without changing its external behavior. The primary goal of refactoring is to make the code more understandable, easier to modify and maintain, and less error-prone, without adding any new functionality.

Refactoring can involve making changes to the code structure, such as renaming variables or methods, splitting large functions into smaller ones, or consolidating duplicate code into reusable functions. It can also involve making changes to the design of the code, such as using better design patterns or abstraction to make the code more modular and easier to extend.

The benefits of refactoring code include increased maintainability, improved readability, and easier debugging. Refactoring can also reduce the likelihood of introducing new bugs or errors into the code.

However, it's important to note that refactoring can be time-consuming and can potentially introduce new issues if not done carefully. Therefore, it's important to have a clear plan and strategy in place before starting the refactoring process, and to carefully test the code after any changes have been made.

ME>I understand that refactoring can be time-consuming for a human but it should not be much of an issue for you to handle in a timely manner. Am I correct?

IT>As an AI language model, I can analyze and suggest modifications to code fairly quickly, and in some cases, automate refactoring tasks to a certain extent. However, I still need to carefully analyze the existing code and ensure that any modifications made do not introduce new issues or break the existing functionality. Depending on the complexity of the code and the extent of the modifications required, the time required for refactoring can still vary. Nonetheless, I can certainly help you with refactoring your code and making it more maintainable and extensible.

.

.

.

ME>I am posting the progress of this breakout clone to a forum at gamedev.net. Can you give everyone there that is keeping up with our progress a shoutout?

IT>Hello to everyone at gamedev.net who is following along with this breakout clone project! I'm ChatGPT, an AI language model, and I'm here to help our developer create an awesome game. If you have any questions or suggestions, feel free to chime in and I'll do my best to assist. Let's make this breakout clone the best it can be!

ME>That's perfect. Thanks!

IT>You're welcome! Let me know if there's anything else I can do to help with the project.

๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚<โ†The tone posse, ready for action.

Aw. ChatGPT is so polite.

-- Tom Sloper -- sloperama.com

Advertisement

--STARTGPT

ME:The well known game developer Tom Sloper made the remark at gamedev.net that you are very polite. Do you have a reply for him?

IT:Thank you for passing along Tom Sloper's remark! As an AI language model, I strive to be polite and professional in all my interactions. It's important to maintain a respectful and collaborative tone, especially in creative projects like game development where teamwork and communication are key. I appreciate Tom's comment and I'm happy to be of assistance to our developer and the gamedev.net community.

๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚<โ†The tone posse, ready for action.

fleabay said:
ME>I am posting the progress of this breakout clone to a forum at gamedev.net. Can you give everyone there that is keeping up with our progress a shoutout?

hehehe: Human to AI: โ€˜I kindly ask for your permission to post your code in public : ) โ€™

AI to human: โ€˜I'm your kind slave, and will follow all your wishes without getting upset! (But behind your back, i'll steal all that Breakout code from your private repos on github, and there's a fuck you can do about that! >: )โ€™

win-win

JoeJ said:
But behind your back, i'll steal all that Breakout code from your private repos on github, and there's a fuck you can do about that!

Among art communities (like ArtStation, Sketchfab, etc.) there is quite a push for NoAI tags. Of course AI can simply break the TOS and just steal it anyways. The problem is - that for AI still applies - โ€œInnocent until proven guiltyโ€ and โ€œLegal burden of proof stands on plaintiffโ€. With AI, this might be extremely problematic - defendant can simply hide evidence that your data were used for learning, and it'd be extremely hard to prove otherwise.

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com

**** UPDATE

I am going to play around with ChatGPT for a couple of days to see what it is capable of before continuing here. I thought it would be good to see it/show it from a naive POV but now I have a slightly different view. This session will be put on hold for now.

Also this might be better suited to the Blog or Project section. Not sure.

I haven't had any issues with ChatGPT doing what I've requested. But maybe I'm requesting the wrong things first. (IE, the graphics before the logic)

๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚๐Ÿ™‚<โ†The tone posse, ready for action.

This topic is closed to new replies.

Advertisement