CodeWithAbdessamad

Game Development Basics

Simple Game Logic

In game development, game logic is the set of rules and behaviors that define how your game world responds to player input and internal state changes. It’s the “brain” of your game that transforms raw input into meaningful interactions. For beginners, starting with minimal, runnable logic is the most effective way to build confidence and understand core principles before tackling complex systems. Let’s break down the fundamentals through a concrete example.

Why Game Logic Matters for Beginners

Game logic bridges the gap between abstract concepts and tangible gameplay. Without it, your game will feel unresponsive or unpredictable. A well-structured game loop (the engine of your logic) ensures:

  • Consistent input processing
  • Predictable state transitions
  • Smooth frame-by-frame updates
  • Easy debugging through modular components

For instance, in a platformer game, your physics engine (part of game logic) must handle gravity, collisions, and jumping in a way that feels natural to players. Starting small helps you isolate these components without overwhelming complexity.

The Core Game Loop: Your Game’s Engine

Every game runs on a game loop—a continuous cycle that processes input, updates state, and renders output. This loop is your foundation for all gameplay. Here’s the minimal structure in C++:

<code class="language-cpp">while (gameActive) {
<p>    // 1. Handle input</p>
<p>    // 2. Update game state</p>
<p>    // 3. Render output</p>
<p>}</code>

This loop repeats at a consistent frame rate (typically 30–60 FPS), ensuring smooth gameplay. The key is to update state before rendering—this prevents visual glitches and ensures physics behave predictably.

Input Handling: The Player’s Voice

Input is how players interact with your game. For simplicity, we’ll use keyboard input with the SFML library (a lightweight, cross-platform toolkit perfect for beginners). Here’s how to capture input:

<code class="language-cpp">while (window.pollEvent(event)) {
<p>    if (event.type == sf::Event::CloseRequested) {</p>
<p>        gameActive = false;</p>
<p>    }</p>
<p>    // Additional input checks here (e.g., key presses)</p>
<p>}</code>

This code runs per frame to check for input events. Crucially, input should be handled in the game loop, not in the main body—this keeps your code responsive and decoupled.

Adding Movement Logic: A Concrete Example

Let’s build a simple game where a player-controlled rectangle moves left/right using arrow keys. This demonstrates:

  1. Input processing
  2. State updates
  3. Boundary constraints
  4. Frame-rate independence

Here’s the complete runnable code:

<code class="language-cpp">#include <SFML/Graphics.hpp>

<p>int main() {</p>
<p>    // Create window (800x600)</p>
<p>    sf::RenderWindow window(sf::VideoMode(800, 600), "Simple Game");</p>
<p>    </p>
<p>    // Player rectangle (50x50)</p>
<p>    sf::RectangleShape player(sf::Vector2f(50, 50));</p>
<p>    player.setFillColor(sf::Color::Red);</p>
<p>    player.setPosition(400, 300); // Start at center</p>

<p>    // Game state</p>
<p>    bool gameActive = true;</p>
<p>    float playerSpeed = 5.0f; // Pixels per frame</p>
<p>    float playerX = 400.0f;   // Current X position</p>

<p>    // Main loop</p>
<p>    while (gameActive) {</p>
<p>        // 1. Handle input</p>
<p>        sf::Event event;</p>
<p>        while (window.pollEvent(event)) {</p>
<p>            if (event.type == sf::Event::CloseRequested) {</p>
<p>                gameActive = false;</p>
<p>            }</p>
<p>        }</p>

<p>        // 2. Update game state</p>
<p>        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {</p>
<p>            playerX -= playerSpeed;</p>
<p>        }</p>
<p>        if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {</p>
<p>            playerX += playerSpeed;</p>
<p>        }</p>
<p>        </p>
<p>        // Prevent movement outside window</p>
<p>        if (playerX < 0) playerX = 0;</p>
<p>        if (playerX > 800 - 50) playerX = 800 - 50;</p>

<p>        // 3. Render</p>
<p>        window.clear();</p>
<p>        window.draw(player);</p>
<p>        window.display();</p>
<p>    }</p>

<p>    return 0;</p>
<p>}</code>

Key insights from this example:

  • sf::Keyboard::isKeyPressed() checks input per frame (critical for smooth movement)
  • Boundary checks (if (playerX < 0)) prevent visual artifacts
  • The player’s position is updated before rendering (ensures correct visuals)
  • This code runs in < 100 lines—perfect for beginners to modify

Game State Management: Scaling Up

While our example uses a single state (player position), real games need more complex state management. Here’s how to extend it:

  1. Use enums for state types (e.g., GameState):
<code class="language-cpp">   enum class GameState { Menu, Playing, GameOver };</code>

  1. Track state transitions (e.g., from Menu to Playing when a button is pressed):
<code class="language-cpp">   GameState currentState = GameState::Menu;</p>
<p>   if (playerPressedStartButton) {</p>
<p>       currentState = GameState::Playing;</p>
<p>   }</code>

  1. Update state in the loop:
<code class="language-cpp">   switch (currentState) {</p>
<p>       case GameState::Menu:</p>
<p>           // Handle menu logic</p>
<p>           break;</p>
<p>       case GameState::Playing:</p>
<p>           // Update player movement, collisions, etc.</p>
<p>           break;</p>
<p>       case GameState::GameOver:</p>
<p>           // Show game over screen</p>
<p>           break;</p>
<p>   }</code>

This pattern keeps your code modular and easy to debug—essential for larger projects.

Why This Approach Works for Real Projects

This simple game logic pattern scales beautifully:

  • Beginner-friendly: Starts with 100-line code that runs immediately
  • Frame-rate independent: Uses deltas (not fixed time intervals) for smooth movement
  • Extensible: Add physics, collisions, or AI without rewriting the loop
  • Debuggable: Clear separation of input, update, and render phases

For example, adding collision detection with a moving obstacle would only require:

  1. A new Obstacle class
  2. A collision check in the Playing state
  3. State updates (e.g., playerX = 0 on collision)

Summary

Simple game logic is the cornerstone of all interactive experiences. By mastering the game loop, input handling, and state updates—starting with a minimal example like the moving rectangle—you build a robust foundation. This approach ensures your code is runnable, debuggable, and scalable. Remember: small, focused logic wins in game development. 🎮