basic smooth movement

This commit is contained in:
Sven Balzer
2026-08-01 12:37:53 +02:00
parent f564c14354
commit 0c7ec7299e
+65 -11
View File
@@ -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(&current_time);
if (use_actual_time)