Game Loop
The Game Loop is the core, continuously running cycle that drives the entire game forward. It's the heartbeat of the application. While implementations vary, a typical game loop performs these fundamental steps repeatedly, many times per second (aiming for 30, 60, or even higher frames per second):
Process Input: The engine checks for any input from the player (keyboard presses, mouse movements, controller buttons, touch events, etc.) or other sources (like network messages).
Update Game State (Logic/Simulation): This is where the game world changes based on input, time elapsed, AI, physics, and game rules.
Render Frame (Drawing): Based on the updated game state, the engine draws the visual representation of the scene onto the screen for the player to see.
Different game loop designs offer various trade-offs. This guide will use the "Play catch up" method, which divides the loop into "ticks" for updates and "frames" for rendering. TPS (ticks per second) establishes a fixed update rate, while FPS (frames per second) sets the target rendering rate. This decoupling means that the game's logic updates (TPS) and its visual presentation (FPS) are independent. A prime example is Minecraft, where a lagging TPS (often around 20) will only impact the simulation's speed, not the smoothness of the rendering.
#pragma once
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/System/String.hpp>
#include <cstdint>
#include "input.h"
#include "resource_manager.h"
namespace ng {
/// @brief The core application class, managing the game loop, window, resources, input, and scenes.
class App {
public:
/// @brief Constructs an App instance with the specified window size and title, ticks and frames per second.
/// @param window_size The initial size of the game window.
/// @param window_title The title of the game window.
/// @param tps The target ticks per second (game logic updates).
/// @param fps The target frames per second (rendering updates).
App(sf::Vector2u window_size, const sf::String& window_title, uint32_t tps,
uint32_t fps);
~App() = default;
App(const App& other) = delete;
App& operator=(const App& other) = delete;
App(App&& other) = delete;
App& operator=(App&& other) = delete;
/// @brief Runs the main game loop.
void Run();
/// @brief Returns the duration of a single game tick in seconds.
/// @return The time elapsed per tick.
[[nodiscard]] std::chrono::duration<float> SecondsPerTick() const;
/// @brief Returns the duration of a single game tick in nanoseconds.
/// @return The time elapsed per tick.
[[nodiscard]] std::chrono::nanoseconds NanosecondsPerTick() const;
/// @brief Returns a reference to the SFML RenderWindow.
/// @return A reference to the game window object.
[[nodiscard]] sf::RenderWindow& GetWindow();
/// @brief Returns a reference to the ResourceManager for managing game assets.
/// @return A reference to the ResourceManager.
[[nodiscard]] ResourceManager& GetResourceManager();
/// @brief Returns a constant reference to the Input manager.
/// @return A constant reference to the Input manager.
[[nodiscard]] const Input& GetInput() const;
private:
/// @brief Polls for SFML window events and updates the input state.
void PollInput();
// The main SFML render window.
sf::RenderWindow window_;
// Target ticks per second for game logic updates.
uint32_t tps_ = 0;
// Target frames per second for rendering.
uint32_t fps_ = 0;
// Manages game resources like textures and sounds.
ResourceManager resource_manager_;
// Handles user input events.
Input input_;
};
} // namespace ngLast updated