The Game class is the core entry point for Pyramid Engine applications. It manages the main game loop, graphics device initialization, and provides virtual methods for game-specific logic implementation.
namespace Pyramid {
class Game {
public:
explicit Game(GraphicsAPI api = GraphicsAPI::OpenGL);
virtual ~Game();
void run();
void quit();
protected:
virtual void onCreate();
virtual void onUpdate(float deltaTime);
virtual void onRender();
IGraphicsDevice* GetGraphicsDevice() const;
private:
std::unique_ptr<Window> m_window;
std::unique_ptr<IGraphicsDevice> m_graphicsDevice;
bool m_isRunning;
};
}Creates a new game instance with the specified graphics API.
Parameters:
api: The graphics API to use (defaults toGraphicsAPI::OpenGL)
Example:
// Use default OpenGL
class MyGame : public Pyramid::Game {
public:
MyGame() : Game() {} // Uses OpenGL by default
};
// Explicitly specify graphics API
class MyGame : public Pyramid::Game {
public:
MyGame() : Game(Pyramid::GraphicsAPI::OpenGL) {}
};Starts the main game loop. This method blocks until the game is quit.
void run();Example:
int main() {
MyGame game;
game.run(); // Blocks until game exits
return 0;
}Signals the game loop to stop gracefully.
void quit();Example:
void MyGame::onUpdate(float deltaTime) {
if (inputManager.IsKeyPressed(Key::Escape)) {
quit(); // Exit the game
}
}Called once when the game engine is first created. Override this method to initialize your game resources.
virtual void onCreate();Example:
void MyGame::onCreate() {
// Initialize game resources
auto* device = GetGraphicsDevice();
// Create shaders
m_shader = device->CreateShader();
m_shader->Compile(vertexSource, fragmentSource);
// Create geometry
CreateGameObjects();
// Setup camera
m_camera.SetPosition(Math::Vec3(0.0f, 5.0f, 10.0f));
m_camera.LookAt(Math::Vec3::Zero);
PYRAMID_LOG_INFO("Game initialized successfully");
}Called every frame to update game logic. Override this method to implement your game update logic.
Parameters:
deltaTime: Time elapsed since the last update in seconds
virtual void onUpdate(float deltaTime);Example:
void MyGame::onUpdate(float deltaTime) {
// Update game logic
m_player.Update(deltaTime);
m_enemies.Update(deltaTime);
// Update camera
UpdateCamera(deltaTime);
// Check game conditions
if (m_player.GetHealth() <= 0) {
GameOver();
}
}Called every frame to render the game. Override this method to implement your game rendering.
virtual void onRender();Example:
void MyGame::onRender() {
auto* device = GetGraphicsDevice();
// Clear the screen
device->Clear(Color(0.1f, 0.1f, 0.1f, 1.0f));
// Set up rendering state
m_shader->Bind();
m_shader->SetUniform("u_ViewProjection", m_camera.GetViewProjectionMatrix());
// Render game objects
m_player.Render(device);
m_enemies.Render(device);
m_environment.Render(device);
// Present the frame
device->Present(true); // Enable VSync
}Returns a pointer to the graphics device instance.
IGraphicsDevice* GetGraphicsDevice() const;Returns: Pointer to the graphics device
Example:
void MyGame::onCreate() {
auto* device = GetGraphicsDevice();
if (!device) {
PYRAMID_LOG_ERROR("Graphics device not available");
return;
}
// Use the graphics device
auto shader = device->CreateShader();
auto buffer = device->CreateVertexBuffer();
}The Game class supports multiple graphics APIs through the GraphicsAPI enumeration:
enum class GraphicsAPI {
OpenGL, // OpenGL 3.3-4.6 (currently supported)
DirectX9, // DirectX 9 (planned)
DirectX11, // DirectX 11 (planned)
DirectX12, // DirectX 12 (planned)
Vulkan // Vulkan (planned)
};The game loop follows a standard pattern:
- Initialization:
onCreate()is called once - Main Loop: Repeats until quit is called:
- Process window events
- Calculate delta time
- Call
onUpdate(deltaTime) - Call
onRender()
- Cleanup: Automatic resource cleanup on destruction
// Simplified game loop pseudocode
void Game::run() {
onCreate();
auto lastTime = std::chrono::high_resolution_clock::now();
while (m_isRunning) {
auto currentTime = std::chrono::high_resolution_clock::now();
float deltaTime = std::chrono::duration<float>(currentTime - lastTime).count();
lastTime = currentTime;
// Process window events
m_window->ProcessEvents();
// Update and render
onUpdate(deltaTime);
onRender();
}
// Cleanup happens in destructor
}Here's a complete minimal game implementation:
#include <Pyramid/Core/Game.hpp>
#include <Pyramid/Graphics/GraphicsDevice.hpp>
#include <Pyramid/Math/Math.hpp>
class HelloTriangleGame : public Pyramid::Game {
public:
HelloTriangleGame() : Game(Pyramid::GraphicsAPI::OpenGL) {}
protected:
void onCreate() override {
auto* device = GetGraphicsDevice();
// Create shader
m_shader = device->CreateShader();
const char* vertexSource = R"(
#version 330 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec3 a_Color;
uniform mat4 u_ViewProjection;
out vec3 v_Color;
void main() {
gl_Position = u_ViewProjection * vec4(a_Position, 1.0);
v_Color = a_Color;
}
)";
const char* fragmentSource = R"(
#version 330 core
in vec3 v_Color;
out vec4 o_Color;
void main() {
o_Color = vec4(v_Color, 1.0);
}
)";
m_shader->SetVertexSource(vertexSource);
m_shader->SetFragmentSource(fragmentSource);
m_shader->Compile();
// Create triangle vertices
float vertices[] = {
// Position // Color
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // Red
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // Green
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // Blue
};
m_vertexBuffer = device->CreateVertexBuffer();
m_vertexBuffer->SetData(vertices, sizeof(vertices));
// Set up vertex layout
Pyramid::BufferLayout layout = {
{Pyramid::ShaderDataType::Float3, "a_Position"},
{Pyramid::ShaderDataType::Float3, "a_Color"}
};
m_vertexBuffer->SetLayout(layout);
m_vertexArray = device->CreateVertexArray();
m_vertexArray->AddVertexBuffer(m_vertexBuffer);
// Setup camera
m_camera = Pyramid::Camera(
Pyramid::Math::Radians(60.0f),
1280.0f / 720.0f,
0.1f, 100.0f
);
m_camera.SetPosition(Pyramid::Math::Vec3(0.0f, 0.0f, 3.0f));
PYRAMID_LOG_INFO("Hello Triangle game created!");
}
void onUpdate(float deltaTime) override {
// Rotate triangle
m_rotation += deltaTime;
}
void onRender() override {
auto* device = GetGraphicsDevice();
device->Clear(Pyramid::Color(0.2f, 0.2f, 0.2f, 1.0f));
// Create rotation matrix
auto rotationMatrix = Pyramid::Math::Mat4::CreateRotationZ(m_rotation);
auto mvp = m_camera.GetViewProjectionMatrix() * rotationMatrix;
m_shader->Bind();
m_shader->SetUniform("u_ViewProjection", mvp);
m_vertexArray->Bind();
device->DrawArrays(3);
device->Present(true);
}
private:
std::shared_ptr<Pyramid::IShader> m_shader;
std::shared_ptr<Pyramid::IVertexBuffer> m_vertexBuffer;
std::shared_ptr<Pyramid::IVertexArray> m_vertexArray;
Pyramid::Camera m_camera;
float m_rotation = 0.0f;
};
// Entry point
int main() {
try {
HelloTriangleGame game;
game.run();
return 0;
} catch (const std::exception& e) {
PYRAMID_LOG_ERROR("Game crashed: ", e.what());
return 1;
}
}The Game class provides basic error handling:
void MyGame::onCreate() {
auto* device = GetGraphicsDevice();
if (!device) {
PYRAMID_LOG_ERROR("Failed to get graphics device");
quit(); // Exit gracefully
return;
}
// Continue with initialization...
}- Always use
deltaTimefor frame-rate independent updates - Clamp delta time to prevent large jumps (e.g., when debugging)
void MyGame::onUpdate(float deltaTime) {
// Clamp delta time to prevent physics issues
deltaTime = std::min(deltaTime, 1.0f / 30.0f); // Max 30 FPS minimum
// Use delta time for all updates
m_player.Move(velocity * deltaTime);
}- Initialize heavy resources in
onCreate() - Use smart pointers for automatic cleanup
- Avoid creating resources in the render loop
- Graphics Device API - Graphics device interface
- Window Management - Window and input handling
- Camera System - Camera management
- Shader System - Shader creation and management