From 90bbad09aee5c411532d6122e1add3d552b767e7 Mon Sep 17 00:00:00 2001 From: En Yi Date: Sat, 17 Aug 2024 14:49:51 +0800 Subject: [PATCH] Add free-movement to camera in editor scene --- scenes/camera_systems.c | 106 ++++++++++++++++++++++++---------------- scenes/editor_scene.c | 5 ++ scenes/scene_impl.h | 7 +++ scenes/scene_systems.c | 1 + 4 files changed, 78 insertions(+), 41 deletions(-) diff --git a/scenes/camera_systems.c b/scenes/camera_systems.c index 9854e3e..dcaef3f 100644 --- a/scenes/camera_systems.c +++ b/scenes/camera_systems.c @@ -10,49 +10,62 @@ void camera_update_system(Scene_t* scene) const int height =data->game_rec.height; data->camera.cam.offset = (Vector2){ width/2.0f, height/2.0f }; - Vector2 target_vel = {0}; - sc_map_foreach_value(&scene->ent_manager.entities_map[PLAYER_ENT_TAG], p_player) + if (data->camera.mode == CAMERA_FOLLOW_PLAYER) { - CTransform_t* p_ctransform = get_component(p_player, CTRANSFORM_COMP_T); - data->camera.target_pos.x = p_player->position.x; - target_vel = p_ctransform->velocity; - CMovementState_t* p_movement = get_component(p_player, CMOVEMENTSTATE_T); - CPlayerState_t* p_pstate = get_component(p_player, CPLAYERSTATE_T); - data->camera.target_pos.x += (p_movement->x_dir == 1) ? width/6: -width/6; + Vector2 target_vel = {0}; + sc_map_foreach_value(&scene->ent_manager.entities_map[PLAYER_ENT_TAG], p_player) + { + CTransform_t* p_ctransform = get_component(p_player, CTRANSFORM_COMP_T); + data->camera.target_pos.x = p_player->position.x; + target_vel = p_ctransform->velocity; + CMovementState_t* p_movement = get_component(p_player, CMOVEMENTSTATE_T); + CPlayerState_t* p_pstate = get_component(p_player, CPLAYERSTATE_T); + data->camera.target_pos.x += (p_movement->x_dir == 1) ? width/6: -width/6; - if (p_movement->ground_state == 0b01 - || (p_movement->water_state & 1) - || (p_pstate->ladder_state & 1) - ) - { - data->camera.base_y = p_player->position.y; - } - if (p_player->position.y >= data->camera.base_y) - { - data->camera.target_pos.y = p_player->position.y; - data->camera.target_pos.y += p_ctransform->velocity.y * 0.2; + if (p_movement->ground_state == 0b01 + || (p_movement->water_state & 1) + || (p_pstate->ladder_state & 1) + ) + { + data->camera.base_y = p_player->position.y; + } + if (p_player->position.y >= data->camera.base_y) + { + data->camera.target_pos.y = p_player->position.y; + data->camera.target_pos.y += p_ctransform->velocity.y * 0.2; + } } + data->camera.target_pos.x = Clamp(data->camera.target_pos.x, data->game_rec.width / 2, + fmax(data->tilemap.width * data->tilemap.tile_size, data->game_rec.width) - data->game_rec.width / 2); + data->camera.target_pos.y = Clamp(data->camera.target_pos.y, data->game_rec.height / 2, + fmax(data->tilemap.height * data->tilemap.tile_size, data->game_rec.width) - data->game_rec.height / 2); + + // Mass-Spring damper update in x direction + float x = data->camera.target_pos.x - data->camera.cam.target.x; + float v = data->camera.current_vel.x - target_vel.x; + float F = data->camera.k * x - data->camera.c * v; + // Kinematics update + const float dt = scene->delta_time; + float a_dt = F * dt / data->camera.mass; + data->camera.cam.target.x += (data->camera.current_vel.x + a_dt * 0.5) * dt; + + data->camera.current_vel.x += a_dt; + + // Simple lerp for y direction + float dy = (data->camera.target_pos.y - data->camera.cam.target.y); + data->camera.cam.target.y += dy * 0.1f; + + + } + else + { + //sc_map_foreach_value(&scene->ent_manager.entities_map[PLAYER_ENT_TAG], p_player) + //{ + // break; + //} } - data->camera.target_pos.x = Clamp(data->camera.target_pos.x, data->game_rec.width / 2, - fmax(data->tilemap.width * data->tilemap.tile_size, data->game_rec.width) - data->game_rec.width / 2); - data->camera.target_pos.y = Clamp(data->camera.target_pos.y, data->game_rec.height / 2, - fmax(data->tilemap.height * data->tilemap.tile_size, data->game_rec.width) - data->game_rec.height / 2); - - // Mass-Spring damper update in x direction - float x = data->camera.target_pos.x - data->camera.cam.target.x; - float v = data->camera.current_vel.x - target_vel.x; - float F = data->camera.k * x - data->camera.c * v; - // Kinematics update - const float dt = scene->delta_time; - float a_dt = F * dt / data->camera.mass; - data->camera.cam.target.x += (data->camera.current_vel.x + a_dt * 0.5) * dt; - - data->camera.current_vel.x += a_dt; - - // Simple lerp for y direction - float dy = (data->camera.target_pos.y - data->camera.cam.target.y); - data->camera.cam.target.y += dy * 0.1f; + // Bound camera within level limits Vector2 max = GetWorldToScreen2D( (Vector2){ fmax(data->tilemap.width * data->tilemap.tile_size, data->game_rec.width), @@ -61,18 +74,29 @@ void camera_update_system(Scene_t* scene) data->camera.cam ); Vector2 min = GetWorldToScreen2D((Vector2){0, 0}, data->camera.cam); - if (max.x < width) { - data->camera.cam.offset.x = width - (max.x - width/2.0f); + //data->camera.cam.offset.x = width - (max.x - width/2.0f); data->camera.cam.target.x = fmax(data->tilemap.width * data->tilemap.tile_size, data->game_rec.width) - (width >> 1); data->camera.current_vel.x = 0; } if (min.x > 0) { - data->camera.cam.offset.x = (width >> 1) - min.x; + //data->camera.cam.offset.x = (width >> 1) - min.x; data->camera.cam.target.x = (width >> 1); data->camera.current_vel.x = 0; } + if (max.y < height) + { + //data->camera.cam.offset.y = height - (max.y - height/2.0f); + data->camera.cam.target.y = fmax(data->tilemap.height * data->tilemap.tile_size, data->game_rec.height) - (height >> 1); + data->camera.current_vel.y = 0; + } + if (min.y > 0) + { + //data->camera.cam.offset.y = (height >> 1) - min.y; + data->camera.cam.target.y = (height >> 1); + data->camera.current_vel.y = 0; + } } diff --git a/scenes/editor_scene.c b/scenes/editor_scene.c index 722d130..5d49e29 100644 --- a/scenes/editor_scene.c +++ b/scenes/editor_scene.c @@ -842,15 +842,19 @@ static void level_do_action(Scene_t* scene, ActionType_t action, bool pressed) { case ACTION_UP: p_playerstate->player_dir.y = (pressed)? -1 : 0; + if (data->camera.mode == CAMERA_RANGED_MOVEMENT) data->camera.cam.target.y -= 20; break; case ACTION_DOWN: p_playerstate->player_dir.y = (pressed)? 1 : 0; + if (data->camera.mode == CAMERA_RANGED_MOVEMENT) data->camera.cam.target.y += 20; break; case ACTION_LEFT: p_playerstate->player_dir.x = (pressed)? -1 : 0; + if (data->camera.mode == CAMERA_RANGED_MOVEMENT) data->camera.cam.target.x -= 20; break; case ACTION_RIGHT: p_playerstate->player_dir.x = (pressed)? 1 : 0; + if (data->camera.mode == CAMERA_RANGED_MOVEMENT) data->camera.cam.target.x += 20; break; case ACTION_JUMP: p_playerstate->jump_pressed = pressed; @@ -1034,6 +1038,7 @@ static void level_do_action(Scene_t* scene, ActionType_t action, bool pressed) break; case ACTION_LOOKAHEAD: p_playerstate->locked = pressed; + data->camera.mode = pressed ? CAMERA_RANGED_MOVEMENT : CAMERA_FOLLOW_PLAYER; default: break; } diff --git a/scenes/scene_impl.h b/scenes/scene_impl.h index eb1c5d5..f6be934 100644 --- a/scenes/scene_impl.h +++ b/scenes/scene_impl.h @@ -27,8 +27,14 @@ typedef struct CoinCounter uint16_t total; }CoinCounter_t; +typedef enum CameraMode { + CAMERA_FOLLOW_PLAYER = 0, + CAMERA_RANGED_MOVEMENT, +} CameraMode_t; + typedef struct LevelCamera { Camera2D cam; + CameraMode_t mode; Vector2 target_pos; float base_y; //Vector2 prev_pos; @@ -36,6 +42,7 @@ typedef struct LevelCamera { float mass; float c; // damping factor float k; // spring constant + float range_limit; }LevelCamera_t; typedef struct LevelSceneData { diff --git a/scenes/scene_systems.c b/scenes/scene_systems.c index 3935cc7..daed2c9 100644 --- a/scenes/scene_systems.c +++ b/scenes/scene_systems.c @@ -12,6 +12,7 @@ void init_level_scene_data(LevelSceneData_t* data, uint32_t max_tiles, Tile_t* t data->camera.mass = 0.2f; data->camera.k = 6.2f; data->camera.c = 2.2f; + data->camera.range_limit = 200.0f; data->tilemap.max_tiles = max_tiles; if (tiles != NULL)