diff --git a/physics_engine.vhd b/physics_engine.vhd index a43c742..eb1ff47 100644 --- a/physics_engine.vhd +++ b/physics_engine.vhd @@ -52,7 +52,12 @@ architecture behavior of physics_engine is -- Physics tuning constant GRAVITY : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(1, 10); constant IMPULSE : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(3, 10); - constant SLAM_FORCE : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(4, 10); + constant SLAM_TAP_FORCE : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(18, 10); + constant SLAM_BOOST_CLOSE : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(24, 10); + constant SLAM_BOOST_MED : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(16, 10); + constant SLAM_BOOST_FAR : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(8, 10); + constant SLAM_CLOSE_THR : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(270, 11); + constant SLAM_MED_THR : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(660, 11); -- Initial jump: full force at zero velocity, tapers off as |vel_y| rises. -- Piecewise lookup approximates: max(JUMP_MIN, JUMP_BASE*JUMP_SCALE/(JUMP_SCALE+|vy|)) constant JUMP_BASE : integer := 14; -- force at zero velocity @@ -87,6 +92,9 @@ architecture behavior of physics_engine is signal squish_h : std_logic := '0'; signal on_ground : std_logic := '0'; signal jump_pressed : std_logic := '0'; + signal slam_held : std_logic := '0'; + signal slam_start_y : std_logic_vector(10 downto 0) := (others => '0'); + signal prev_key_s : std_logic := '0'; signal abs_vel_x : std_logic_vector(9 downto 0); signal abs_vel_y : std_logic_vector(9 downto 0); @@ -149,6 +157,8 @@ begin variable abs_vy_int : integer; variable jforce_int : integer; variable jforce_slv : std_logic_vector(9 downto 0); + variable slam_dist : std_logic_vector(10 downto 0); + variable slam_boost : std_logic_vector(9 downto 0); begin wait until vert_sync'event and vert_sync = '1'; @@ -180,7 +190,14 @@ begin vy := vy - JUMP_BOUNCE; end if; - if key_s = '1' and on_ground = '0' then vy := vy + SLAM_FORCE; end if; + -- S slam: rising edge in air = tap burst downward; hold to get landing boost + if key_s = '1' and prev_key_s = '0' and on_ground = '0' then + slam_start_y <= pos_y; + slam_held <= '1'; + vy := vy + SLAM_TAP_FORCE; + end if; + if key_s = '0' then slam_held <= '0'; end if; + prev_key_s <= key_s; if key_a = '1' then if on_ground = '1' then vx := vx - IMPULSE; else vx := vx - 2; end if; @@ -347,6 +364,21 @@ begin end if; end loop; + -- == HOLD-SLAM LANDING BOOST == + -- Bigger boost when slam started closer to the surface + if grounded = '1' and slam_held = '1' then + slam_dist := py - slam_start_y; + if slam_dist < SLAM_CLOSE_THR then + slam_boost := SLAM_BOOST_CLOSE; + elsif slam_dist < SLAM_MED_THR then + slam_boost := SLAM_BOOST_MED; + else + slam_boost := SLAM_BOOST_FAR; + end if; + vy := vy - slam_boost; + slam_held <= '0'; + end if; + -- == COMMIT == vel_x <= vx; vel_y <= vy; diff --git a/visualizer.py b/visualizer.py index 7e13e77..3fdfb3f 100644 --- a/visualizer.py +++ b/visualizer.py @@ -23,7 +23,12 @@ FPS = 60 # --- Physics constants (match VHDL exactly) --- GRAVITY = 1 IMPULSE = 3 -SLAM_FORCE = 4 +SLAM_TAP_FORCE = 18 # instant downward burst on S press in air +SLAM_BOOST_CLOSE = 24 # upward boost on hold-slam landing, close range +SLAM_BOOST_MED = 16 # upward boost, medium range +SLAM_BOOST_FAR = 8 # upward boost, far range +SLAM_CLOSE_THR = 80 # pixels: "close to surface" threshold +SLAM_MED_THR = 200 # pixels: "medium distance" threshold AIR_CONTROL = 2 JUMP_FORCE = 14 # initial jump force at zero velocity (scales down with |vel_y|) JUMP_VEL_SCALE = 12 # velocity magnitude at which initial jump force is halved @@ -85,6 +90,9 @@ def main(): squish_h = False # False = vertical squish (floor/ceil), True = horizontal squish (walls) on_ground = False jump_pressed = False + slam_held = False + slam_start_y = 0 + prev_key_s = False keys_held = {'w': False, 'a': False, 's': False, 'd': False} trail = [] @@ -108,6 +116,7 @@ def main(): char_x, char_y = 100, 200 vel_x = vel_y = to_unsigned(0) squish = 0; squish_h = False; on_ground = False; jump_pressed = False + slam_held = False; slam_start_y = 0; prev_key_s = False trail.clear() elif event.type == pygame.KEYUP: if event.key == pygame.K_w: keys_held['w'] = False @@ -143,9 +152,14 @@ def main(): # Holding W while bouncing: fixed boost so trampoline accumulates each contact vy = (vy - JUMP_BOUNCE) & MASK - # S: slam (air only) - if keys_held['s'] and not on_ground: - vy = (vy + SLAM_FORCE) & MASK + # S slam: rising edge in air = tap burst downward; hold to get landing boost + if keys_held['s'] and not prev_key_s and not on_ground: + slam_start_y = char_y + slam_held = True + vy = (vy + SLAM_TAP_FORCE) & MASK + if not keys_held['s']: + slam_held = False + prev_key_s = keys_held['s'] # A/D if keys_held['a']: @@ -312,6 +326,18 @@ def main(): svy = svy - loss if svy > 0 else svy + loss vy = to_unsigned(svy) + # Hold-slam landing boost: bigger boost when slam started closer to the surface + if grounded and slam_held: + dist = py - slam_start_y + if dist < SLAM_CLOSE_THR: + slam_boost_val = SLAM_BOOST_CLOSE + elif dist < SLAM_MED_THR: + slam_boost_val = SLAM_BOOST_MED + else: + slam_boost_val = SLAM_BOOST_FAR + vy = (vy - slam_boost_val) & MASK + slam_held = False + # Commit char_x = px char_y = py