zoss/Engine/Resources/MinimalGameClient

Zen Engine :: Resources :: Minimal Game Client

This resource shows you how to create a minimal game client without using the Base Starter Kit.

This resource is incomplete. Please complete it or remind me (Tony SgtFlame Richards) that it's incomplete and see if I have time to finish it.

Note: The Base Starter Kit gives you a lot of the "game engine" features of Zen Engine such as behaviors and some of the integration between physics and rendering, etc. Going this route is probably only a good idea if you need a severe subset (i.e. only rendering and possibly audio for simple games) or if you're capable of writing your own game engine. I don't want to discourage you from taking this route, but be forewarned that it's not an easy task and probably only quality, experienced C++ programmers should attempt it.

The examples included in this resource are taken from Starter/Base/GameClient/src/GameClient.cpp and Starter/Base/ZGameLoader/main.cpp. For the full examples, take a look at those two files to see how Zen Engine game client is normally initialized.

Register Application

The purpose of registering an application is to inform the plugin manager of details about the appliation, including plugins that the application requires as well as the paths where the plugin modules can be found.

There are two ways to register the application.

Config File

// Install the application
boost::filesystem::path configPath = boost::filesystem::system_complete
(
    boost::filesystem::path(argv[1], boost::filesystem::native)
).normalize();
Zen::Plugins::I_PluginManager::app_ptr_type pApp = 
    Zen::Plugins::I_PluginManager::getSingleton().installApplication(configPath);

Manual Application Registration

This code snippet shows some of the methods that you should call in order to do manual registration. TODO: Create a better example.

Zen::Plugins::I_PluginManager::getSingleton().setPluginPath(pluginPath);
Zen::Plugins::I_PluginManager::getSingleton().setModulePath(pluginPath);
Zen::Plugins::I_PluginManager::getSingleton().installPlugin(pluginName);

Note: I've not tested this. Please let me know if it doesn't work.

Load the Rendering Service

This code snippet shows an example loading the rendering service(untested, please let me know if it has problems)

    // Make sure you keep a reference to these services.  If you do not then they will be destroyed automatically
    m_pRenderingService = Rendering::I_RenderingManager::getSingleton().create("ogre");
    if (m_pRenderingService.isValid())
    {
        // Create the context
        m_pContext = m_pRenderingService->createContext(m_pParent);

        // Create the view
        m_pView = m_pRenderingService->createView(*m_pContext, _windowName, _width, _height);
    }
    else
    {
        // Error
        return false;
    }

Load the Rendering Resource Service

This code snippet shows an example loading the rendering resource service(untested, please let me know if it has problems)

    // Create the Rendering Resource service (I'm not sure what config needs to contain)
    m_pRenderingResourceService = 
        Resource::I_ResourceManager::getSingleton().create("ogre", config);

Load the Input Service

The Input Service is optional. This example only shows "keyboard" but in actuality initializing the keyboard also initializes the OIS keyboard and mouse, so there's no need to try to initialize the mouse. This behavior will change in the near future.

This code snippet shows an example loading the rendering resource service(untested, please let me know if it has problems)

    // Initialize the input service
    Input::I_InputServiceManager::config_type config;

    std::ostringstream window;

    // TODO This is not 64 bit portable
    window << (unsigned long)m_pContext->getWindow();

    config["WINDOW"] = window.str();

    m_pInputService = 
        Input::I_InputServiceManager::getSingleton().create("keyboard", config);

    m_pMainInputMap = m_pInputService->createInputMap("main");

Main Rendering Loop (Windows)

This was copied from BaseClient::run().

    getInputService().resumeEvents();

    FrameDelta_type delta = 0.0;

    // Get the current time
    initTimer();

    while(!m_quitting)
    {

        // Windows Message Loop (NULL means check all HWNDs belonging to this context)
        MSG  msg;
        while( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }

        // Increment the timer here; this gives us the least amount of time after 
        // handling the input
#define CLAMP

#ifdef CLAMP
        double elapsed = incrementTimer();
        // Clamp to 200 fps
        if(elapsed < (1.0 / 60.0))
        {
            int sleepTime = 1.0 / 60.0 - elapsed;
            if (sleepTime >= 0)
            {
                Threading::I_Thread::sleepForMilliseconds(sleepTime / 2);
                elapsed += incrementTimer();
            }
        }
#else
        double elapsed = incrementTimer();
#endif

        /// Give the input service a chance to process events
        m_pInputService->processEvents();

        onBeforeFrameRenderedEvent(elapsed);
        m_pRenderingCanvas->renderScene();
        onAfterFrameRenderedEvent(elapsed);

        Threading::I_Thread::sleepForMilliseconds(0);

    }