diff --git a/Makefile b/Makefile index 50afafd..382b97b 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # ██║ ██║ ██║██████╔╝ █████╔╝██║ ██║ # ██║ ██║ ██║██╔══██╗ ╚═══██╗██║ ██║ # ╚██████╗╚██████╔╝██████╔╝██████╔╝██████╔╝ -# ╚═════╝ ╚═════╝ ╚═════╝ ╚ ╚═════╝ +# ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ # === general configuration === NAME = cub3D @@ -27,6 +27,12 @@ INC_DIR = -Iincludes -I$(LIBFT_DIR)/includes -I$(MLX_DIR) # === source files === SRC = src/main.c \ + src/events/cleanup_exit.c \ + src/events/events_handler.c \ + src/events/hooks.c \ + src/events/player_actions_rotate.c \ + src/events/player_actions_move.c \ + src/events/mouse_handler.c \ src/init/init_data.c \ src/init/init_mlx.c \ src/parsing/file_validations.c \ @@ -35,6 +41,7 @@ SRC = src/main.c \ src/render/draw_pixels.c \ src/parsing/player_setup.c \ src/parsing/player_setup_utils.c \ + src/utils/ascii_art.c \ src/utils/print_errors.c \ # object files preserving subdirectory structure diff --git a/includes/cub3d.h b/includes/cub3d.h index b5df856..74188fd 100644 --- a/includes/cub3d.h +++ b/includes/cub3d.h @@ -10,6 +10,7 @@ # include # include # include +# include /* =========================== */ /* DEFINE */ @@ -36,7 +37,7 @@ /* game elements */ # define WINDOWS_X 800 # define WINDOWS_Y 600 -# define WINDOWS_MSG "Welcome to cub3D" +# define WINDOWS_MSG "Welcome to CUB3D" /* =========================== */ /* STRUCTURES */ @@ -59,7 +60,18 @@ typedef struct s_map int ceiling_color; // rgb color for the ceiling, converted to int (0xRRGGBB) } t_map; -/* Represents the player’s state in the game */ +/* Tracks which keys are currently pressed */ +typedef struct s_keys +{ + bool w_pressed; + bool a_pressed; + bool s_pressed; + bool d_pressed; + bool left_arrow_pressed; + bool right_arrow_pressed; +} t_keys; + +/* Represents the player's state in the game */ typedef struct s_player { double pos_x; @@ -87,6 +99,10 @@ typedef struct s_game // === Game state === t_player player; // player data (position, direction, camera plane) t_map map; // map data (grid, size, textures paths, colors) + t_keys keys; // tracks which keys are currently pressed + // === Mouse === + int last_mouse_x; // last mouse X position for delta calculation + int last_mouse_y; // last mouse Y position for delta calculation } t_game; /* player orientation struct for the look up table */ @@ -99,50 +115,91 @@ typedef struct s_orientation double plane_y; } t_orientation; +/* key binding struct for mapping keys to actions */ +typedef struct s_key_binding +{ + int keycode; // X11 keycode for this specific key (ex: XK_w, XK_Left) + void (*action)(t_game *); // function pointer to the action that should be executed + bool *flag_ptr; // Pointer to the boolean flag that represents whether this key is currently pressed (true) or released (false) +} t_key_binding; + +/* =========================== */ +/* EVENT */ +/* =========================== */ + +/* cleanup_exit.c */ +void cleanup_exit(t_game *game); + +/* events handlers.c */ +int handle_keypress(int keycode, void *param); +int handle_keyrelease(int keycode, void *param); +int handle_close(void *param); +int game_loop(void *param); +t_key_binding *get_key_bindings(t_game *game); + +/* mouse_handler.c */ +int handle_mouse_move(int x, int y, void *param); + +/* hooks.c */ +void setup_hooks(t_game *game); + +/* player_actions_rotate.c */ +void rotate_left(t_game *game); +void rotate_right(t_game *game); + +/* player_actions_move.c */ +void move_forward(t_game *game); +void move_backward(t_game *game); +void strafe_left(t_game *game); +void strafe_right(t_game *game); + /* =========================== */ /* INIT */ /* =========================== */ /* init_data.c */ -void init_data(t_game *game); +void init_data(t_game *game); /* init_mlx.c */ -int init_game_data(t_game *game); +int init_game_data(t_game *game); /* =========================== */ /* PARSING */ /* =========================== */ /* file_validations.c */ -int validate_argument(char *filename); +int validate_argument(char *filename); /*parse_map.c */ -int parse_map(const char *path, t_map *map); +int parse_map(const char *path, t_map *map); /*parse_map_utils.c */ -int open_cub_file(const char *path); -void print_map_grid(t_map *map); -void free_map(t_map *map); -void free_partial_grid(t_map *map, int filled_rows); +int open_cub_file(const char *path); +void print_map_grid(t_map *map); +void free_map(t_map *map); +void free_partial_grid(t_map *map, int filled_rows); /* player_setup_utils.c */ -void print_player_info(t_player *player); +void print_player_info(t_player *player); /* player_setup.c */ -int init_player(t_game *game); +int init_player(t_game *game); /* =========================== */ /* RENDERS */ /* =========================== */ /* draw_pixels.c*/ -void draw_pixel_in_buffer(t_game *game, int x, int y, int color); +void draw_pixel_in_buffer(t_game *game, int x, int y, int color); /* =========================== */ /* UTILS */ /* =========================== */ +/* ascii art */ +void print_ascii_art_hello(void); + /* utils/print_errors.c */ -void print_errors(char *p1, char *p2, char *p3); +void print_errors(char *p1, char *p2, char *p3); #endif diff --git a/src/events/.gitkeep b/src/events/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/events/cleanup_exit.c b/src/events/cleanup_exit.c new file mode 100644 index 0000000..1d32822 --- /dev/null +++ b/src/events/cleanup_exit.c @@ -0,0 +1,27 @@ +#include "cub3d.h" + +/** + * @brief Cleans up all game resources and exits program + * + * Destroys MLX resources (image, window, display) and frees game data. + * Called when user presses ESC or clicks window close button. + * + * @param game Pointer to game structure +*/ +void cleanup_exit(t_game *game) +{ + if (!game) + exit(EXIT_FAILURE); + if (game->img) + mlx_destroy_image(game->mlx, game->img); + if (game->win) + mlx_destroy_window(game->mlx, game->win); + if (game->mlx) + { + mlx_destroy_display(game->mlx); + free(game->mlx); + } + if (game->map.grid) + free_map(&game->map); + exit(EXIT_SUCCESS); +} diff --git a/src/events/events_handler.c b/src/events/events_handler.c new file mode 100644 index 0000000..84edae2 --- /dev/null +++ b/src/events/events_handler.c @@ -0,0 +1,132 @@ +#include "cub3d.h" + +/** + * @brief Returns an array of key bindings mapping keycodes to actions + * + * This function returns a static array that maps X11 keycodes to their + * corresponding action functions and key state flags. + * + * @param game Pointer to game structure to access key flags + * @return Pointer to a static array of key bindings (NULL-terminated) + */ +t_key_binding *get_key_bindings(t_game *game) +{ + static t_key_binding bindings[7]; + + bindings[0] = (t_key_binding){XK_w, move_forward, &game->keys.w_pressed}; + bindings[1] = (t_key_binding){XK_s, move_backward, &game->keys.s_pressed}; + bindings[2] = (t_key_binding){XK_a, strafe_left, &game->keys.a_pressed}; + bindings[3] = (t_key_binding){XK_d, strafe_right, &game->keys.d_pressed}; + bindings[4] = (t_key_binding){XK_Left, rotate_left, + &game->keys.left_arrow_pressed}; + bindings[5] = (t_key_binding){XK_Right, rotate_right, + &game->keys.right_arrow_pressed}; + bindings[6] = (t_key_binding){0, NULL, NULL}; + return (bindings); +} + +/** + * @brief Handles key press events using function pointers + * + * Iterates through key bindings and sets the corresponding flag to true + * when a registered key is pressed. + * + * @param keycode X11 keycode of the pressed key + * @param param Pointer to game structure (void* from MLX, must cast) + * @return EXIT_SUCCESS + */ +int handle_keypress(int keycode, void *param) +{ + t_game *game; + const t_key_binding *bindings; + int i; + + game = (t_game *)param; + if (keycode == XK_Escape) + cleanup_exit(game); + bindings = get_key_bindings(game); + i = 0; + while (bindings[i].action) + { + if (bindings[i].keycode == keycode) + { + *bindings[i].flag_ptr = true; + return (EXIT_SUCCESS); + } + i++; + } + return (EXIT_SUCCESS); +} + +/** + * @brief Handles key release events using function pointers + * + * Iterates through key bindings and sets the corresponding flag to false + * when a registered key is released. + * + * @param keycode X11 keycode of the released key + * @param param Pointer to game structure (void* from MLX, must cast) + * @return EXIT_SUCCESS + */ +int handle_keyrelease(int keycode, void *param) +{ + t_game *game; + t_key_binding *bindings; + int i; + + game = (t_game *)param; + bindings = get_key_bindings(game); + i = 0; + while (bindings[i].action) + { + if (bindings[i].keycode == keycode) + { + *bindings[i].flag_ptr = false; + return (EXIT_SUCCESS); + } + i++; + } + return (EXIT_SUCCESS); +} + +/** + * @brief Handles window close button (red cross) event + * + * @param param Pointer to game structure (void* from MLX, must cast) + * @return 0/EXIT_SUCCESS (required by MLX) + */ +int handle_close(void *param) +{ + t_game *game; + + game = (t_game *)param; + cleanup_exit(game); + return (EXIT_SUCCESS); +} + +/** + * @brief Main game loop - called every frame by MLX (~60 FPS) + * + * Checks which keys are pressed and calls their corresponding action + * functions using the key bindings system. + * + * @param param Pointer to game structure (void* from MLX, must cast) + * @return EXIT_SUCCESS + */ +int game_loop(void *param) +{ + t_game *game; + t_key_binding *bindings; + int i; + + game = (t_game *)param; + bindings = get_key_bindings(game); + i = 0; + while (bindings[i].action) + { + if (*bindings[i].flag_ptr) + bindings[i].action(game); + i++; + } + return (EXIT_SUCCESS); +} diff --git a/src/events/hooks.c b/src/events/hooks.c new file mode 100644 index 0000000..b27ba14 --- /dev/null +++ b/src/events/hooks.c @@ -0,0 +1,18 @@ +#include "cub3d.h" + +/** + * @brief Registers all event hooks for the game window. + * + * Sets up keyboard press/release events, window close event, + * and mouse movement handling. These functions allow the game + * to react to player inputs during runtime. + * + * @param game Pointer to the game structure containing MLX window. + */ +void setup_hooks(t_game *game) +{ + mlx_hook(game->win, 2, 1L << 0, handle_keypress, game); + mlx_hook(game->win, 3, 1L << 1, handle_keyrelease, game); + mlx_hook(game->win, 17, 0, handle_close, game); + mlx_hook(game->win, 6, 1L << 6, handle_mouse_move, game); +} diff --git a/src/events/mouse_handler.c b/src/events/mouse_handler.c new file mode 100644 index 0000000..6b3f4e0 --- /dev/null +++ b/src/events/mouse_handler.c @@ -0,0 +1,40 @@ +#include "cub3d.h" + +/** + * @brief Handles mouse movement for horizontal camera rotation (stub) + * + * Detects horizontal mouse movement and logs rotation direction. + * Only handles left/right rotation (yaw), not up/down (pitch). + * Currently just logs debug messages, actual rotation logic to be implemented. + * + * @param x Current mouse X position in window coordinates + * @param y Current mouse Y position in window coordinates + * @param param Pointer to game structure (void* from MLX, must cast) + * @return EXIT_SUCCESS + */ +int handle_mouse_move(int x, int y, void *param) +{ + static int frame_count_left = 0; + static int frame_count_right = 0; + t_game *game; + int delta_x; + + game = (t_game *)param; + delta_x = x - game->last_mouse_x; + if (delta_x > 0) + { + frame_count_right++; + if (frame_count_right % 60 == 0) + printf("DEBUG: Mouse rotating RIGHT (frame %d)\n", + frame_count_right); + } + else if (delta_x < 0) + { + frame_count_left++; + if (frame_count_left % 60 == 0) + printf("DEBUG: Mouse rotating LEFT (frame %d)\n", frame_count_left); + } + game->last_mouse_x = x; + game->last_mouse_y = y; + return (EXIT_SUCCESS); +} diff --git a/src/events/player_actions_move.c b/src/events/player_actions_move.c new file mode 100644 index 0000000..0501528 --- /dev/null +++ b/src/events/player_actions_move.c @@ -0,0 +1,61 @@ +#include "cub3d.h" + +/** + * @brief Moves player forward in current direction + * + * @param game Pointer to game structure +*/ +void move_forward(t_game *game) +{ + static int frame_count = 0; + + (void)game; + frame_count++; + if (frame_count % 60 == 0) + printf("DEBUG: Moving FORWARD (frame %d)\n", frame_count); +} + +/** + * @brief Moves player backward (opposite of current direction) + * + * @param game Pointer to game structure +*/ +void move_backward(t_game *game) +{ + static int frame_count = 0; + + (void)game; + frame_count++; + if (frame_count % 60 == 0) + printf("DEBUG: Moving BACKWARD (frame %d)\n", frame_count); +} + +/** + * @brief Strafes player to the left (perpendicular to direction) + * + * @param game Pointer to game structure +*/ +void strafe_left(t_game *game) +{ + static int frame_count = 0; + + (void)game; + frame_count++; + if (frame_count % 60 == 0) + printf("DEBUG: Strafing LEFT (frame %d)\n", frame_count); +} + +/** + * @brief Strafes player to the right (perpendicular to direction) + * + * @param game Pointer to game structure +*/ +void strafe_right(t_game *game) +{ + static int frame_count = 0; + + (void)game; + frame_count++; + if (frame_count % 60 == 0) + printf("DEBUG: Strafing RIGHT (frame %d)\n", frame_count); +} diff --git a/src/events/player_actions_rotate.c b/src/events/player_actions_rotate.c new file mode 100644 index 0000000..35a6f6a --- /dev/null +++ b/src/events/player_actions_rotate.c @@ -0,0 +1,31 @@ +#include "cub3d.h" + +/** + * @brief Rotates camera to the left + * + * @param game Pointer to game structure +*/ +void rotate_left(t_game *game) +{ + static int frame_count = 0; + + (void)game; + frame_count++; + if (frame_count % 60 == 0) + printf("DEBUG: Rotating LEFT (frame %d)\n", frame_count); +} + +/** + * @brief Rotates camera to the right + * + * @param game Pointer to game structure +*/ +void rotate_right(t_game *game) +{ + static int frame_count = 0; + + (void)game; + frame_count++; + if (frame_count % 60 == 0) + printf("DEBUG: Rotating RIGHT (frame %d)\n", frame_count); +} diff --git a/src/init/init_data.c b/src/init/init_data.c index fdc18b1..1cafc73 100644 --- a/src/init/init_data.c +++ b/src/init/init_data.c @@ -16,4 +16,7 @@ void init_data(t_game *game) return ; // Zero out entire struct including any nested structs and its fields ft_bzero(game, sizeof(t_game)); + // Initialize mouse position to center of window + game->last_mouse_x = WINDOWS_X / 2; + game->last_mouse_y = WINDOWS_Y / 2; } diff --git a/src/main.c b/src/main.c index 2cc95c7..90fc97d 100644 --- a/src/main.c +++ b/src/main.c @@ -16,7 +16,11 @@ int main(int argc, char **argv) return (EXIT_FAILURE); if (init_game_data(&game) != EXIT_SUCCESS) return (EXIT_FAILURE); + print_ascii_art_hello(); print_map_grid(&game.map); - free_map(&game.map); + setup_hooks(&game); + mlx_loop_hook(game.mlx, game_loop, &game); + mlx_loop(game.mlx); + cleanup_exit(&game); return (EXIT_SUCCESS); } diff --git a/src/utils/ascii_art.c b/src/utils/ascii_art.c new file mode 100644 index 0000000..c86a58e --- /dev/null +++ b/src/utils/ascii_art.c @@ -0,0 +1,18 @@ +#include "cub3d.h" + +void print_ascii_art_hello(void) +{ + printf("Welcome to\n"); + printf(BR_GRN); + printf(" ██████╗██╗ ██╗██████╗ ██████╗ ██████╗\n"); + printf("██╔════╝██║ ██║██╔══██╗╚════██╗██╔══██╗\n"); + printf("██║ ██║ ██║██████╔╝ █████╔╝██║ ██║\n"); + printf("██║ ██║ ██║██╔══██╗ ╚═══██╗██║ ██║\n"); + printf("╚██████╗╚██████╔╝██████╔╝██████╔╝██████╔╝\n"); + printf(" ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚═════╝\n"); + printf(RESET); + printf(BR_YEL); + printf("use WASD to move - left/right arrow to rotate camera\n"); + printf("press ESC or click the top right window cross to exit game\n\n"); + printf(RESET); +}