Custom User Events

Efficiently Handling Multiple Custom Event Types

What's the best way to handle multiple custom event types without cluttering my main event loop?

Abstract art representing computer programming

Handling multiple custom event types efficiently is crucial for maintaining clean and manageable code. Here are some strategies to keep your main event loop tidy:

1. Use a Switch Statement

For a small number of event types, a switch statement can be clean and efficient:

#include "UserEvents.h"
#include <SDL.h>

void HandleCustomEvent(const SDL_Event& event) {
  switch (event.type) {
  case UserEvents::PLAYER_MOVE:
    HandlePlayerMove(event.user);
    break;
  case UserEvents::ENEMY_SPAWN:
    HandleEnemySpawn(event.user);
    break;
  case UserEvents::COLLECT_ITEM:
    HandleItemCollection(event.user);
    break;
  // Add more cases as needed
  }
}

int main() {
  SDL_Init(SDL_INIT_EVERYTHING);
  SDL_Event event;
  bool quit{false};

  while (!quit) {
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) {
        quit = true;
      } else if (event.type >= SDL_USEREVENT) {
        HandleCustomEvent(event);
      } else {
        // Handle other SDL events
      }
    }
    // Game loop logic
  }

  SDL_Quit();
  return 0;
}

2. Use an Event Handler Map

For a larger number of event types, consider using a std::unordered_map to map event types to handler functions:

#include "UserEvents.h"
#include <SDL.h>
#include <functional>
#include <unordered_map>

using EventHandler =
std::function<void(const SDL_UserEvent&)>;

class EventManager {
private:
  std::unordered_map<Uint32, EventHandler>
  handlers;

public:
  void RegisterHandler(Uint32 eventType,
                       EventHandler handler) {
    handlers[eventType] = std::move(handler);
  }

  void HandleEvent(const SDL_Event& event) {
    if (event.type >= SDL_USEREVENT) {
      auto it = handlers.find(event.type);
      if (it != handlers.end()) {
        it->second(event.user);
      }
    }
  }
};

int main() {
  SDL_Init(SDL_INIT_EVERYTHING);
  SDL_Event event;
  bool quit{false};

  EventManager eventManager;
  eventManager.RegisterHandler(
      UserEvents::PLAYER_MOVE,
      [](const SDL_UserEvent& e) {
        /* Handle player move */
      });
  eventManager.RegisterHandler(
      UserEvents::ENEMY_SPAWN,
      [](const SDL_UserEvent& e) {
        /* Handle enemy spawn */
      });
  // Register more handlers as needed

  while (!quit) {
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) {
        quit = true;
      } else {
        eventManager.HandleEvent(event);
      }
    }
    // Game loop logic
  }

  SDL_Quit();
  return 0;
}

This approach allows you to keep your main loop clean and makes it easy to add or remove event handlers as your game evolves.

3. Use a Component-Based System

For more complex games, consider a component-based system where game objects handle their own events:

#include "UserEvents.h"
#include <SDL.h>
#include <vector>

class GameObject {
public:
  virtual void HandleEvent(
      const SDL_Event& event) = 0;
  virtual void Update() = 0;
  virtual ~GameObject() = default;
};

class Player : public GameObject {
public:
  void
  HandleEvent(const SDL_Event& event) override {
    if (event.type == UserEvents::PLAYER_MOVE) {
      // Handle player move
    }
  }

  void Update() override {
    /* Update player state */
  }
};

class Enemy : public GameObject {
public:
  void
  HandleEvent(const SDL_Event& event) override {
    if (event.type == UserEvents::ENEMY_SPAWN) {
      // Handle enemy spawn
    }
  }

  void Update() override {
    /* Update enemy state */
  }
};

int main() {
  SDL_Init(SDL_INIT_EVERYTHING);
  SDL_Event event;
  bool quit{false};

  std::vector<std::unique_ptr<GameObject>>
      gameObjects;
  gameObjects.push_back(
      std::make_unique<Player>());
  gameObjects.push_back(
      std::make_unique<Enemy>());

  while (!quit) {
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT) {
        quit = true;
      } else {
        for (auto& obj : gameObjects) {
          obj->HandleEvent(event);
        }
      }
    }
    for (auto& obj : gameObjects) {
      obj->Update();
    }
    // Render game objects
  }

  SDL_Quit();
  return 0;
}

This approach distributes event handling responsibilities among game objects, keeping your main loop clean and making your code more modular and easier to maintain as your game grows in complexity.

This Question is from the Lesson:

Custom User Events

Discover how to use the SDL2 event system to handle custom, game-specific interactions

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

Custom User Events

Discover how to use the SDL2 event system to handle custom, game-specific interactions

3D art representing computer programming
Part of the course:

Building Minesweeper with C++ and SDL2

Apply what we learned to build an interactive, portfolio-ready capstone project using C++ and the SDL2 library

Free, unlimited access

This course includes:

  • 37 Lessons
  • 100+ Code Samples
  • 92% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved