diff --git a/src/main.cpp b/src/main.cpp index 6891baa..89462f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -71,6 +71,7 @@ static mat4x4 inverse_view_matrix; static mat4x4 projection_matrix; static mat4x4 inverse_projection_matrix; +static SDL_Time last_time; static SDL_Time current_time; static bool enable_time_tints = true; @@ -89,6 +90,8 @@ static bool show_demo_window; static bool show_tile_picker; static bool show_settings; +static float character_speed = 4.0f; + #define log_error(...) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, __VA_ARGS__) float remap(float in_a, float in_b, float out_a, float out_b, float v) { @@ -204,6 +207,10 @@ static Map current_map; struct Player { i32vec2 position; + i32vec2 target_position; + + bool is_moving; + vec2 visual_position; }; static Player player; @@ -219,6 +226,13 @@ struct alignas(16) PerFrame { static PerFrame per_frame = {}; +typedef enum : Uint8 { + DIR_DOWN, + DIR_UP, + DIR_LEFT, + DIR_RIGHT, +} Direction; + typedef enum : Uint8 { TILEKIND_ERROR = 0, TILEKIND_NONE = 1, @@ -402,6 +416,9 @@ static bool dragging_tile_change; static bool dragging_camera_change; static vec2 drag_start_pos; +static bool queued_movement; +static Direction queued_movement_direction; + static R_Texture create_texture(const char *path) { char path_to_load[256] = ASSETS_PATH; SDL_strlcat(path_to_load, path, SDL_arraysize(path_to_load)); @@ -1357,20 +1374,26 @@ static void process_event_game(SDL_Event event) { switch (event.type) { case SDL_EVENT_KEY_DOWN: { + if (event.key.repeat) return; + if (event.key.key == SDLK_UP || event.key.key == SDLK_W) { - player.position.y = clamp(0, player.position.y + 1, current_map.size.y - 2); + queued_movement = true; + queued_movement_direction = DIR_UP; } if (event.key.key == SDLK_LEFT || event.key.key == SDLK_A) { - player.position.x = clamp(0, player.position.x - 1, current_map.size.x - 2); + queued_movement = true; + queued_movement_direction = DIR_LEFT; } if (event.key.key == SDLK_DOWN || event.key.key == SDLK_S) { - player.position.y = clamp(0, player.position.y - 1, current_map.size.y - 2); + queued_movement = true; + queued_movement_direction = DIR_DOWN; } if (event.key.key == SDLK_RIGHT || event.key.key == SDLK_D) { - player.position.x = clamp(0, player.position.x + 1, current_map.size.x - 2); + queued_movement = true; + queued_movement_direction = DIR_RIGHT; } if (event.key.key == SDLK_F9) { @@ -1380,19 +1403,23 @@ static void process_event_game(SDL_Event event) { case SDL_EVENT_GAMEPAD_BUTTON_DOWN: { if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_UP) { - player.position.y = clamp(0, player.position.y + 1, current_map.size.y - 2); + queued_movement = true; + queued_movement_direction = DIR_UP; } if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_LEFT) { - player.position.x = clamp(0, player.position.x - 1, current_map.size.x - 2); + queued_movement = true; + queued_movement_direction = DIR_LEFT; } if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_DOWN) { - player.position.y = clamp(0, player.position.y - 1, current_map.size.y - 2); + queued_movement = true; + queued_movement_direction = DIR_DOWN; } if (event.gbutton.button == SDL_GAMEPAD_BUTTON_DPAD_RIGHT) { - player.position.x = clamp(0, player.position.x + 1, current_map.size.x - 2); + queued_movement = true; + queued_movement_direction = DIR_RIGHT; } } break; } @@ -1401,6 +1428,32 @@ static void process_event_game(SDL_Event event) { static void update_state_game() { ZoneScopedN("update_state_game"); + SDL_Time delta_time = current_time - last_time; + float delta_t = delta_time / (float)SDL_NS_PER_SECOND; + + const bool *keyboard_state = SDL_GetKeyboardState(NULL); + + if (player.is_moving) { + vec2 leftover_movement = vec2(player.target_position) - player.visual_position; + vec2 movement = clamp(min(vec2(0, 0), leftover_movement), normalize(leftover_movement) * (delta_t * character_speed * (keyboard_state[SDL_SCANCODE_LSHIFT] ? 2.0f : 1.0f)), max(vec2(0, 0), leftover_movement)); + player.visual_position += movement; + + if (movement == leftover_movement) { + player.is_moving = false; + player.position = player.target_position; + } + } + + if (!player.is_moving && (queued_movement || keyboard_state[SDL_SCANCODE_W] || keyboard_state[SDL_SCANCODE_A] || keyboard_state[SDL_SCANCODE_S] || keyboard_state[SDL_SCANCODE_D])) { + switch (queued_movement_direction) { + case DIR_UP: { player.target_position = player.position + ivec2( 0, 1); if (player.target_position != player.position) player.is_moving = true; } break; + case DIR_LEFT: { player.target_position = player.position + ivec2(-1, 0); if (player.target_position != player.position) player.is_moving = true; } break; + case DIR_DOWN: { player.target_position = player.position + ivec2( 0, -1); if (player.target_position != player.position) player.is_moving = true; } break; + case DIR_RIGHT: { player.target_position = player.position + ivec2( 1, 0); if (player.target_position != player.position) player.is_moving = true; } break; + } + } + queued_movement = false; + if (!MIX_TrackPlaying(music_track)) { MIX_SetTrackAudio(music_track, music_setting_off_piano); MIX_PlayTrack(music_track, 0); @@ -1414,7 +1467,7 @@ static void render_game() { ZoneScopedN("update buffers"); { ZoneScopedN("player_instance_buffer"); - player_instance.pos = player.position; + player_instance.pos = player.visual_position; renderer_buffer_update(player_instance_buffer, 0, sizeof(player_instance), &player_instance); } @@ -1424,8 +1477,8 @@ static void render_game() { float aspect_ratio = ((float)window_size.x / (float)window_size.y); - view_matrix = view (vec3(player.position, 0), radians(camera_tilt), camera_distance); - inverse_view_matrix = inverse_view(vec3(player.position, 0), radians(camera_tilt), camera_distance); + view_matrix = view (vec3(player.visual_position, 0), radians(camera_tilt), camera_distance); + inverse_view_matrix = inverse_view(vec3(player.visual_position, 0), radians(camera_tilt), camera_distance); projection_matrix = projection (radians(camera_fovy_degrees), aspect_ratio, NEAR_PLANE); inverse_projection_matrix = inverse_projection(radians(camera_fovy_degrees), aspect_ratio, NEAR_PLANE); @@ -1530,6 +1583,7 @@ static void process_events() { static void update_state() { ZoneScopedN("update_state"); + last_time = current_time; SDL_GetCurrentTime(¤t_time); if (use_actual_time)