vibe coding an orbital mechanics simulation to try out claude code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

6.8 KiB

Dynamic Camera Zoom Implementation Plan

Overview

Replace fixed zoom behavior with adaptive zoom speed and minimum distance based on current camera distance and target characteristics.

Goals

  • Zoom speed adapts to current distance (faster when far, slower when close)
  • Minimum camera distance based on target's physical size (radius)
  • Prevent zooming through body surfaces
  • Maintain smooth, controllable zoom with delta clamping

Changes Required

1. Add New Constants (src/renderer.cpp)

Add after existing camera constants:

// Dynamic zoom settings
#define ZOOM_PERCENTAGE 0.07f                        // 7% of current distance per keypress
#define ZOOM_MIN_DELTA 0.05f                        // Minimum zoom delta (prevents too-slow zoom)
#define ZOOM_MAX_DELTA 5.0f                          // Maximum zoom delta (prevents too-fast zoom)

// Minimum distance settings (in render units)
#define MIN_DISTANCE_BODY_RADIUS_MULT 2.75f           // 2.75x body radius minimum
#define MIN_DISTANCE_SPACECRAFT_DEFAULT 0.5f          // Fallback for orphaned spacecraft
#define MIN_DISTANCE_SPACECRAFT_PARENT_RADIUS_MULT 0.1f // Scale parent radius for spacecraft

2. Add Zoom Direction Enum (src/renderer.cpp)

Local enum for improved readability:

enum ZoomDirection {
    ZOOM_IN = -1.0f,
    ZOOM_OUT = 1.0f
};

3. Modify zoom_camera() Function

Location: src/renderer.cpp:223

Changes:

  • Update signature: static void zoom_camera(RenderState* render_state, SimulationState* sim, ZoomDirection direction)
  • Replace fixed CAMERA_ZOOM_DELTA with dynamic calculation
  • Add minimum distance based on target radius

Implementation:

static void zoom_camera(RenderState* render_state, SimulationState* sim, ZoomDirection direction) {
    Vector3 to_target = Vector3Subtract(render_state->camera.target, render_state->camera.position);
    Vector3 direction_vec = Vector3Normalize(to_target);
    float camera_distance = Vector3Length(to_target);

    // Calculate dynamic zoom delta based on current distance
    float raw_delta = camera_distance * ZOOM_PERCENTAGE * (float)direction;

    // Clamp delta to reasonable bounds
    float distance_delta = raw_delta;
    if (fabsf(distance_delta) < ZOOM_MIN_DELTA) {
        distance_delta = ZOOM_MIN_DELTA * (float)direction;
    }
    if (fabsf(distance_delta) > ZOOM_MAX_DELTA) {
        distance_delta = ZOOM_MAX_DELTA * (float)direction;
    }

    // Get target-specific minimum distance
    float min_dist = get_target_min_distance(render_state, sim);

    // Check if zoom would exceed minimum distance
    if (direction == ZOOM_IN && camera_distance - distance_delta <= min_dist) {
        distance_delta = camera_distance - min_dist - 0.001f;
    }

    render_state->camera.position = Vector3Add(render_state->camera.position, Vector3Scale(direction_vec, distance_delta));

    if (render_state->camera_target_enabled) {
        render_state->camera_offset = Vector3Subtract(
            render_state->camera.position,
            render_state->camera.target
        );
    }
}

4. Add get_target_min_distance() Helper Function

Location: Add new static function before zoom_camera()

static float get_target_min_distance(RenderState* render_state, SimulationState* sim) {
    float target_radius = 0.0f;

    if (render_state->selected_body_index >= 0) {
        CelestialBody* body = &sim->bodies[render_state->selected_body_index];
        target_radius = scale_radius(body->radius, render_state->distance_scale);
    } else if (render_state->selected_craft_index >= 0) {
        Spacecraft* craft = &sim->spacecraft[render_state->selected_craft_index];
        if (craft->parent_index >= 0 && craft->parent_index < sim->body_count) {
            CelestialBody* parent = &sim->bodies[craft->parent_index];
            target_radius = scale_radius(parent->radius, render_state->distance_scale);
            target_radius *= MIN_DISTANCE_SPACECRAFT_PARENT_RADIUS_MULT;
        } else {
            // Spacecraft without parent (shouldn't happen in valid configs)
            return MIN_DISTANCE_SPACECRAFT_DEFAULT;
        }
    } else {
        // No target selected, use existing fallback
        return CAMERA_MIN_DISTANCE;
    }

    return target_radius * MIN_DISTANCE_BODY_RADIUS_MULT;
}

5. Update update_camera() Calls

Location: src/renderer.cpp:277-282

Change from:

if (IsKeyDown(KEY_UP)) {
    zoom_camera(render_state, CAMERA_ZOOM_DELTA);
}
if (IsKeyDown(KEY_DOWN)) {
    zoom_camera(render_state, -CAMERA_ZOOM_DELTA);
}

Change to:

if (IsKeyDown(KEY_UP)) {
    zoom_camera(render_state, sim, ZOOM_IN);
}
if (IsKeyDown(KEY_DOWN)) {
    zoom_camera(render_state, sim, ZOOM_OUT);
}

6. Remove/Update Old Constants

Location: src/renderer.cpp:8

Remove: #define CAMERA_ZOOM_DELTA 2.0f (replaced by dynamic calculation) Keep: #define CAMERA_MIN_DISTANCE 0.1f (as fallback when no target)

Technical Details

Dynamic Zoom Calculation

  1. Calculate raw delta: current_distance * ZOOM_PERCENTAGE * direction
  2. Clamp delta between ZOOM_MIN_DELTA and ZOOM_MAX_DELTA
  3. Ensure sign matches zoom direction

Minimum Distance Logic

  1. For bodies: body_radius * MIN_DISTANCE_BODY_RADIUS_MULT
  2. For spacecraft: parent_radius * MIN_DISTANCE_SPACECRAFT_PARENT_RADIUS_MULT * MIN_DISTANCE_BODY_RADIUS_MULT
  3. For no target: CAMERA_MIN_DISTANCE (existing fallback)

Sign Convention

  • ZOOM_IN (-1.0): Move camera closer to target (decrease distance)
  • ZOOM_OUT (+1.0): Move camera farther from target (increase distance)

Edge Cases

  • Spacecraft without parent: Uses MIN_DISTANCE_SPACECRAFT_DEFAULT
  • No target selected: Uses existing CAMERA_MIN_DISTANCE
  • Very close zoom: Delta clamping prevents too-slow movement

Implementation Order

  1. Add new constants and enum to renderer.cpp
  2. Implement get_target_min_distance() helper
  3. Modify zoom_camera() function signature and implementation
  4. Update update_camera() calls to zoom_camera()
  5. Remove old CAMERA_ZOOM_DELTA constant
  6. Build and test

Testing Checklist

  • Zoom in/out works smoothly with new percentage-based behavior
  • Zoom speed adapts based on current distance (faster when far, slower when close)
  • Cannot zoom through body surface (minimum distance enforced)
  • Spacecraft zoom uses parent body radius (scaled down)
  • Zoom delta clamping prevents too-fast or too-slow zoom
  • No target selected still works (uses existing fallbacks)
  • Build succeeds without errors

Future Enhancements (Not in scope)

  • Use parent's SOI radius instead of radius for more physically meaningful bounds
  • Consider orbital characteristics (semi-major axis) for context-aware minimums
  • Add configurable zoom speed presets (slow/normal/fast)
  • Smooth interpolation when zooming rapidly