main_game_loop - ryzom/ryzomcore GitHub Wiki


title: Write a main game loop description: published: true date: 2023-05-27T22:08:50.893Z tags: editor: markdown dateCreated: 2023-03-26T20:24:46.424Z

We've just prepared a new personal project that initializes the NeL application context. This tutorial explains how to set up the NeL 3D graphics driver, implement a basic game loop, and handle window events.

Game Loop

Set up the graphics driver

Open the main.cpp file in your ryzomcore/personal folder, to include the necessary headers and add a member variable for the NL3D driver to the game class:

// Main game class
#include <nel/3d/u_driver.h>
class CDriver
{
public:
	CDriver();
	~CDriver();
	void run();

protected:
  NL3D::UDriver *m_Driver; // The graphic driver
};

In the constructor method, initialize the graphics driver and open a blank window.

To initialize the graphics driver, use the createDriver() method of the NL3D::UDriver class. If the driver cannot be created, display an error message using the nlerror() method.

Then initialize the window using the setDisplay() method of the driver. You can pass in a NL3D::UDriver::CMode object to specify the dimensions and color depth of the window. You can also set the window title using the setWindowTitle() method of the driver.

CDriver::CDriver()
{
	// Initialize the graphics driver
	m_Driver = NL3D::UDriver::createDriver();
	if (!m_Driver)
	{
		nlerror("Failed to create driver");
		return;
	}

	// Initialize the window
	m_Driver->setDisplay(NL3D::UDriver::CMode(800, 600, 32));

	// Set the window title
	m_Driver->setWindowTitle(ucstring("My Game"));
}

In the destructor, release any resources used.

CDriver::~CDriver()
{
	// Release the driver's resources
	m_Driver->release();
	delete m_Driver;
}

Implement a basic game loop in the run() method.

This loop should repeat until the window is closed or the application is exited. You must check the isActive() method of the graphics driver to verify if the window still exists. In order for the window to receive event messages, such as user input, from the window manager, the events will be received using the pump() method on the EventServer of the driver.

Use the clearBuffers() method of the driver to clear the screen with a specified color, and swapBuffers() to display the updated screen.

void CDriver::run()
{
	// Main driver loop
	while (m_Driver->isActive())
	{
		// Update window messages
		m_Driver->EventServer.pump();

		// Clear the screen
		m_Driver->clearBuffers(NLMISC::CRGBA(0, 0, 128));
    
		// Swap buffers
		m_Driver->swapBuffers();
	}
}

Now, compile and run your project. When running your project, you should see a blank window with the title "My Game". However, it will stay open when you try to close it.

Handle window events

To make the window close, you must register a listener for the relevant window event. Modify the game class to inherit from NLMISC::IEventListener. You'll also need a variable in your class to flag when the window is being closed. The release() call on the driver will define the behaviour when you ask the window to close.

class CDriver : public NLMISC::IEventListener
{
public:
	CDriver();
	~CDriver();
	void run();

	virtual void operator()(const NLMISC::CEvent &event) NL_OVERRIDE;

private:
	bool m_CloseWindow;

protected:
	NL3D::UDriver *m_Driver; // The graphic driver
};

Implement the event handler for the window close message, and update the main loop to exit when the close event has been flagged.

// Handle events
void CDriver::operator()(const NLMISC::CEvent &event)
{
	// Handle event
	if (event == NLMISC::EventCloseWindowId)
		m_CloseWindow = true;
}
void CDriver::run()
{
	// Main driver loop
	while (m_Driver->isActive() && !m_CloseWindow)
	{
		// ...
	}
}

Initialize the flag, and register the listener to handle the window close event.

CDriver::CDriver()
    : m_CloseWindow(false)
{
	// ...

	// Add event listeners
	m_Driver->EventServer.addListener(NLMISC::EventCloseWindowId, this);

	// Initialize the window
	// ...
}

The window should now remain open until you close it manually.

Source code

Here's the complete source of the tutorial project so far.

// Driver container class
#include <nel/3d/u_driver.h>
class CDriver : public NLMISC::IEventListener
{
public:
	CDriver();
	~CDriver();
	void run();

	virtual void operator()(const NLMISC::CEvent &event) NL_OVERRIDE;

private:
	bool m_CloseWindow;

protected:
	NL3D::UDriver *m_Driver; // The graphic driver
};

// Initialize game resources
CDriver::CDriver()
	: m_CloseWindow(false)
{
	// Initialize the graphics driver
	m_Driver = NL3D::UDriver::createDriver();
	if (!m_Driver)
	{
		nlerror("Failed to create driver");
		return;
	}

	// Add event listeners
	m_Driver->EventServer.addListener(NLMISC::EventCloseWindowId, this);

	// Initialize the window
	m_Driver->setDisplay(NL3D::UDriver::CMode(800, 600, 32));

	// Set the window title
	m_Driver->setWindowTitle(ucstring("My Game"));
}

// Release game resources
CDriver::~CDriver()
{
	// Release the driver's resources
	m_Driver->release();
	delete m_Driver;
}

// Main loop
void CDriver::run()
{
	// Main driver loop
	while (m_Driver->isActive() && !m_CloseWindow)
	{
		// Update window messages
		m_Driver->EventServer.pump();

		// Clear the screen
		m_Driver->clearBuffers(NLMISC::CRGBA(0, 0, 128));

		// Swap buffers
		m_Driver->swapBuffers();
	}
}

// Handle events
void CDriver::operator()(const NLMISC::CEvent &event)
{
	// Handle event
	if (event == NLMISC::EventCloseWindowId)
		m_CloseWindow = true;
}

// Main function
int main(int argc, char *argv[])
{
	// Create the application context
	CApplicationContext applicationContext;

	// Defining the game
	CDriver myGame;

	// Run the game
	myGame.run();

	return EXIT_SUCCESS;
}

At this point, you should have set up a personal NeL project, configured CMake, initialized the NeL 3D driver, opened a blank window, and implemented a basic game loop.

What's next

⚠️ **GitHub.com Fallback** ⚠️