Search code examples
c++game-enginegame-development

how to automatically generate a unique c++ class based on a file


let me preface this question by saying I have no idea if I'm asking the right question. I'm pretty new to c++ and I haven't gotten all of its nuances down yet, but I have coded in other OOP languages for nearly 7 years.

I originally asked: Is there a way to take a text file and automatically generate c++ code? If yes, how do I do that? What are some resources that explain the process?

but to clarify, what I really want is: Is there some way to take a text file, or other file type (like json) and use it to generate a compiled c++ class, or other compiled object, that can be interfaced with c++?

The final result doesn't need to be human readable, and it can be system specific. I want to be able to do this at compile time. It does not have to happen at run time. I will know at run time what classes I need. It's just that the classes I will be making (and there will be a lot of them) are all very similar, and just deviate in a few key places. So I want a way to tell the computer the important stuff (which may only take 5 or 6 lines of code), and have it generate the other 30 lines of boiler plate code.

I'm making a game engine, and I am trying to design a system that allows me to plug and play with systems, without having to write a lot of boiler plate code.

Someone commented that I should make the example simpler. So here goes.

I'm trying to build a system that takes a text file input and builds me a compiled c++ binary. It doesn't have to be a text file, and it doesn't have to be specifically c++, as long as it can interface with c++ (relatively easily). This is to decrease the amount of boiler plate code, and number of short kinda useless c++ files that are all almost identical.

For example having a file called example.txt which looks like this.

objectGenerator ExampleClass {
autofunction[hello world]
}

I would then hope to generate something that functions similarly to a c++ class like

class ExampleClass
{
public:
    void callAutoFunctions()
    {
        helloWorld();
    }

private:
    AutoFunction helloWorld;
};

then in my main.cpp for example I could call

void main()
{
    GeneratedClasses::ExampleClass exampleClass; 
    exampleClass.callAutoFunctions();
}

to print "hello world".

I want to be able to do this so I can make lots of different game objects that I can pull parts out of easily (by just changing one or two lines of text). It would make iterating over game ideas much easier, and in the long run would mean my games aren't the tangled mess of references and convoluted solutions to easy problems that they normally are.

I don't mind If I have to write a script in a different language than c++. It will make my indie game design career a lot easier if I could set this up now, and just use it for all my games in the future.

p.s. I'm trying to remake a game I created in python arcade over a year ago, but in c++ so it runs better, and I can actually create an exe file for the game that I can give to friends, or add to itch.io. I know that it is very bold of me to assume I will be able to make a viable, sellable game when I've coded in c++ for less than a year, but I am a task driven person and I wouldn't have the motivation to learn the c++ I need without doing something over the top like this.


Solution

  • It seems like all you want is separate compilation. Firstly, you make an interface for the part of your game you wish to make more decoupled:

    // Player.hpp
    
    #include <memory>
    
    struct IPlayer {
      virtual void run() = 0;
      virtual ~IPlayer() = default;
    };
    
    std::unique_ptr<IPlayer> getPlayer();
    

    Then use it in your program without supplying the implementation:

    // main.cpp
    
    #include "Player.hpp"
    
    int main() {
      auto player = getPlayer();
      player->run();
    }
    

    Then you compile it without linking:

    $ clang++ -c main.cpp -O3 -Wall -Wextra
    

    Now you work on your actual implementations:

    // FastPlayer.cpp
    
    #include "Player.hpp"
    
    struct FastPlayer : IPlayer {
      void run() override { /* ... */ }
    }
    
    std::unique_ptr<IPlayer> getPlayer() {
      return std::unique_ptr<IPlayer>{ new FastPlayer };
    }
    

    Then compile whichever implementation you wish to test now and link it with the binary you compiled previously:

    $ clang++ FastPlayer.cpp main.o -O3 -Wall -Wextra
    

    This way you can swap out the implementations easily to test a lot of functionality. It is safer than loading arbitrary code at run time.

    Ideally, you wouldn't do this manually and would have a build system like CMake handle it for you.