The Entity System provides a robust and flexible framework for managing all game entities, including players, NPCs, and dynamic objects. It uses a Data-Oriented Design (DoD) approach with the EntityDataManager as the single source of truth for all entity data, combined with lightweight EntityHandle references and a state machine pattern for managing behaviors.
- EntityDataManager Integration
- EntityHandle System
- Simulation Tiers
- Core Entity Structure
- Entity States
- Entity State Machines
- Player Entities
- NPC Entities
- API Reference
- Best Practices
- Related Documentation
All entity data is stored centrally in EntityDataManager using Structure-of-Arrays (SoA) layout for cache-optimal access:
Key features:
- Single source of truth (eliminates 4x position duplication)
- Cache-optimal 64-byte
EntityHotDatastructs (one cache line) - Thread-safe index-based accessors for parallel batch processing
- Type-specific data blocks (CharacterData, ItemData, ProjectileData)
- Supports 100K+ entities with tiered simulation
Where to find the code:
- Header:
include/managers/EntityDataManager.hpp - Implementation:
src/managers/EntityDataManager.cpp
// Entity creation via EDM
auto& edm = EntityDataManager::Instance();
EntityHandle npc = edm.createNPC(position, EntityKind::NPC);
// Data access via handle
auto& hotData = edm.getHotData(npc);
auto& transform = edm.getTransform(npc);EntityHandle provides lightweight, type-safe entity references without RTTI.
See: EntityHandle Documentation for complete API reference.
Key features:
- 16-byte struct suitable for passing by value
EntityKindenum for fast type checking- Generation counter for stale reference detection
- Replaces raw pointers and EntityID lookups
Where to find the code:
- Header:
include/entities/EntityHandle.hpp
struct EntityHandle {
EntityID id; // Unique identifier
EntityKind kind; // Type without RTTI
uint8_t generation; // Stale reference detection
[[nodiscard]] bool isValid() const noexcept;
[[nodiscard]] bool isNPC() const noexcept;
[[nodiscard]] bool isPlayer() const noexcept;
};enum class EntityKind : uint8_t {
Player, NPC, // Characters (have health, AI)
DroppedItem, Container, Harvestable, // Interactables
Projectile, AreaEffect, // Combat (short-lived)
Prop, Trigger, // Environment
StaticObstacle // World geometry
};Entities are assigned to simulation tiers based on distance from camera/player:
| Tier | Processing | Use Case |
|---|---|---|
| Active | Full AI, collision, render | Near camera (visible) |
| Background | Position-only @ 10Hz | Off-screen but nearby |
| Hibernated | No updates, data stored | Far away |
enum class SimulationTier : uint8_t {
Active = 0, // Full update every frame
Background = 1, // Simplified updates at 10Hz
Hibernated = 2 // No updates, data only
};Tier management:
BackgroundSimulationManagerhandles tier reassignment every 60 frames- Active tier entities processed by AIManager, CollisionManager
- Background tier entities processed by BackgroundSimulationManager
Entities in the Hammer Engine are built upon a base Entity class, which provides fundamental properties and functionalities common to all game objects.
Key features:
- EntityHandle for EDM integration
- Position, velocity, acceleration (stored in EDM)
- Dimensions (width, height)
- Basic rendering capabilities
- State machine integration
Where to find the code:
- Header:
include/entities/Entity.hpp - Implementation:
src/entities/Entity.cpp
Entities utilize a state machine pattern to manage their current actions and behaviors. This provides a clear, modular way to define how an entity behaves in different contexts (e.g., idle, walking, attacking, dying).
See also: Entity States for detailed documentation on available NPC and Player states.
Each entity (Player, NPC) maintains its own state machine, which manages transitions between different states. The state machine ensures that entities only move between valid states and handles the entry and exit logic for each state.
Key features:
- Current state management
- State transition logic
- Entry and exit actions for states
- Event-driven state changes
Where to find the code:
- Base State:
include/entities/EntityState.hpp - State Manager:
include/managers/EntityStateManager.hpp
The Player class extends the base Entity to provide player-specific functionalities, including input handling, player-specific states, and interaction with game systems.
Key features:
- Input-driven movement and actions
- Player-specific state machine
- Inventory management
- Interaction with UI
Where to find the code:
- Header:
include/entities/Player.hpp - Implementation:
src/entities/Player.cpp
The NPC (Non-Player Character) class extends the base Entity to provide functionalities for AI-controlled characters. NPCs integrate with the AIManager for behavior management and have their own set of states.
Key features:
- AI-driven behaviors (Wander, Patrol, Attack, etc.)
- NPC-specific state machine
- Health and combat attributes
- Interaction with environment
Where to find the code:
- Header:
include/entities/NPC.hpp - Implementation:
src/entities/NPC.cpp
struct EntityHandle {
EntityID id;
EntityKind kind;
uint8_t generation;
[[nodiscard]] bool isValid() const noexcept;
[[nodiscard]] bool isNPC() const noexcept;
[[nodiscard]] bool isPlayer() const noexcept;
[[nodiscard]] EntityKind getKind() const noexcept;
};class EntityDataManager {
public:
static EntityDataManager& Instance();
// Entity creation
EntityHandle createNPC(const Vector2D& position, EntityKind kind);
EntityHandle createPlayer(const Vector2D& position);
// Data access (by handle)
EntityHotData& getHotData(EntityHandle handle);
TransformData& getTransform(EntityHandle handle);
// Index-based access (for batch processing)
EntityHotData& getHotDataByIndex(uint32_t edmIndex);
TransformData& getTransformByIndex(uint32_t edmIndex);
// Handle validation
[[nodiscard]] bool isValidHandle(EntityHandle handle) const;
[[nodiscard]] uint32_t getEdmIndex(EntityHandle handle) const;
};class Entity {
public:
Entity(const std::string& textureId, const Vector2D& position, int width, int height);
virtual ~Entity() = default;
virtual void update(float deltaTime);
virtual void render(SDL_Renderer* renderer, float cameraX, float cameraY, float interpolationAlpha);
[[nodiscard]] EntityHandle getHandle() const;
[[nodiscard]] const Vector2D& getPosition() const;
void setPosition(const Vector2D& position);
};class Player : public Entity {
public:
Player(const std::string& textureId, const Vector2D& position, int width, int height);
void handleInput(const SDL_Event& event);
void update(float deltaTime) override;
};class NPC : public Entity {
public:
NPC(const std::string& textureId, const Vector2D& position, int width, int height);
void update(float deltaTime) override;
[[nodiscard]] EntityHandle getHandle() const;
};- Use EntityDataManager: All entity data should flow through EDM. Never cache position data locally when EDM is the source of truth.
- Use EntityHandle: Pass handles by value instead of raw pointers. Validate with
isValid()before accessing data. - Tier-Aware Processing: Check entity tier before expensive operations. Background/Hibernated entities should skip full AI/collision.
- Index-Based Batch Processing: For parallel processing, use
getHotDataByIndex()with pre-cached indices to avoid map lookups. - State-Driven Logic: Implement entity-specific logic within their states to maintain modularity and prevent tangled code.
- Event-Driven Interactions: Use the
EventManagerfor communication between entities and other game systems (e.g.,CombatEventfor combat).
// GOOD - Use EDM for position data
auto& transform = EntityDataManager::Instance().getTransform(handle);
transform.position = newPosition;
// BAD - Local position copy becomes stale
Vector2D localPos = entity->getPosition(); // May diverge from EDM- Entity States:
EntityStates.md- Detailed documentation for all entity states. - EntityDataManager:
../managers/EntityDataManager.md- Central data authority for all entities. - BackgroundSimulationManager:
../managers/BackgroundSimulationManager.md- Off-screen entity simulation. - AIManager:
../ai/AIManager.md- AI behavior management for NPCs. - CombatController:
../controllers/CombatController.md- Combat logic and event handling. - EventManager:
../events/EventManager.md- Global event system. - GameStates:
../gameStates/README.md- Managing different game modes.