Páginas

quarta-feira, 1 de junho de 2016

Games in C++ can't be that hard, right? - YAML.

These last weeks I've been making some progress with the components and rendering system of the game engine. It is all so crude, but it's working and that makes me happy. I've managed to get a moveable first-person camera with a cube in the scene, reduce the amount of code needed to add a component to an entity and even got both orthographic and perspective camera projections!

Now, indeed, reinventing the wheel is totally unproductive. With the amount of code I've written here I could have doubled the amount of features in my last game prototype made in Unity. In this c++ project, I'm still at cube point.

Anyway, a friend has suggested me to try to make my rendering system in Vulkan – an idea that I grew fond of. But first, there are other things I want to do, and one of them is to avoid “rebuilds” every stupid test change such as screen resolution or, guess what, switching between OpenGL and Vulkan. As a starting point, it seems like a good idea to reduce “rebuilds” by tackling two areas:

- Components, which can be coded by scripting languages such as FalconPL or Lua
- Assets data.

Components scripting and FalconPL / Lua is too far away from me right now; I simply don't have any clue on how to set up them with my engine architecture and bind everything, and I can't tell if FalconPL is still alive as well. That leaves me figuring out only how to load assets data. It could be done with a scripting language, too, but the truth is that any kind of file reading technique will do.

In the past, in a restaurant simulator prototype, I've used JSON to store data for things such as food recipes or employees names. In that, there are many advantages like being able to store rules anywhere that allows storage of text, and they are readable enough to be written with any text editor. It'd be nice if these features were available for the engine assets information. If I write down what data I need, for example, to set up a texture and a material, I'd get something like the following:

Texture:
    - Name : HappyFace
    - File : HappyFace.png
    - WrapMode : Clamp

Material:
    - Name : UnlitHappyFace
    - Texture : HappyFace
    - Shader : TextureUnlit

It is really easy to write and to read, and it is also YAML. Sure, loading times will be way longer than if I were reading binary data, but then I can simply write a “stupid compiler” to make the binary files from the texts – if I ever come to need this performance. To read the files, I've used a small but elegant library called Yaml-Cpp. The rendering configuration file seemed a nice “hello world” practice. Here's how it turned out:

Video:
    - ScreenWidth : 800
    - ScreenHeight : 600
    - Renderer : OpenGL

The Yaml-Cpp is really easy to use. The code is clear and straight-forward, even with some (not all) error precautions. With some practice, the code should get even simpler.


void GameSettings::Load(std::string fileName)
{
    YAML::Node mainNode;

    try
    {
        mainNode = YAML::LoadFile(fileName);
    }
    catch (std::ifstream::failure e)
    {
        throw Engine::FailedToLoadException(std::string("Failed to load game configuration: file not successfully loaded."));
    }

    if (mainNode["Video"])
    {
        YAML::Node videoNode = mainNode["Video"];
        for (const auto& node : videoNode)
        {
            if (!node.first.IsScalar() || !node.second.IsScalar()) continue;

            if (node.first.as<std::string>() == "ScreenWidth")
            {
                m_ScreenWidth = node.second.as<int>();
            }

            if (node.first.as<std::string>() == "ScreenHeight")
            {
                m_ScreenHeight = node.second.as<int>();
            }

            if (node.first.as<std::string>() == "Renderer")
            {
                std::string renderer = node.second.as<std::string>();

                if (renderer == "OpenGL")
                {
                    m_GameRenderer = GameRenderer::OpenGL;
                }
                else if (renderer == "Vulkan")
                {
                    m_GameRenderer = GameRenderer::Vulkan;
                }
            }
        }
    }
}

Now I'll try to think in a way to store the assets meta data in disk. Again, I'll probably end up with something like in Unity 3d.


The code has been highlighted by hilite.me.

Nenhum comentário:

Postar um comentário