Entity System Overview
The entity system is the core game object architecture in Cub3D. All interactive objects (players, enemies, walls, doors, items) inherit from the base t_entity structure.
Entity Type Hierarchy
t_entity (base)
├── t_wall
│ ├── t_door
│ └── t_elevator
├── t_billboard
│ ├── t_character
│ │ └── t_player
│ └── t_drop
└── (other specialized types)
Entity Type Enumeration
enum e_entity_type {
ENTITY, // Base entity
ENTITY_PLAYER, // Player-controlled character
ENTITY_WALL, // Static wall
ENTITY_DOOR, // Interactive door
ENTITY_BILLBOARD, // Sprite-based entity
ENTITY_DROP, // Item drop
ENTITY_CHARACTER, // NPC character
ENTITY_ELEVATOR // Map transition
};
Core Structures
Base Entity
The foundational entity structure all types inherit from.
struct s_entity {
// Lifecycle methods
void ( * frame)(t_game * game, t_entity * entity, double delta_time);
void ( * clear)( void * this);
// Interaction methods
void ( * action)(t_entity * entity, t_character * actioner);
void ( * shot)(t_entity * shooted, t_character * shooter);
// Controller (for AI/player input)
t_controller controller;
// Rendering flags
bool targetable; // Can be targeted by raycasts
bool transparent; // Rays pass through
bool ultra_mega_transparent; // Completely invisible to rays
bool no_transparency_for_bill; // Opaque for billboard rendering
// Health system
int max_health;
int health;
bool invencible;
// Physical properties
bool hard; // Solid collision
bool wall; // Is a wall entity
bool actionable; // Can be interacted with (E key)
bool billboard; // Is a billboard sprite
bool character; // Is a living character
// Identity
char identifier; // Map character representing this entity
bool active; // Currently active in game
// Transform
t_coords coords; // Position (x, y) and rotation (yaw)
t_dsize size; // Width and height
// Type information
t_entity_type type;
// Audio
t_fta_audio * collision_sound;
};
Called every frame to update entity state. Signature : void (*frame)(t_game *game, t_entity *entity, double delta_time)
game: Global game state
entity: This entity
delta_time: Seconds since last frame
Cleanup function to release resources before deallocation. Signature : void (*clear)(void *this)
Called when a character interacts with this entity (E key). Signature : void (*action)(t_entity *entity, t_character *actioner)Used for opening doors, picking up items, activating switches.
Called when this entity is hit by a weapon. Signature : void (*shot)(t_entity *shooted, t_character *shooter)
Controller
Handles AI and player input for entities.
struct s_controller {
// Control methods
void ( * key)(t_game * game, t_entity * entity, t_ftm_key_hook_values);
void ( * frame)(t_game * game, t_entity * entity, double delta_time);
// AI state
t_time last_shot;
t_time last_strafe;
t_time last_seen_target;
t_coords last_target_position;
t_entity * prev_target;
int prev_key;
double prev_angle;
double moving_to_angle;
double time_accumulator;
double optimal_proximity; // Preferred distance from target
// Movement state
bool walking_forward;
bool walking_left;
bool walking_backward;
bool walking_right;
bool looking_right;
bool looking_left;
bool sprinting;
bool action; // E key pressed
bool keyboard_only; // Disable mouse input
bool already_actioned; // Action handled this frame
// Look/movement parameters
double mouse_moviment;
double mouse_look_velocity;
double key_look_velocity;
double walk_velocity;
double sprint_velocity;
};
void enemy_ai_frame (t_game * game , t_entity * entity , double delta_time ) {
t_controller * ctrl = & entity -> controller ;
// Find player target
t_entity * target = find_nearest_player (game, entity);
if (target) {
// Calculate angle to target
double angle = atan2 (
target -> coords . y - entity -> coords . y ,
target -> coords . x - entity -> coords . x
);
// Rotate towards target
ctrl -> moving_to_angle = angle;
// Move forward
ctrl -> walking_forward = true ;
// Shoot if close enough
if ( distance_to (entity, target) < 5.0 ) {
shoot_weapon (entity);
}
}
}
Player Controller Example
void player_controller_key (t_game * game , t_entity * entity ,
t_ftm_key_hook_values key ) {
t_controller * ctrl = & entity -> controller ;
// Handle movement keys
if ( key . key == 'w' )
ctrl -> walking_forward = key . pressed ;
if ( key . key == 'a' )
ctrl -> walking_left = key . pressed ;
if ( key . key == 's' )
ctrl -> walking_backward = key . pressed ;
if ( key . key == 'd' )
ctrl -> walking_right = key . pressed ;
// Sprint
if ( key . key == K_SHIFT)
ctrl -> sprinting = key . pressed ;
// Action
if ( key . key == 'e' )
ctrl -> action = key . pressed ;
}
Entity Types
Billboard
Sprite-based entities rendered as flat images facing the camera.
struct s_billboard {
t_entity entity; // Inherits from entity
bool y_centered; // Center sprite vertically
t_sprite ** sprites; // 8-directional sprites (N, NE, E, SE, S, SW, W, NW)
};
Constructor : t_billboard *billboard_new(t_game *game, t_ftm_window *window, char identifier)
Sprites are directional - the appropriate sprite is selected based on the camera’s viewing angle.
Character
Living entities with health, inventory, and AI.
struct s_character {
t_billboard billboard; // Inherits from billboard
// Animation sprites
t_sprite ** using_sprite; // Weapon usage animation
t_sprite ** death_sprite; // Death animation
t_sprite ** hit_sprite; // Taking damage animation
t_sprite ** walking_sprite; // Walking animation
t_sprite ** _sprite; // Base sprite reference
// Timing
t_time last_hit;
t_time last_use; // Last weapon use
t_time last_auto_use; // Last auto-fire
// Audio
t_fta_audio * hit_sound;
t_fta_audio * death_sound;
// Targeting
t_entity * target_entity; // Current target
t_character * last_hit_by_character; // For revenge AI
t_direction target_entity_direction; // Direction to target
// Inventory
t_time last_inventory_scroll;
bool cheating; // God mode / infinite ammo
t_item * inventory [INVENTORY_SIZE];
t_drop * drop; // Associated item drop
bool drop_items; // Drop items on death
int inventory_index; // Selected slot (0-8)
char last_used_item_identifier;
// Camera (for players)
double fov;
int rays; // Ray count (screen width)
// Resources
int ammo;
int score;
// Death state
t_time died_at;
bool was_already_dead;
bool dead;
};
Constructor : t_character *character_new(t_game *game, t_ftm_window *window, char identifier)
inventory[INVENTORY_SIZE]
Array of item pointers. NULL entries represent empty slots. // Add item to first empty slot
for ( int i = 0 ; i < INVENTORY_SIZE; i ++ ) {
if ( character -> inventory [i] == NULL ) {
character -> inventory [i] = item;
break ;
}
}
Entity currently under the player’s crosshair. Used for:
Action prompts (“Press E to open”)
Weapon targeting
Interaction detection
Player
Player-controlled character with split-screen support.
struct s_player {
t_character character; // Inherits from character
t_ftm_image * canvas; // Player's viewport canvas
t_coords last_canvas_pos; // For split-screen layout
int controller_id; // Controller index (0-3)
bool friendly_fire; // Can damage other players
};
Constructor : t_player *player_new(t_game *game, t_ftm_window *window, char identifier)
Up to 4 players supported simultaneously. Each has an independent viewport rendered to canvas.
Wall
Static wall entities with directional textures.
struct s_wall {
t_entity entity; // Inherits from entity
t_sprite * north_sprite; // Texture for north-facing side
t_sprite * south_sprite; // Texture for south-facing side
t_sprite * west_sprite; // Texture for west-facing side
t_sprite * east_sprite; // Texture for east-facing side
};
Constructor : t_wall *wall_new(t_game *game, t_ftm_window *window, char identifier)
The appropriate sprite is selected based on which side the ray hits.
Door
Interactive door entities with animation.
struct s_door {
t_wall wall; // Inherits from wall
t_direction direction; // Door orientation (N/S/E/W)
// Sprites
t_sprite * opening_sprite; // Animation sequence
t_sprite * door_sprite; // Closed state
t_sprite * door_sides_sprite; // Perpendicular sides
// State
bool opened;
bool cant_close; // Door stuck open
bool closeable; // Can auto-close
t_time auto_close_delay; // Milliseconds until auto-close
t_time last_opened_at;
// Animation
int last_animation_index; // Current frame
t_time animation_delay; // Milliseconds per frame
int animation_frames; // Total frames in sequence
// Audio
t_fta_audio * open_sound;
t_fta_audio * close_sound;
};
Constructor : t_door *door_new_e(t_game *game, t_ftm_window *window, char identifier)
Player presses E near door
door_action() called
opened = true, last_opened_at = current_time
Each frame: advance last_animation_index
When animation complete: door fully open
After auto_close_delay: reverse animation, opened = false
bool door_is_transparent_at (t_entity * entity , t_direction direction , double x ) {
t_door * door = (t_door * )entity;
if ( ! door -> opened )
return false ; // Closed doors are solid
// Check if ray hits door edge vs open area
double door_width = 0.1 ; // Door thickness
if (x < door_width || x > ( 1.0 - door_width))
return false ; // Hit door frame
return true ; // Ray passes through open area
}
Elevator
Special wall that transitions between maps.
struct s_elevator {
t_wall wall; // Inherits from wall
char * map_path; // Path to destination map
};
Constructor : t_elevator *elevator_new(t_game *game, t_ftm_window *window, char identifier)
When a player activates an elevator, the entire game state is reloaded with the new map. All entities are destroyed and recreated.
Drop
Item pickups placed in the world.
struct s_drop {
t_billboard billboard; // Inherits from billboard
t_item * item; // Item contained in this drop
t_item * prev_item; // Previous item (for animation)
bool auto_use; // Auto-activate on pickup
bool auto_pickup; // Automatically pick up when touched
};
Constructor : t_drop *drop_new(t_game *game, t_ftm_window *window, char identifier)
When true, walking over the drop automatically adds it to inventory. When false, player must press E to pick up.
When true, item is immediately used instead of being added to inventory (e.g., health packs).
Entity Management
Entity List
All entities are stored in a linked list:
struct s_game {
t_list * entities; // Linked list of all active entities
// ...
};
Creating Entities
// Create entity from map identifier
t_type_creator creator = get_type_creator (game -> map -> identifiers , 'P' );
t_entity * entity = creator (game, window, 'P' );
// Add to entity list
ft_lstadd_back ( & game -> entities , ft_lstnew (entity));
Updating Entities
void call_entity_frames (t_game * game , t_fps * fps ) {
t_list * current = game -> entities ;
while (current) {
t_entity * entity = (t_entity * ) current -> data ;
if ( entity -> active && entity -> frame ) {
entity -> frame (game, entity, fps -> delta_time );
}
current = current -> next ;
}
}
Destroying Entities
void free_entity ( void * data ) {
t_entity * entity = (t_entity * )data;
// Call cleanup method
if ( entity -> clear )
entity -> clear (entity);
// Free memory
free (entity);
}
// Remove from list
ft_lstclear ( & game -> entities , free_entity);
Entity Factory Pattern
Entities are created via factory functions registered in the map’s identifier hashmap:
typedef void * ( * t_type_creator)(t_game * , t_ftm_window * , char );
// Register entity constructors
hashmap_insert (map -> identifiers , "P" , player_new); // Player spawn
hashmap_insert (map -> identifiers , "D" , door_new_e); // Door
hashmap_insert (map -> identifiers , "E" , elevator_new); // Elevator
hashmap_insert (map -> identifiers , "C" , character_new); // NPC
hashmap_insert (map -> identifiers , "I" , drop_new); // Item drop
Utility Functions
Entity Queries
headers/cub3d.h:520-537
headers/cub3d.h:515-519
src/utils/entities/entities.h:18-29
// Entity creation functions
t_player * player_new (t_game * game , t_ftm_window * window , char identifier );
t_wall * wall_new (t_game * game , t_ftm_window * window , char identifier );
t_door * door_new_e (t_game * game , t_ftm_window * window , char identifier );
t_billboard * billboard_new (t_game * game , t_ftm_window * window , char identifier );
t_entity * entity_new (t_game * game , t_ftm_window * window , char identifier );
t_drop * drop_new (t_game * game , t_ftm_window * window , char identifier );
t_character * character_new (t_game * game , t_ftm_window * window , char identifier );
t_elevator * elevator_new (t_game * game , t_ftm_window * window , char identifier );
See Also