c++ 游戏引擎入口点

y1aodyip  于 2023-05-20  发布在  其他
关注(0)|答案(1)|浏览(185)

我在问自己,你如何在游戏引擎中实现一些东西,用户只需定义一个类并可以编译。也许让我用一些代码来详细说明,这只是游戏引擎的用户所做的:

#include <engine.h>

class game : engine::application
{
    void main_loop() override;
    void initialize() override;
    void destruct() override;
};

我如何实现它,游戏引擎可以被编译成一个库或各种包,引擎仍然能够访问一个示例或类似于这个游戏类的单例。所以首先你要编译引擎,然后才能在游戏中使用它。
我尝试了一个使用extern关键字的方法,用户只需定义一个这样的函数:

engine::application* get_game() {return new game();}

但它的使用相当混乱,就像我不知道为什么,但你必须写代码,使用这个函数在头文件中,原因当你编译代码在源文件中,它不会知道这个函数,并说未定义和东西。我也做了一些研究,但在这个问题上没有发现任何东西。

hrirmatl

hrirmatl1#

你可以从几个单元测试框架中获得灵感。通常有一些宏来定义测试用例。通常这些会导致创建一个全局对象,该对象访问存储有关已注册单元测试的信息的单例。(Boost测试和GoogleTest都是这样做的。
在你的例子中,你只需要为一个示例修改它,在游戏实现中你需要做的就是这样的事情(在这个演示中,application被简化为一个成员函数)。

game.cpp

#include <iostream>

#include "engine/engine.hpp"

class my_game : public engine::application
{
public:
    void DoSomething() override
    {
        std::cout << "Hello World!\n";
    }
};

ENGINE_GAME(my_game);

引擎实现

我在这里使用一个cmake项目,并假设使用MSVC for Windows(未测试其他编译器/系统)。

CMakeLists.txt

cmake_minimum_required(VERSION 3.16)

project(EngineDemo)

# use the same dir for dlls and exes to avoid issues with finding the dll
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

include(GenerateExportHeader)

add_library(engine SHARED engine.cpp include/engine/engine.hpp)
target_include_directories(engine PUBLIC include ${CMAKE_CURRENT_BINARY_DIR}/include)
generate_export_header(engine BASE_NAME include/engine/engine EXPORT_MACRO_NAME ENGINE_EXPORT)
target_sources(engine PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include/engine/engine_export.h)
target_compile_features(engine PUBLIC cxx_std_17)

add_executable(game game.cpp)
target_link_libraries(game PRIVATE engine)

engine.hpp

#ifndef ENGINE_ENGINE_HPP
#define ENGINE_ENGINE_HPP

#include <cassert>

#include "engine/engine_export.h"

int ENGINE_EXPORT main();

namespace engine
{
template<class T>
struct application_registrar;

class application;

// std::unique_ptr has no dll interface, so we implement our own
class ENGINE_EXPORT application_ptr
{
    application* m_ptr;
public:
    application_ptr(application* app = nullptr) noexcept
        : m_ptr(app)
    {
    }

    ~application_ptr();

    application_ptr(application_ptr&& other) noexcept
        : m_ptr(other.m_ptr)
    {
        other.m_ptr = nullptr;
    }

    application_ptr& operator=(application_ptr&& other) noexcept;

    explicit operator bool() const noexcept
    {
        return m_ptr != nullptr;
    }

    application* operator->() const noexcept
    {
        assert(m_ptr != nullptr);
        return m_ptr;
    }

    application& operator*() const noexcept
    {
        assert(m_ptr != nullptr);
        return *m_ptr;
    }

};

class ENGINE_EXPORT application
{
    template<class T>
    friend struct application_registrar;

    friend int ::main();

    static application_ptr s_applicationInstance;
public:
    virtual ~application() = 0;

    virtual void DoSomething() = 0;

    static application& instance() noexcept
    {
        [[maybe_unused]] bool const applicationAlreadyRegistered = static_cast<bool>(application::s_applicationInstance);
        assert(applicationAlreadyRegistered);
        return *s_applicationInstance;
    }
};

template<class T>
struct application_registrar
{
    application_registrar()
    {
        [[maybe_unused]] bool const applicationAlreadyRegistered = static_cast<bool>(application::s_applicationInstance);
        assert(!applicationAlreadyRegistered);
        try
        {
            application::s_applicationInstance = application_ptr(new T());
        }
        catch (...)
        {
            assert(!"an exception was thrown initializing the application");
            throw;
        }
    }
};

inline application_ptr::~application_ptr()
{
    delete m_ptr;
}

inline application_ptr& application_ptr::operator=(application_ptr&& other) noexcept
{
    delete m_ptr;
    m_ptr = other.m_ptr;
    other.m_ptr = nullptr;
    return *this;
}

} // namespace engine

/**
 * macro for registering the game
 */
#define ENGINE_GAME(type)                                                           \
namespace EngineGameRegistrationImpl                                                \
{                                                                                   \
static ::engine::application_registrar<type> g_gameRegistrator##type##__LINE__ ;    \
}

#endif // ENGINE_ENGINE_HPP

相关问题