stargazing-dino / cosmic-junkyard

A space game
MIT License
1 stars 0 forks source link

Implement Variable Jump Height #33

Open stargazing-dino opened 1 year ago

stargazing-dino commented 1 year ago

Description:

To enhance player control and gameplay dynamics, implement a variable jump height feature. The jump's height should be dependent on the duration the jump button (KeyCode::Space) is held. A short button press should result in a lower jump, while holding the button should allow the character to reach the maximum jump height.

Acceptance Criteria:

  1. Initial Jump Thrust: On the initial press of the jump button, the player should receive an impulse sufficient to initiate a jump.

  2. Height Control: The player should be able to control the jump's height by holding or releasing the jump button. Holding the button will add a continuous, but diminishing force, up to a capped max height. Releasing the button will halt the additional force, allowing gravity to take over immediately.

  3. Feedback: Consider adding a subtle animation or effect when reaching the maximum jump height to provide player feedback.

  4. Sound: Different jump sound effects for short hops versus full jumps can enhance the player's feedback.

  5. Air Control: Ensure that the in-air controls still feel responsive when the player is controlling jump height.

  6. Edge Cases: Ensure the mechanic doesn't allow for 'double jumps' unless intended. If the player taps the jump button multiple times in rapid succession, it shouldn't give them extra height.

  7. Performance: The feature should not introduce any significant performance overhead.

Implementation Details:

  1. On the detection of a jump button press, apply an initial impulse to the player.

  2. Continue to apply a diminishing upward force to the player for as long as the jump button is held, but only up to a maximum duration or height.

  3. Monitor for the release of the jump button, at which point the upward force should stop being applied.

  4. Consider using a Coroutine or Timer (depending on your game engine/framework) to manage the diminishing force over time.

  5. Playtest extensively to find the right balance for the initial impulse, the diminishing force, and the maximum height.

stargazing-dino commented 1 year ago

Certainly! Variable jump height is a common mechanic in platformers and provides players with more control over their character's movements. The idea is straightforward: the longer the jump button is held, the higher the character jumps, up to a maximum height. Releasing the button prematurely results in a shorter jump. This allows for precise, skill-based platforming.

Here's a basic approach to implementing variable jump height:

  1. Jump Start:

    • When the player presses the jump button and the character is on the ground, apply an initial upward force or velocity to initiate the jump.
  2. Jump Hold:

    • While the jump button is held, continue applying a smaller upward force or maintain an upward velocity, but decrease it over time (to simulate gravity and diminishing force).
    • Implement a maximum hold time or maximum height to ensure the character can't jump indefinitely.
  3. Jump Release:

    • If the player releases the jump button before the maximum hold time, stop applying the upward force or reduce the upward velocity significantly. This will cause gravity to pull the character down faster, resulting in a shorter jump.

Here's a possible implementation based on the code you provided:

const MAX_JUMP_HOLD_TIME: f32 = 0.5; // Max time the jump can be held in seconds
const JUMP_START_FORCE: f32 = 20.0; // Initial jump force
const JUMP_HOLD_FORCE: f32 = 8.0;   // Additional force applied while the jump button is held

pub fn variable_jump(
    time: Res<Time>,
    keyboard_input: Res<Input<KeyCode>>,
    mut players: Query<(&mut ExternalImpulse, &ShapeHits, &GravityBound, &mut JumpState), With<Player>>,
    sensors_query: Query<&Sensor>,
) {
    for (mut external_impulse, shape_hits, gravity_bound, mut jump_state) in &mut players {
        let gravity_force = gravity_bound.gravity_force;

        // If the player is floating in space, don't apply jump
        if gravity_force == Vec3::ZERO {
            continue;
        }

        let gravity_up = -gravity_force.normalize();

        if keyboard_input.just_pressed(KeyCode::Space) {
            let touching_ground = shape_hits
                .iter()
                .any(|hit| sensors_query.get(hit.entity).is_err());

            if touching_ground {
                external_impulse.apply_impulse(gravity_up * JUMP_START_FORCE);
                jump_state.is_jumping = true;
                jump_state.hold_timer = 0.0;
            }
        }

        // If the jump button is held and the player is still in the jump process
        if keyboard_input.pressed(KeyCode::Space) && jump_state.is_jumping {
            if jump_state.hold_timer < MAX_JUMP_HOLD_TIME {
                external_impulse.apply_impulse(gravity_up * JUMP_HOLD_FORCE * time.delta_seconds());
                jump_state.hold_timer += time.delta_seconds();
            }
        }

        // If the jump button is released
        if keyboard_input.just_released(KeyCode::Space) && jump_state.is_jumping {
            jump_state.is_jumping = false;
        }
    }
}

// ... elsewhere in the code ...

pub struct JumpState {
    is_jumping: bool,
    hold_timer: f32,
}

Here's a summary:

This implementation is just a starting point, and you may need to adjust values and mechanics based on how it feels in your game. Remember, game mechanics often need iterative testing and refining!