1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add big thing

+858 -483
+669 -363
physics_engine.vhd
··· 1 - -- ======================================================================== 2 - -- Physics Engine 3 - -- Runs once per frame on vert_sync rising edge (~60Hz). 4 - -- Handles gravity, keyboard input, friction, bouncing off walls/floor/ 5 - -- ceiling/obstacles, and squish animation. 6 - -- 7 - -- Outputs character position and animated dimensions for the renderer. 8 - -- All velocity math is 10-bit 2's complement (bit 9 = sign). 9 - -- ======================================================================== 10 - 11 - library IEEE; 12 - use IEEE.STD_LOGIC_1164.all; 13 - use IEEE.STD_LOGIC_ARITH.all; 14 - use IEEE.STD_LOGIC_UNSIGNED.all; 15 - 16 - entity physics_engine is 17 - port( 18 - vert_sync : in std_logic; -- frame clock (~60Hz) 19 - key_w : in std_logic; -- from ps2_decoder 20 - key_a : in std_logic; 21 - key_s : in std_logic; 22 - key_d : in std_logic; 23 - char_x : out std_logic_vector(9 downto 0); -- character center X 24 - char_y : out std_logic_vector(9 downto 0); -- character center Y 25 - char_width : out std_logic_vector(9 downto 0); -- animated half-width 26 - char_height : out std_logic_vector(9 downto 0) -- animated half-height 27 - ); 28 - end physics_engine; 29 - 30 - architecture behavior of physics_engine is 31 - 32 - -- Character state 33 - signal pos_x : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(100, 10); 34 - signal pos_y : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(200, 10); 35 - signal vel_x : std_logic_vector(9 downto 0) := (others => '0'); 36 - signal vel_y : std_logic_vector(9 downto 0) := (others => '0'); 37 - 38 - constant SIZE : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(7, 10); 39 - 40 - -- Tuning constants 41 - constant GRAVITY : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(1, 10); 42 - constant IMPULSE : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(3, 10); 43 - constant JUMP_FORCE : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(13, 10); 44 - constant MAX_VEL_X : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(32, 10); 45 - 46 - -- Screen bounds 47 - constant GROUND : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(440, 10); 48 - constant CEILING : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(16, 10); 49 - constant LEFT_WALL : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(8, 10); 50 - constant RIGHT_WALL: std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(631, 10); 51 - 52 - -- Obstacle positions (must match renderer) 53 - constant O1_L : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(60, 10); 54 - constant O1_T : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(370, 10); 55 - constant O1_R : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(180, 10); 56 - constant O1_B : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(386, 10); 57 - 58 - constant O2_L : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(250, 10); 59 - constant O2_T : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(300, 10); 60 - constant O2_R : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(390, 10); 61 - constant O2_B : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(316, 10); 62 - 63 - constant O3_L : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(440, 10); 64 - constant O3_T : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(200, 10); 65 - constant O3_R : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(580, 10); 66 - constant O3_B : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(216, 10); 67 - 68 - constant O4_L : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(140, 10); 69 - constant O4_T : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(120, 10); 70 - constant O4_R : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(200, 10); 71 - constant O4_B : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(150, 10); 72 - 73 - -- Animation state 74 - signal squish : std_logic_vector(3 downto 0) := (others => '0'); 75 - signal squish_h : std_logic := '0'; -- '0'=vertical squish, '1'=horizontal 76 - signal on_ground : std_logic := '0'; 77 - signal jump_pressed : std_logic := '0'; 78 - 79 - begin 80 - 81 - -- Output character position 82 - char_x <= pos_x; 83 - char_y <= pos_y; 84 - 85 - -- Squish deforms the character: vertical hit = wider+shorter, wall hit = taller+narrower 86 - char_width <= SIZE + ("000000" & squish) when squish_h = '0' 87 - else SIZE - ("000000" & squish(3 downto 1)); 88 - char_height <= SIZE - ("000000" & squish(3 downto 1)) when squish_h = '0' 89 - else SIZE + ("000000" & squish); 90 - 91 - -- Main physics process: one tick per frame 92 - physics : process 93 - variable vx, vy : std_logic_vector(9 downto 0); 94 - variable px, py : std_logic_vector(9 downto 0); 95 - variable bounced : std_logic; 96 - variable bounce_wall : std_logic; 97 - variable bounce_speed : std_logic_vector(9 downto 0); 98 - variable grounded : std_logic; 99 - variable c_left, c_right, c_top, c_bot : std_logic_vector(9 downto 0); 100 - variable overlap_x, overlap_y : std_logic_vector(9 downto 0); 101 - begin 102 - wait until vert_sync'event and vert_sync = '1'; 103 - 104 - vx := vel_x; 105 - vy := vel_y; 106 - bounced := '0'; 107 - bounce_wall := '0'; 108 - bounce_speed := (others => '0'); 109 - grounded := '0'; 110 - 111 - -- == INPUT == 112 - 113 - if key_w = '0' then 114 - jump_pressed <= '0'; 115 - end if; 116 - 117 - -- Jump on ground (single impulse) 118 - if key_w = '1' and jump_pressed = '0' and on_ground = '1' then 119 - vy := (others => '0'); 120 - vy := vy - JUMP_FORCE; 121 - jump_pressed <= '1'; 122 - end if; 123 - 124 - -- Bounce boost: holding W adds energy each ground contact 125 - if key_w = '1' and jump_pressed = '1' and on_ground = '1' then 126 - vy := vy - 4; 127 - end if; 128 - 129 - -- Slam down (air only) 130 - if key_s = '1' and on_ground = '0' then 131 - vy := vy + IMPULSE; 132 - end if; 133 - 134 - -- Horizontal: full on ground, reduced in air 135 - if key_a = '1' then 136 - if on_ground = '1' then vx := vx - IMPULSE; 137 - else vx := vx - 2; end if; 138 - end if; 139 - if key_d = '1' then 140 - if on_ground = '1' then vx := vx + IMPULSE; 141 - else vx := vx + 2; end if; 142 - end if; 143 - 144 - -- == GRAVITY == 145 - vy := vy + GRAVITY; 146 - 147 - -- == FRICTION: vel -= vel/4, min 1 == 148 - if vx(9) = '0' then 149 - if vx > 0 then 150 - if vx(9 downto 2) = "00000000" then vx := vx - 1; 151 - else vx := vx - ("000" & vx(9 downto 3)); end if; 152 - end if; 153 - else 154 - if vx /= "0000000000" then 155 - if vx(9 downto 2) = "11111111" then vx := vx + 1; 156 - else vx := vx - ("11" & vx(9 downto 2)); end if; 157 - end if; 158 - end if; 159 - 160 - -- == CLAMP == 161 - if vx(9) = '0' and vx > MAX_VEL_X then vx := MAX_VEL_X; end if; 162 - if vx(9) = '1' and vx < (not MAX_VEL_X) + 1 then vx := (not MAX_VEL_X) + 1; end if; 163 - if vy(9) = '0' and vy > 63 then vy := CONV_STD_LOGIC_VECTOR(63, 10); end if; 164 - if vy(9) = '1' and vy < CONV_STD_LOGIC_VECTOR(960, 10) then vy := CONV_STD_LOGIC_VECTOR(960, 10); end if; 165 - 166 - -- == MOVE == 167 - px := pos_x + vx; 168 - py := pos_y + vy; 169 - 170 - -- == GROUND == 171 - if py >= GROUND then 172 - py := GROUND; 173 - bounced := '1'; grounded := '1'; 174 - bounce_speed := vy; 175 - vy := (not vy) + 1; 176 - if vy(9) = '1' then 177 - vy := vy + ("000" & ((not vy(9 downto 3)) + 1)); 178 - end if; 179 - if vy(9) = '1' and vy >= CONV_STD_LOGIC_VECTOR(1022, 10) then vy := (others => '0'); 180 - elsif vy(9) = '0' then vy := (others => '0'); end if; 181 - end if; 182 - 183 - -- == CEILING == 184 - if py(9) = '1' or py <= CEILING then 185 - py := CEILING; 186 - bounced := '1'; 187 - bounce_speed := (not vy) + 1; 188 - vy := (not vy) + 1; 189 - if vy(9) = '0' and vy > 1 then 190 - vy := vy - ("000" & vy(9 downto 3)); 191 - end if; 192 - end if; 193 - 194 - -- == LEFT WALL == 195 - -- Detect underflow: moving left (vx negative) but px wrapped to > pos_x 196 - if (vx(9) = '1' and px > pos_x) or px <= LEFT_WALL + SIZE then 197 - px := LEFT_WALL + SIZE; 198 - bounced := '1'; bounce_wall := '1'; 199 - bounce_speed := (not vx) + 1; 200 - vx := (not vx) + 1; 201 - if vx(9) = '0' and vx > 1 then 202 - vx := vx - ("000" & vx(9 downto 3)); 203 - end if; 204 - end if; 205 - 206 - -- == RIGHT WALL == 207 - if px >= RIGHT_WALL - SIZE then 208 - px := RIGHT_WALL - SIZE; 209 - bounced := '1'; bounce_wall := '1'; 210 - bounce_speed := vx; 211 - vx := (not vx) + 1; 212 - -- vx is now negative: reduce magnitude toward zero 213 - if vx(9) = '1' then 214 - vx := vx + ("000" & ((not vx(9 downto 3)) + 1)); 215 - end if; 216 - -- Kill tiny bounces 217 - if vx(9) = '1' and vx >= CONV_STD_LOGIC_VECTOR(1022, 10) then vx := (others => '0'); end if; 218 - end if; 219 - 220 - -- == OBSTACLE COLLISIONS == 221 - -- Pattern: AABB overlap -> resolve on shallower axis -> bounce 222 - 223 - -- Obstacle 1 224 - c_left := px - SIZE; c_right := px + SIZE; 225 - c_top := py - SIZE; c_bot := py + SIZE; 226 - if (c_right >= O1_L) and (c_left <= O1_R) and 227 - (c_bot >= O1_T) and (c_top <= O1_B) then 228 - if vy(9) = '0' then overlap_y := c_bot - O1_T; 229 - else overlap_y := O1_B - c_top; end if; 230 - if vx(9) = '0' then overlap_x := c_right - O1_L; 231 - else overlap_x := O1_R - c_left; end if; 232 - if overlap_y <= overlap_x then 233 - if vy(9) = '0' then py := O1_T - SIZE; grounded := '1'; 234 - else py := O1_B + SIZE; end if; 235 - bounced := '1'; 236 - vy := (not vy) + 1; 237 - if vy(9) = '0' and vy > 1 then vy := vy - ("000" & vy(9 downto 3)); 238 - elsif vy(9) = '1' and vy < CONV_STD_LOGIC_VECTOR(1022, 10) then 239 - vy := vy + ("000" & ((not vy(9 downto 3)) + 1)); end if; 240 - if vy(9) = '0' and vy < 2 then vy := (others => '0'); end if; 241 - if vy(9) = '1' and vy >= CONV_STD_LOGIC_VECTOR(1022, 10) then vy := (others => '0'); end if; 242 - else 243 - if vx(9) = '0' then px := O1_L - SIZE; 244 - else px := O1_R + SIZE; end if; 245 - bounced := '1'; bounce_wall := '1'; 246 - vx := (not vx) + 1; 247 - if vx(9) = '0' and vx > 1 then vx := vx - ("000" & vx(9 downto 3)); 248 - elsif vx(9) = '1' and vx < CONV_STD_LOGIC_VECTOR(1022, 10) then 249 - vx := vx + ("000" & ((not vx(9 downto 3)) + 1)); end if; 250 - end if; 251 - end if; 252 - 253 - -- Obstacle 2 254 - c_left := px - SIZE; c_right := px + SIZE; 255 - c_top := py - SIZE; c_bot := py + SIZE; 256 - if (c_right >= O2_L) and (c_left <= O2_R) and 257 - (c_bot >= O2_T) and (c_top <= O2_B) then 258 - if vy(9) = '0' then overlap_y := c_bot - O2_T; 259 - else overlap_y := O2_B - c_top; end if; 260 - if vx(9) = '0' then overlap_x := c_right - O2_L; 261 - else overlap_x := O2_R - c_left; end if; 262 - if overlap_y <= overlap_x then 263 - if vy(9) = '0' then py := O2_T - SIZE; grounded := '1'; 264 - else py := O2_B + SIZE; end if; 265 - bounced := '1'; 266 - vy := (not vy) + 1; 267 - if vy(9) = '0' and vy > 1 then vy := vy - ("000" & vy(9 downto 3)); 268 - elsif vy(9) = '1' and vy < CONV_STD_LOGIC_VECTOR(1022, 10) then 269 - vy := vy + ("000" & ((not vy(9 downto 3)) + 1)); end if; 270 - if vy(9) = '0' and vy < 2 then vy := (others => '0'); end if; 271 - if vy(9) = '1' and vy >= CONV_STD_LOGIC_VECTOR(1022, 10) then vy := (others => '0'); end if; 272 - else 273 - if vx(9) = '0' then px := O2_L - SIZE; 274 - else px := O2_R + SIZE; end if; 275 - bounced := '1'; bounce_wall := '1'; 276 - vx := (not vx) + 1; 277 - if vx(9) = '0' and vx > 1 then vx := vx - ("000" & vx(9 downto 3)); 278 - elsif vx(9) = '1' and vx < CONV_STD_LOGIC_VECTOR(1022, 10) then 279 - vx := vx + ("000" & ((not vx(9 downto 3)) + 1)); end if; 280 - end if; 281 - end if; 282 - 283 - -- Obstacle 3 284 - c_left := px - SIZE; c_right := px + SIZE; 285 - c_top := py - SIZE; c_bot := py + SIZE; 286 - if (c_right >= O3_L) and (c_left <= O3_R) and 287 - (c_bot >= O3_T) and (c_top <= O3_B) then 288 - if vy(9) = '0' then overlap_y := c_bot - O3_T; 289 - else overlap_y := O3_B - c_top; end if; 290 - if vx(9) = '0' then overlap_x := c_right - O3_L; 291 - else overlap_x := O3_R - c_left; end if; 292 - if overlap_y <= overlap_x then 293 - if vy(9) = '0' then py := O3_T - SIZE; grounded := '1'; 294 - else py := O3_B + SIZE; end if; 295 - bounced := '1'; 296 - vy := (not vy) + 1; 297 - if vy(9) = '0' and vy > 1 then vy := vy - ("000" & vy(9 downto 3)); 298 - elsif vy(9) = '1' and vy < CONV_STD_LOGIC_VECTOR(1022, 10) then 299 - vy := vy + ("000" & ((not vy(9 downto 3)) + 1)); end if; 300 - if vy(9) = '0' and vy < 2 then vy := (others => '0'); end if; 301 - if vy(9) = '1' and vy >= CONV_STD_LOGIC_VECTOR(1022, 10) then vy := (others => '0'); end if; 302 - else 303 - if vx(9) = '0' then px := O3_L - SIZE; 304 - else px := O3_R + SIZE; end if; 305 - bounced := '1'; bounce_wall := '1'; 306 - vx := (not vx) + 1; 307 - if vx(9) = '0' and vx > 1 then vx := vx - ("000" & vx(9 downto 3)); 308 - elsif vx(9) = '1' and vx < CONV_STD_LOGIC_VECTOR(1022, 10) then 309 - vx := vx + ("000" & ((not vx(9 downto 3)) + 1)); end if; 310 - end if; 311 - end if; 312 - 313 - -- Obstacle 4 314 - c_left := px - SIZE; c_right := px + SIZE; 315 - c_top := py - SIZE; c_bot := py + SIZE; 316 - if (c_right >= O4_L) and (c_left <= O4_R) and 317 - (c_bot >= O4_T) and (c_top <= O4_B) then 318 - if vy(9) = '0' then overlap_y := c_bot - O4_T; 319 - else overlap_y := O4_B - c_top; end if; 320 - if vx(9) = '0' then overlap_x := c_right - O4_L; 321 - else overlap_x := O4_R - c_left; end if; 322 - if overlap_y <= overlap_x then 323 - if vy(9) = '0' then py := O4_T - SIZE; grounded := '1'; 324 - else py := O4_B + SIZE; end if; 325 - bounced := '1'; 326 - vy := (not vy) + 1; 327 - if vy(9) = '0' and vy > 1 then vy := vy - ("000" & vy(9 downto 3)); 328 - elsif vy(9) = '1' and vy < CONV_STD_LOGIC_VECTOR(1022, 10) then 329 - vy := vy + ("000" & ((not vy(9 downto 3)) + 1)); end if; 330 - if vy(9) = '0' and vy < 2 then vy := (others => '0'); end if; 331 - if vy(9) = '1' and vy >= CONV_STD_LOGIC_VECTOR(1022, 10) then vy := (others => '0'); end if; 332 - else 333 - if vx(9) = '0' then px := O4_L - SIZE; 334 - else px := O4_R + SIZE; end if; 335 - bounced := '1'; bounce_wall := '1'; 336 - vx := (not vx) + 1; 337 - if vx(9) = '0' and vx > 1 then vx := vx - ("000" & vx(9 downto 3)); 338 - elsif vx(9) = '1' and vx < CONV_STD_LOGIC_VECTOR(1022, 10) then 339 - vx := vx + ("000" & ((not vx(9 downto 3)) + 1)); end if; 340 - end if; 341 - end if; 342 - 343 - -- == COMMIT == 344 - vel_x <= vx; 345 - vel_y <= vy; 346 - pos_x <= px; 347 - pos_y <= py; 348 - 349 - -- Squish on meaningful impacts only 350 - if bounced = '1' and bounce_speed > 3 then 351 - if bounce_speed >= 8 then squish <= "1000"; 352 - else squish <= bounce_speed(3 downto 0); end if; 353 - squish_h <= bounce_wall; 354 - elsif squish > 0 then 355 - squish <= squish - 1; 356 - end if; 357 - 358 - if grounded = '1' then on_ground <= '1'; 359 - elsif py < GROUND - 1 then on_ground <= '0'; end if; 360 - 361 - end process physics; 362 - 363 - end behavior; 1 + -- ======================================================================== 2 + -- Physics Engine (scrolling 1500x1500 world) 3 + -- Positions: 11-bit unsigned (0..2047, world fits in 0..1500). 4 + -- Velocities: 10-bit 2's complement (bit 9 = sign), unchanged. 5 + -- Camera: follows character, clamped to world bounds, output for renderer. 6 + -- ======================================================================== 7 + 8 + library IEEE; 9 + use IEEE.STD_LOGIC_1164.all; 10 + use IEEE.STD_LOGIC_ARITH.all; 11 + use IEEE.STD_LOGIC_UNSIGNED.all; 12 + 13 + entity physics_engine is 14 + port( 15 + vert_sync : in std_logic; 16 + key_w : in std_logic; 17 + key_a : in std_logic; 18 + key_s : in std_logic; 19 + key_d : in std_logic; 20 + char_x : out std_logic_vector(10 downto 0); 21 + char_y : out std_logic_vector(10 downto 0); 22 + char_width : out std_logic_vector(9 downto 0); 23 + char_height : out std_logic_vector(9 downto 0); 24 + cam_x : out std_logic_vector(10 downto 0); 25 + cam_y : out std_logic_vector(10 downto 0) 26 + ); 27 + end physics_engine; 28 + 29 + architecture behavior of physics_engine is 30 + 31 + -- Character state 32 + signal pos_x : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(100, 11); 33 + signal pos_y : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1400, 11); 34 + signal vel_x : std_logic_vector(9 downto 0) := (others => '0'); 35 + signal vel_y : std_logic_vector(9 downto 0) := (others => '0'); 36 + signal cam_x_sig : std_logic_vector(10 downto 0) := (others => '0'); 37 + signal cam_y_sig : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1020, 11); 38 + 39 + -- SIZE: 10-bit for squish outputs, 11-bit for position arithmetic 40 + constant SIZE : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(7, 10); 41 + constant SIZE11 : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(7, 11); 42 + 43 + -- Physics tuning 44 + constant GRAVITY : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(1, 10); 45 + constant IMPULSE : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(3, 10); 46 + constant JUMP_FORCE : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(13, 10); 47 + constant MAX_VEL_X : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(32, 10); 48 + 49 + -- World bounds (11-bit) 50 + constant GROUND : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1480, 11); 51 + constant CEILING : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(16, 11); 52 + constant LEFT_WALL : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(15, 11); 53 + constant RIGHT_WALL : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1492, 11); 54 + 55 + -- ---- Obstacle constants (L, T, R, B) in world-space (11-bit) ---- 56 + -- Bottom zone (near ground, y ~1300-1420) 57 + constant O1_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(100, 11); 58 + constant O1_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1380, 11); 59 + constant O1_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(280, 11); 60 + constant O1_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1396, 11); 61 + 62 + constant O2_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(450, 11); 63 + constant O2_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1320, 11); 64 + constant O2_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(530, 11); 65 + constant O2_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1336, 11); 66 + 67 + constant O3_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(750, 11); 68 + constant O3_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1390, 11); 69 + constant O3_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(950, 11); 70 + constant O3_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1406, 11); 71 + 72 + constant O4_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1150, 11); 73 + constant O4_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1300, 11); 74 + constant O4_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1380, 11); 75 + constant O4_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1316, 11); 76 + 77 + -- Mid-lower zone (y ~1000-1140) 78 + constant O5_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(60, 11); 79 + constant O5_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1100, 11); 80 + constant O5_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(250, 11); 81 + constant O5_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1116, 11); 82 + 83 + constant O6_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(400, 11); 84 + constant O6_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1050, 11); 85 + constant O6_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(550, 11); 86 + constant O6_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1066, 11); 87 + 88 + constant O7_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(720, 11); 89 + constant O7_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1000, 11); 90 + constant O7_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(920, 11); 91 + constant O7_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1016, 11); 92 + 93 + constant O8_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1100, 11); 94 + constant O8_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1120, 11); 95 + constant O8_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1350, 11); 96 + constant O8_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1136, 11); 97 + 98 + -- Mid-upper zone (y ~650-800) 99 + constant O9_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(150, 11); 100 + constant O9_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(780, 11); 101 + constant O9_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(380, 11); 102 + constant O9_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(796, 11); 103 + 104 + constant O10_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(550, 11); 105 + constant O10_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(700, 11); 106 + constant O10_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(650, 11); 107 + constant O10_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(716, 11); 108 + 109 + constant O11_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(850, 11); 110 + constant O11_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(650, 11); 111 + constant O11_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1050, 11); 112 + constant O11_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(666, 11); 113 + 114 + constant O12_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1200, 11); 115 + constant O12_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(760, 11); 116 + constant O12_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1450, 11); 117 + constant O12_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(776, 11); 118 + 119 + -- Upper zone (y ~320-500) 120 + constant O13_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(200, 11); 121 + constant O13_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(450, 11); 122 + constant O13_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(420, 11); 123 + constant O13_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(466, 11); 124 + 125 + constant O14_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(620, 11); 126 + constant O14_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(380, 11); 127 + constant O14_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(820, 11); 128 + constant O14_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(396, 11); 129 + 130 + constant O15_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1000, 11); 131 + constant O15_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(320, 11); 132 + constant O15_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1200, 11); 133 + constant O15_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(336, 11); 134 + 135 + constant O16_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1320, 11); 136 + constant O16_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(420, 11); 137 + constant O16_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1460, 11); 138 + constant O16_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(436, 11); 139 + 140 + -- Animation 141 + signal squish : std_logic_vector(3 downto 0) := (others => '0'); 142 + signal squish_h : std_logic := '0'; 143 + signal on_ground : std_logic := '0'; 144 + signal jump_pressed : std_logic := '0'; 145 + 146 + begin 147 + 148 + char_x <= pos_x; 149 + char_y <= pos_y; 150 + cam_x <= cam_x_sig; 151 + cam_y <= cam_y_sig; 152 + 153 + char_width <= SIZE + ("000000" & squish) when squish_h = '0' 154 + else SIZE - ("000000" & squish(3 downto 1)); 155 + char_height <= SIZE - ("000000" & squish(3 downto 1)) when squish_h = '0' 156 + else SIZE + ("000000" & squish); 157 + 158 + physics : process 159 + variable vx, vy : std_logic_vector(9 downto 0); 160 + variable px, py : std_logic_vector(10 downto 0); 161 + variable bounced : std_logic; 162 + variable bounce_wall : std_logic; 163 + variable bounce_speed: std_logic_vector(9 downto 0); 164 + variable grounded : std_logic; 165 + variable c_left, c_right, c_top, c_bot : std_logic_vector(10 downto 0); 166 + variable overlap_x, overlap_y : std_logic_vector(10 downto 0); 167 + begin 168 + wait until vert_sync'event and vert_sync = '1'; 169 + 170 + vx := vel_x; vy := vel_y; 171 + bounced := '0'; bounce_wall := '0'; 172 + bounce_speed := (others => '0'); 173 + grounded := '0'; 174 + 175 + -- == INPUT == 176 + if key_w = '0' then jump_pressed <= '0'; end if; 177 + 178 + if key_w = '1' and jump_pressed = '0' and on_ground = '1' then 179 + vy := (others => '0'); 180 + vy := vy - JUMP_FORCE; 181 + jump_pressed <= '1'; 182 + end if; 183 + 184 + if key_w = '1' and jump_pressed = '1' and on_ground = '1' then 185 + vy := vy - 4; 186 + end if; 187 + 188 + if key_s = '1' and on_ground = '0' then vy := vy + IMPULSE; end if; 189 + 190 + if key_a = '1' then 191 + if on_ground = '1' then vx := vx - IMPULSE; else vx := vx - 2; end if; 192 + end if; 193 + if key_d = '1' then 194 + if on_ground = '1' then vx := vx + IMPULSE; else vx := vx + 2; end if; 195 + end if; 196 + 197 + -- == GRAVITY == 198 + vy := vy + GRAVITY; 199 + 200 + -- == FRICTION: vel -= vel/4, min 1 == 201 + if vx(9) = '0' then 202 + if vx > 0 then 203 + if vx(9 downto 2) = "00000000" then vx := vx - 1; 204 + else vx := vx - ("000" & vx(9 downto 3)); end if; 205 + end if; 206 + else 207 + if vx /= "0000000000" then 208 + if vx(9 downto 2) = "11111111" then vx := vx + 1; 209 + else vx := vx - ("11" & vx(9 downto 2)); end if; 210 + end if; 211 + end if; 212 + 213 + -- == CLAMP velocities == 214 + if vx(9) = '0' and vx > MAX_VEL_X then vx := MAX_VEL_X; end if; 215 + if vx(9) = '1' and vx < (not MAX_VEL_X) + 1 then vx := (not MAX_VEL_X) + 1; end if; 216 + if vy(9) = '0' and vy > 63 then vy := CONV_STD_LOGIC_VECTOR(63, 10); end if; 217 + if vy(9) = '1' and vy < CONV_STD_LOGIC_VECTOR(960, 10) then 218 + vy := CONV_STD_LOGIC_VECTOR(960, 10); 219 + end if; 220 + 221 + -- == MOVE: sign-extend 10-bit velocity to 11-bit before adding == 222 + px := pos_x + (vx(9) & vx); 223 + py := pos_y + (vy(9) & vy); 224 + 225 + -- == GROUND == 226 + if py >= GROUND then 227 + py := GROUND; 228 + bounced := '1'; grounded := '1'; 229 + bounce_speed := vy; 230 + vy := (not vy) + 1; 231 + if vy(9) = '1' then 232 + vy := vy + ("000" & ((not vy(9 downto 3)) + 1)); 233 + end if; 234 + if vy(9) = '1' and vy >= CONV_STD_LOGIC_VECTOR(1022, 10) then 235 + vy := (others => '0'); 236 + elsif vy(9) = '0' then vy := (others => '0'); end if; 237 + end if; 238 + 239 + -- == CEILING (py(10)='1' catches negative-wrap underflow) == 240 + if py(10) = '1' or py <= CEILING then 241 + py := CEILING; 242 + bounced := '1'; 243 + bounce_speed := (not vy) + 1; 244 + vy := (not vy) + 1; 245 + if vy(9) = '0' and vy > 1 then 246 + vy := vy - ("000" & vy(9 downto 3)); 247 + end if; 248 + end if; 249 + 250 + -- == LEFT WALL (px(10)='1' catches underflow) == 251 + if px(10) = '1' or px <= LEFT_WALL + SIZE11 then 252 + px := LEFT_WALL + SIZE11; 253 + bounced := '1'; bounce_wall := '1'; 254 + bounce_speed := (not vx) + 1; 255 + vx := (not vx) + 1; 256 + if vx(9) = '0' and vx > 1 then 257 + vx := vx - ("000" & vx(9 downto 3)); 258 + end if; 259 + end if; 260 + 261 + -- == RIGHT WALL == 262 + if px >= RIGHT_WALL - SIZE11 then 263 + px := RIGHT_WALL - SIZE11; 264 + bounced := '1'; bounce_wall := '1'; 265 + bounce_speed := vx; 266 + vx := (not vx) + 1; 267 + if vx(9) = '1' then 268 + vx := vx + ("000" & ((not vx(9 downto 3)) + 1)); 269 + end if; 270 + if vx(9) = '1' and vx >= CONV_STD_LOGIC_VECTOR(1022, 10) then 271 + vx := (others => '0'); 272 + end if; 273 + end if; 274 + 275 + -- == OBSTACLE COLLISIONS == 276 + -- Shared bounce helpers (vert and horiz) used identically per obstacle. 277 + 278 + -- O1 279 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 280 + if c_right>=O1_L and c_left<=O1_R and c_bot>=O1_T and c_top<=O1_B then 281 + if vy(9)='0' then overlap_y:=c_bot-O1_T; else overlap_y:=O1_B-c_top; end if; 282 + if vx(9)='0' then overlap_x:=c_right-O1_L; else overlap_x:=O1_R-c_left; end if; 283 + if overlap_y<=overlap_x then 284 + if vy(9)='0' then py:=O1_T-SIZE11; grounded:='1'; else py:=O1_B+SIZE11; end if; 285 + bounced:='1'; 286 + vy:=(not vy)+1; 287 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 288 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 289 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 290 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 291 + else 292 + if vx(9)='0' then px:=O1_L-SIZE11; else px:=O1_R+SIZE11; end if; 293 + bounced:='1'; bounce_wall:='1'; 294 + vx:=(not vx)+1; 295 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 296 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 297 + end if; 298 + end if; 299 + 300 + -- O2 301 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 302 + if c_right>=O2_L and c_left<=O2_R and c_bot>=O2_T and c_top<=O2_B then 303 + if vy(9)='0' then overlap_y:=c_bot-O2_T; else overlap_y:=O2_B-c_top; end if; 304 + if vx(9)='0' then overlap_x:=c_right-O2_L; else overlap_x:=O2_R-c_left; end if; 305 + if overlap_y<=overlap_x then 306 + if vy(9)='0' then py:=O2_T-SIZE11; grounded:='1'; else py:=O2_B+SIZE11; end if; 307 + bounced:='1'; 308 + vy:=(not vy)+1; 309 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 310 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 311 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 312 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 313 + else 314 + if vx(9)='0' then px:=O2_L-SIZE11; else px:=O2_R+SIZE11; end if; 315 + bounced:='1'; bounce_wall:='1'; 316 + vx:=(not vx)+1; 317 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 318 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 319 + end if; 320 + end if; 321 + 322 + -- O3 323 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 324 + if c_right>=O3_L and c_left<=O3_R and c_bot>=O3_T and c_top<=O3_B then 325 + if vy(9)='0' then overlap_y:=c_bot-O3_T; else overlap_y:=O3_B-c_top; end if; 326 + if vx(9)='0' then overlap_x:=c_right-O3_L; else overlap_x:=O3_R-c_left; end if; 327 + if overlap_y<=overlap_x then 328 + if vy(9)='0' then py:=O3_T-SIZE11; grounded:='1'; else py:=O3_B+SIZE11; end if; 329 + bounced:='1'; 330 + vy:=(not vy)+1; 331 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 332 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 333 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 334 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 335 + else 336 + if vx(9)='0' then px:=O3_L-SIZE11; else px:=O3_R+SIZE11; end if; 337 + bounced:='1'; bounce_wall:='1'; 338 + vx:=(not vx)+1; 339 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 340 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 341 + end if; 342 + end if; 343 + 344 + -- O4 345 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 346 + if c_right>=O4_L and c_left<=O4_R and c_bot>=O4_T and c_top<=O4_B then 347 + if vy(9)='0' then overlap_y:=c_bot-O4_T; else overlap_y:=O4_B-c_top; end if; 348 + if vx(9)='0' then overlap_x:=c_right-O4_L; else overlap_x:=O4_R-c_left; end if; 349 + if overlap_y<=overlap_x then 350 + if vy(9)='0' then py:=O4_T-SIZE11; grounded:='1'; else py:=O4_B+SIZE11; end if; 351 + bounced:='1'; 352 + vy:=(not vy)+1; 353 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 354 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 355 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 356 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 357 + else 358 + if vx(9)='0' then px:=O4_L-SIZE11; else px:=O4_R+SIZE11; end if; 359 + bounced:='1'; bounce_wall:='1'; 360 + vx:=(not vx)+1; 361 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 362 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 363 + end if; 364 + end if; 365 + 366 + -- O5 367 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 368 + if c_right>=O5_L and c_left<=O5_R and c_bot>=O5_T and c_top<=O5_B then 369 + if vy(9)='0' then overlap_y:=c_bot-O5_T; else overlap_y:=O5_B-c_top; end if; 370 + if vx(9)='0' then overlap_x:=c_right-O5_L; else overlap_x:=O5_R-c_left; end if; 371 + if overlap_y<=overlap_x then 372 + if vy(9)='0' then py:=O5_T-SIZE11; grounded:='1'; else py:=O5_B+SIZE11; end if; 373 + bounced:='1'; 374 + vy:=(not vy)+1; 375 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 376 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 377 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 378 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 379 + else 380 + if vx(9)='0' then px:=O5_L-SIZE11; else px:=O5_R+SIZE11; end if; 381 + bounced:='1'; bounce_wall:='1'; 382 + vx:=(not vx)+1; 383 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 384 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 385 + end if; 386 + end if; 387 + 388 + -- O6 389 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 390 + if c_right>=O6_L and c_left<=O6_R and c_bot>=O6_T and c_top<=O6_B then 391 + if vy(9)='0' then overlap_y:=c_bot-O6_T; else overlap_y:=O6_B-c_top; end if; 392 + if vx(9)='0' then overlap_x:=c_right-O6_L; else overlap_x:=O6_R-c_left; end if; 393 + if overlap_y<=overlap_x then 394 + if vy(9)='0' then py:=O6_T-SIZE11; grounded:='1'; else py:=O6_B+SIZE11; end if; 395 + bounced:='1'; 396 + vy:=(not vy)+1; 397 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 398 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 399 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 400 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 401 + else 402 + if vx(9)='0' then px:=O6_L-SIZE11; else px:=O6_R+SIZE11; end if; 403 + bounced:='1'; bounce_wall:='1'; 404 + vx:=(not vx)+1; 405 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 406 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 407 + end if; 408 + end if; 409 + 410 + -- O7 411 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 412 + if c_right>=O7_L and c_left<=O7_R and c_bot>=O7_T and c_top<=O7_B then 413 + if vy(9)='0' then overlap_y:=c_bot-O7_T; else overlap_y:=O7_B-c_top; end if; 414 + if vx(9)='0' then overlap_x:=c_right-O7_L; else overlap_x:=O7_R-c_left; end if; 415 + if overlap_y<=overlap_x then 416 + if vy(9)='0' then py:=O7_T-SIZE11; grounded:='1'; else py:=O7_B+SIZE11; end if; 417 + bounced:='1'; 418 + vy:=(not vy)+1; 419 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 420 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 421 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 422 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 423 + else 424 + if vx(9)='0' then px:=O7_L-SIZE11; else px:=O7_R+SIZE11; end if; 425 + bounced:='1'; bounce_wall:='1'; 426 + vx:=(not vx)+1; 427 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 428 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 429 + end if; 430 + end if; 431 + 432 + -- O8 433 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 434 + if c_right>=O8_L and c_left<=O8_R and c_bot>=O8_T and c_top<=O8_B then 435 + if vy(9)='0' then overlap_y:=c_bot-O8_T; else overlap_y:=O8_B-c_top; end if; 436 + if vx(9)='0' then overlap_x:=c_right-O8_L; else overlap_x:=O8_R-c_left; end if; 437 + if overlap_y<=overlap_x then 438 + if vy(9)='0' then py:=O8_T-SIZE11; grounded:='1'; else py:=O8_B+SIZE11; end if; 439 + bounced:='1'; 440 + vy:=(not vy)+1; 441 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 442 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 443 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 444 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 445 + else 446 + if vx(9)='0' then px:=O8_L-SIZE11; else px:=O8_R+SIZE11; end if; 447 + bounced:='1'; bounce_wall:='1'; 448 + vx:=(not vx)+1; 449 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 450 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 451 + end if; 452 + end if; 453 + 454 + -- O9 455 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 456 + if c_right>=O9_L and c_left<=O9_R and c_bot>=O9_T and c_top<=O9_B then 457 + if vy(9)='0' then overlap_y:=c_bot-O9_T; else overlap_y:=O9_B-c_top; end if; 458 + if vx(9)='0' then overlap_x:=c_right-O9_L; else overlap_x:=O9_R-c_left; end if; 459 + if overlap_y<=overlap_x then 460 + if vy(9)='0' then py:=O9_T-SIZE11; grounded:='1'; else py:=O9_B+SIZE11; end if; 461 + bounced:='1'; 462 + vy:=(not vy)+1; 463 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 464 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 465 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 466 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 467 + else 468 + if vx(9)='0' then px:=O9_L-SIZE11; else px:=O9_R+SIZE11; end if; 469 + bounced:='1'; bounce_wall:='1'; 470 + vx:=(not vx)+1; 471 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 472 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 473 + end if; 474 + end if; 475 + 476 + -- O10 477 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 478 + if c_right>=O10_L and c_left<=O10_R and c_bot>=O10_T and c_top<=O10_B then 479 + if vy(9)='0' then overlap_y:=c_bot-O10_T; else overlap_y:=O10_B-c_top; end if; 480 + if vx(9)='0' then overlap_x:=c_right-O10_L; else overlap_x:=O10_R-c_left; end if; 481 + if overlap_y<=overlap_x then 482 + if vy(9)='0' then py:=O10_T-SIZE11; grounded:='1'; else py:=O10_B+SIZE11; end if; 483 + bounced:='1'; 484 + vy:=(not vy)+1; 485 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 486 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 487 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 488 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 489 + else 490 + if vx(9)='0' then px:=O10_L-SIZE11; else px:=O10_R+SIZE11; end if; 491 + bounced:='1'; bounce_wall:='1'; 492 + vx:=(not vx)+1; 493 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 494 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 495 + end if; 496 + end if; 497 + 498 + -- O11 499 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 500 + if c_right>=O11_L and c_left<=O11_R and c_bot>=O11_T and c_top<=O11_B then 501 + if vy(9)='0' then overlap_y:=c_bot-O11_T; else overlap_y:=O11_B-c_top; end if; 502 + if vx(9)='0' then overlap_x:=c_right-O11_L; else overlap_x:=O11_R-c_left; end if; 503 + if overlap_y<=overlap_x then 504 + if vy(9)='0' then py:=O11_T-SIZE11; grounded:='1'; else py:=O11_B+SIZE11; end if; 505 + bounced:='1'; 506 + vy:=(not vy)+1; 507 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 508 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 509 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 510 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 511 + else 512 + if vx(9)='0' then px:=O11_L-SIZE11; else px:=O11_R+SIZE11; end if; 513 + bounced:='1'; bounce_wall:='1'; 514 + vx:=(not vx)+1; 515 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 516 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 517 + end if; 518 + end if; 519 + 520 + -- O12 521 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 522 + if c_right>=O12_L and c_left<=O12_R and c_bot>=O12_T and c_top<=O12_B then 523 + if vy(9)='0' then overlap_y:=c_bot-O12_T; else overlap_y:=O12_B-c_top; end if; 524 + if vx(9)='0' then overlap_x:=c_right-O12_L; else overlap_x:=O12_R-c_left; end if; 525 + if overlap_y<=overlap_x then 526 + if vy(9)='0' then py:=O12_T-SIZE11; grounded:='1'; else py:=O12_B+SIZE11; end if; 527 + bounced:='1'; 528 + vy:=(not vy)+1; 529 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 530 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 531 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 532 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 533 + else 534 + if vx(9)='0' then px:=O12_L-SIZE11; else px:=O12_R+SIZE11; end if; 535 + bounced:='1'; bounce_wall:='1'; 536 + vx:=(not vx)+1; 537 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 538 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 539 + end if; 540 + end if; 541 + 542 + -- O13 543 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 544 + if c_right>=O13_L and c_left<=O13_R and c_bot>=O13_T and c_top<=O13_B then 545 + if vy(9)='0' then overlap_y:=c_bot-O13_T; else overlap_y:=O13_B-c_top; end if; 546 + if vx(9)='0' then overlap_x:=c_right-O13_L; else overlap_x:=O13_R-c_left; end if; 547 + if overlap_y<=overlap_x then 548 + if vy(9)='0' then py:=O13_T-SIZE11; grounded:='1'; else py:=O13_B+SIZE11; end if; 549 + bounced:='1'; 550 + vy:=(not vy)+1; 551 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 552 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 553 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 554 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 555 + else 556 + if vx(9)='0' then px:=O13_L-SIZE11; else px:=O13_R+SIZE11; end if; 557 + bounced:='1'; bounce_wall:='1'; 558 + vx:=(not vx)+1; 559 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 560 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 561 + end if; 562 + end if; 563 + 564 + -- O14 565 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 566 + if c_right>=O14_L and c_left<=O14_R and c_bot>=O14_T and c_top<=O14_B then 567 + if vy(9)='0' then overlap_y:=c_bot-O14_T; else overlap_y:=O14_B-c_top; end if; 568 + if vx(9)='0' then overlap_x:=c_right-O14_L; else overlap_x:=O14_R-c_left; end if; 569 + if overlap_y<=overlap_x then 570 + if vy(9)='0' then py:=O14_T-SIZE11; grounded:='1'; else py:=O14_B+SIZE11; end if; 571 + bounced:='1'; 572 + vy:=(not vy)+1; 573 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 574 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 575 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 576 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 577 + else 578 + if vx(9)='0' then px:=O14_L-SIZE11; else px:=O14_R+SIZE11; end if; 579 + bounced:='1'; bounce_wall:='1'; 580 + vx:=(not vx)+1; 581 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 582 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 583 + end if; 584 + end if; 585 + 586 + -- O15 587 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 588 + if c_right>=O15_L and c_left<=O15_R and c_bot>=O15_T and c_top<=O15_B then 589 + if vy(9)='0' then overlap_y:=c_bot-O15_T; else overlap_y:=O15_B-c_top; end if; 590 + if vx(9)='0' then overlap_x:=c_right-O15_L; else overlap_x:=O15_R-c_left; end if; 591 + if overlap_y<=overlap_x then 592 + if vy(9)='0' then py:=O15_T-SIZE11; grounded:='1'; else py:=O15_B+SIZE11; end if; 593 + bounced:='1'; 594 + vy:=(not vy)+1; 595 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 596 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 597 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 598 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 599 + else 600 + if vx(9)='0' then px:=O15_L-SIZE11; else px:=O15_R+SIZE11; end if; 601 + bounced:='1'; bounce_wall:='1'; 602 + vx:=(not vx)+1; 603 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 604 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 605 + end if; 606 + end if; 607 + 608 + -- O16 609 + c_left:=px-SIZE11; c_right:=px+SIZE11; c_top:=py-SIZE11; c_bot:=py+SIZE11; 610 + if c_right>=O16_L and c_left<=O16_R and c_bot>=O16_T and c_top<=O16_B then 611 + if vy(9)='0' then overlap_y:=c_bot-O16_T; else overlap_y:=O16_B-c_top; end if; 612 + if vx(9)='0' then overlap_x:=c_right-O16_L; else overlap_x:=O16_R-c_left; end if; 613 + if overlap_y<=overlap_x then 614 + if vy(9)='0' then py:=O16_T-SIZE11; grounded:='1'; else py:=O16_B+SIZE11; end if; 615 + bounced:='1'; 616 + vy:=(not vy)+1; 617 + if vy(9)='0' and vy>1 then vy:=vy-("000"&vy(9 downto 3)); 618 + elsif vy(9)='1' and vy<CONV_STD_LOGIC_VECTOR(1022,10) then vy:=vy+("000"&((not vy(9 downto 3))+1)); end if; 619 + if vy(9)='0' and vy<2 then vy:=(others=>'0'); end if; 620 + if vy(9)='1' and vy>=CONV_STD_LOGIC_VECTOR(1022,10) then vy:=(others=>'0'); end if; 621 + else 622 + if vx(9)='0' then px:=O16_L-SIZE11; else px:=O16_R+SIZE11; end if; 623 + bounced:='1'; bounce_wall:='1'; 624 + vx:=(not vx)+1; 625 + if vx(9)='0' and vx>1 then vx:=vx-("000"&vx(9 downto 3)); 626 + elsif vx(9)='1' and vx<CONV_STD_LOGIC_VECTOR(1022,10) then vx:=vx+("000"&((not vx(9 downto 3))+1)); end if; 627 + end if; 628 + end if; 629 + 630 + -- == COMMIT == 631 + vel_x <= vx; 632 + vel_y <= vy; 633 + pos_x <= px; 634 + pos_y <= py; 635 + 636 + -- == CAMERA: center on character (px/py), clamp to world == 637 + -- cam_x = clamp(px - 320, 0, 860) [world 1500 - screen 640 = 860] 638 + if px < CONV_STD_LOGIC_VECTOR(320, 11) then 639 + cam_x_sig <= (others => '0'); 640 + elsif px > CONV_STD_LOGIC_VECTOR(1180, 11) then 641 + cam_x_sig <= CONV_STD_LOGIC_VECTOR(860, 11); 642 + else 643 + cam_x_sig <= px - CONV_STD_LOGIC_VECTOR(320, 11); 644 + end if; 645 + 646 + -- cam_y = clamp(py - 240, 0, 1020) [world 1500 - screen 480 = 1020] 647 + if py < CONV_STD_LOGIC_VECTOR(240, 11) then 648 + cam_y_sig <= (others => '0'); 649 + elsif py > CONV_STD_LOGIC_VECTOR(1260, 11) then 650 + cam_y_sig <= CONV_STD_LOGIC_VECTOR(1020, 11); 651 + else 652 + cam_y_sig <= py - CONV_STD_LOGIC_VECTOR(240, 11); 653 + end if; 654 + 655 + -- == SQUISH == 656 + if bounced = '1' and bounce_speed > 3 then 657 + if bounce_speed >= 8 then squish <= "1000"; 658 + else squish <= bounce_speed(3 downto 0); end if; 659 + squish_h <= bounce_wall; 660 + elsif squish > 0 then 661 + squish <= squish - 1; 662 + end if; 663 + 664 + if grounded = '1' then on_ground <= '1'; 665 + elsif py < GROUND - 1 then on_ground <= '0'; end if; 666 + 667 + end process physics; 668 + 669 + end behavior;
+189 -120
renderer.vhd
··· 1 - -- ======================================================================== 2 - -- Renderer 3 - -- Combinational logic: given the current pixel position and character 4 - -- state, outputs the RGB color for that pixel. 5 - -- 6 - -- Draws: character (red), 4 obstacles (yellow), ground/ceiling (green), 7 - -- walls (cyan), sky (black) 8 - -- ======================================================================== 9 - 10 - library IEEE; 11 - use IEEE.STD_LOGIC_1164.all; 12 - use IEEE.STD_LOGIC_ARITH.all; 13 - use IEEE.STD_LOGIC_UNSIGNED.all; 14 - 15 - entity renderer is 16 - port( 17 - pixel_row : in std_logic_vector(9 downto 0); -- from vga_sync 18 - pixel_column : in std_logic_vector(9 downto 0); -- from vga_sync 19 - char_x : in std_logic_vector(9 downto 0); -- from physics 20 - char_y : in std_logic_vector(9 downto 0); -- from physics 21 - char_width : in std_logic_vector(9 downto 0); -- from physics (animated) 22 - char_height : in std_logic_vector(9 downto 0); -- from physics (animated) 23 - red : out std_logic; 24 - green : out std_logic; 25 - blue : out std_logic 26 - ); 27 - end renderer; 28 - 29 - architecture behavior of renderer is 30 - 31 - -- Screen boundaries 32 - constant GROUND_TOP : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(448, 10); 33 - constant CEIL_BOT : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(8, 10); 34 - constant LEFT_WALL : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(8, 10); 35 - constant RIGHT_WALL : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(631, 10); 36 - 37 - -- Obstacle positions (must match physics_engine) 38 - constant O1_L : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(60, 10); 39 - constant O1_T : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(370, 10); 40 - constant O1_R : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(180, 10); 41 - constant O1_B : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(386, 10); 42 - 43 - constant O2_L : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(250, 10); 44 - constant O2_T : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(300, 10); 45 - constant O2_R : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(390, 10); 46 - constant O2_B : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(316, 10); 47 - 48 - constant O3_L : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(440, 10); 49 - constant O3_T : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(200, 10); 50 - constant O3_R : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(580, 10); 51 - constant O3_B : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(216, 10); 52 - 53 - constant O4_L : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(140, 10); 54 - constant O4_T : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(120, 10); 55 - constant O4_R : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(200, 10); 56 - constant O4_B : std_logic_vector(9 downto 0) := CONV_STD_LOGIC_VECTOR(150, 10); 57 - 58 - signal char_on, ground_on, wall_on, ceiling_on, obs_on : std_logic; 59 - 60 - begin 61 - 62 - -- Check what the current pixel overlaps 63 - render : process(pixel_row, pixel_column, char_x, char_y, 64 - char_width, char_height) 65 - begin 66 - char_on <= '0'; 67 - ground_on <= '0'; 68 - wall_on <= '0'; 69 - ceiling_on <= '0'; 70 - obs_on <= '0'; 71 - 72 - -- Character 73 - if (pixel_column >= char_x - char_width) and 74 - (pixel_column <= char_x + char_width) and 75 - (pixel_row >= char_y - char_height) and 76 - (pixel_row <= char_y + char_height) then 77 - char_on <= '1'; 78 - end if; 79 - 80 - -- Ground 81 - if pixel_row >= GROUND_TOP then ground_on <= '1'; end if; 82 - 83 - -- Ceiling 84 - if pixel_row <= CEIL_BOT then ceiling_on <= '1'; end if; 85 - 86 - -- Walls 87 - if (pixel_column < LEFT_WALL) or (pixel_column > RIGHT_WALL) then 88 - wall_on <= '1'; 89 - end if; 90 - 91 - -- Obstacles 92 - if (pixel_column >= O1_L) and (pixel_column <= O1_R) and 93 - (pixel_row >= O1_T) and (pixel_row <= O1_B) then obs_on <= '1'; end if; 94 - if (pixel_column >= O2_L) and (pixel_column <= O2_R) and 95 - (pixel_row >= O2_T) and (pixel_row <= O2_B) then obs_on <= '1'; end if; 96 - if (pixel_column >= O3_L) and (pixel_column <= O3_R) and 97 - (pixel_row >= O3_T) and (pixel_row <= O3_B) then obs_on <= '1'; end if; 98 - if (pixel_column >= O4_L) and (pixel_column <= O4_R) and 99 - (pixel_row >= O4_T) and (pixel_row <= O4_B) then obs_on <= '1'; end if; 100 - end process render; 101 - 102 - -- Priority color encoder 103 - -- Character=Red(100), Obstacles=Yellow(110), Ground/Ceil=Green(010), 104 - -- Walls=Green(010), Sky=Black(000) 105 - color : process(char_on, ground_on, wall_on, ceiling_on, obs_on) 106 - begin 107 - if char_on = '1' then 108 - red <= '1'; green <= '0'; blue <= '0'; 109 - elsif obs_on = '1' then 110 - red <= '1'; green <= '1'; blue <= '0'; 111 - elsif ground_on = '1' or ceiling_on = '1' then 112 - red <= '0'; green <= '1'; blue <= '0'; 113 - elsif wall_on = '1' then 114 - red <= '0'; green <= '1'; blue <= '0'; 115 - else 116 - red <= '0'; green <= '0'; blue <= '0'; 117 - end if; 118 - end process color; 119 - 120 - end behavior; 1 + -- ======================================================================== 2 + -- Renderer (scrolling world) 3 + -- Converts screen pixel (col, row) to world coords via camera offset, 4 + -- then tests world-space position against all geometry. 5 + -- 6 + -- world_col = pixel_column + cam_x 7 + -- world_row = pixel_row + cam_y 8 + -- 9 + -- All boundary/obstacle constants are in world-space (11-bit). 10 + -- ======================================================================== 11 + 12 + library IEEE; 13 + use IEEE.STD_LOGIC_1164.all; 14 + use IEEE.STD_LOGIC_ARITH.all; 15 + use IEEE.STD_LOGIC_UNSIGNED.all; 16 + 17 + entity renderer is 18 + port( 19 + pixel_row : in std_logic_vector(9 downto 0); 20 + pixel_column : in std_logic_vector(9 downto 0); 21 + char_x : in std_logic_vector(10 downto 0); 22 + char_y : in std_logic_vector(10 downto 0); 23 + char_width : in std_logic_vector(9 downto 0); 24 + char_height : in std_logic_vector(9 downto 0); 25 + cam_x : in std_logic_vector(10 downto 0); 26 + cam_y : in std_logic_vector(10 downto 0); 27 + red : out std_logic; 28 + green : out std_logic; 29 + blue : out std_logic 30 + ); 31 + end renderer; 32 + 33 + architecture behavior of renderer is 34 + 35 + -- World boundaries (11-bit) 36 + constant GROUND_TOP : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1488, 11); 37 + constant CEIL_BOT : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(8, 11); 38 + constant LEFT_WALL : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(8, 11); 39 + constant RIGHT_WALL : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1492, 11); 40 + 41 + -- Obstacle positions (must match physics_engine, 11-bit world-space) 42 + constant O1_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(100, 11); 43 + constant O1_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1380, 11); 44 + constant O1_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(280, 11); 45 + constant O1_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1396, 11); 46 + 47 + constant O2_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(450, 11); 48 + constant O2_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1320, 11); 49 + constant O2_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(530, 11); 50 + constant O2_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1336, 11); 51 + 52 + constant O3_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(750, 11); 53 + constant O3_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1390, 11); 54 + constant O3_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(950, 11); 55 + constant O3_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1406, 11); 56 + 57 + constant O4_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1150, 11); 58 + constant O4_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1300, 11); 59 + constant O4_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1380, 11); 60 + constant O4_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1316, 11); 61 + 62 + constant O5_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(60, 11); 63 + constant O5_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1100, 11); 64 + constant O5_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(250, 11); 65 + constant O5_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1116, 11); 66 + 67 + constant O6_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(400, 11); 68 + constant O6_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1050, 11); 69 + constant O6_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(550, 11); 70 + constant O6_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1066, 11); 71 + 72 + constant O7_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(720, 11); 73 + constant O7_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1000, 11); 74 + constant O7_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(920, 11); 75 + constant O7_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1016, 11); 76 + 77 + constant O8_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1100, 11); 78 + constant O8_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1120, 11); 79 + constant O8_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1350, 11); 80 + constant O8_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1136, 11); 81 + 82 + constant O9_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(150, 11); 83 + constant O9_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(780, 11); 84 + constant O9_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(380, 11); 85 + constant O9_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(796, 11); 86 + 87 + constant O10_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(550, 11); 88 + constant O10_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(700, 11); 89 + constant O10_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(650, 11); 90 + constant O10_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(716, 11); 91 + 92 + constant O11_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(850, 11); 93 + constant O11_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(650, 11); 94 + constant O11_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1050, 11); 95 + constant O11_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(666, 11); 96 + 97 + constant O12_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1200, 11); 98 + constant O12_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(760, 11); 99 + constant O12_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1450, 11); 100 + constant O12_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(776, 11); 101 + 102 + constant O13_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(200, 11); 103 + constant O13_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(450, 11); 104 + constant O13_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(420, 11); 105 + constant O13_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(466, 11); 106 + 107 + constant O14_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(620, 11); 108 + constant O14_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(380, 11); 109 + constant O14_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(820, 11); 110 + constant O14_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(396, 11); 111 + 112 + constant O15_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1000, 11); 113 + constant O15_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(320, 11); 114 + constant O15_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1200, 11); 115 + constant O15_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(336, 11); 116 + 117 + constant O16_L : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1320, 11); 118 + constant O16_T : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(420, 11); 119 + constant O16_R : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(1460, 11); 120 + constant O16_B : std_logic_vector(10 downto 0) := CONV_STD_LOGIC_VECTOR(436, 11); 121 + 122 + signal char_on, ground_on, wall_on, ceiling_on, obs_on : std_logic; 123 + 124 + begin 125 + 126 + render : process(pixel_row, pixel_column, char_x, char_y, 127 + char_width, char_height, cam_x, cam_y) 128 + variable wc : std_logic_vector(10 downto 0); -- world column 129 + variable wr : std_logic_vector(10 downto 0); -- world row 130 + begin 131 + wc := ('0' & pixel_column) + cam_x; 132 + wr := ('0' & pixel_row) + cam_y; 133 + 134 + char_on <= '0'; 135 + ground_on <= '0'; 136 + wall_on <= '0'; 137 + ceiling_on <= '0'; 138 + obs_on <= '0'; 139 + 140 + -- Character 141 + if wc >= char_x - ('0' & char_width) and 142 + wc <= char_x + ('0' & char_width) and 143 + wr >= char_y - ('0' & char_height) and 144 + wr <= char_y + ('0' & char_height) then 145 + char_on <= '1'; 146 + end if; 147 + 148 + -- Ground / ceiling / walls (world edges) 149 + if wr >= GROUND_TOP then ground_on <= '1'; end if; 150 + if wr <= CEIL_BOT then ceiling_on <= '1'; end if; 151 + if wc < LEFT_WALL or wc > RIGHT_WALL then wall_on <= '1'; end if; 152 + 153 + -- Obstacles 154 + if wc>=O1_L and wc<=O1_R and wr>=O1_T and wr<=O1_B then obs_on<='1'; end if; 155 + if wc>=O2_L and wc<=O2_R and wr>=O2_T and wr<=O2_B then obs_on<='1'; end if; 156 + if wc>=O3_L and wc<=O3_R and wr>=O3_T and wr<=O3_B then obs_on<='1'; end if; 157 + if wc>=O4_L and wc<=O4_R and wr>=O4_T and wr<=O4_B then obs_on<='1'; end if; 158 + if wc>=O5_L and wc<=O5_R and wr>=O5_T and wr<=O5_B then obs_on<='1'; end if; 159 + if wc>=O6_L and wc<=O6_R and wr>=O6_T and wr<=O6_B then obs_on<='1'; end if; 160 + if wc>=O7_L and wc<=O7_R and wr>=O7_T and wr<=O7_B then obs_on<='1'; end if; 161 + if wc>=O8_L and wc<=O8_R and wr>=O8_T and wr<=O8_B then obs_on<='1'; end if; 162 + if wc>=O9_L and wc<=O9_R and wr>=O9_T and wr<=O9_B then obs_on<='1'; end if; 163 + if wc>=O10_L and wc<=O10_R and wr>=O10_T and wr<=O10_B then obs_on<='1'; end if; 164 + if wc>=O11_L and wc<=O11_R and wr>=O11_T and wr<=O11_B then obs_on<='1'; end if; 165 + if wc>=O12_L and wc<=O12_R and wr>=O12_T and wr<=O12_B then obs_on<='1'; end if; 166 + if wc>=O13_L and wc<=O13_R and wr>=O13_T and wr<=O13_B then obs_on<='1'; end if; 167 + if wc>=O14_L and wc<=O14_R and wr>=O14_T and wr<=O14_B then obs_on<='1'; end if; 168 + if wc>=O15_L and wc<=O15_R and wr>=O15_T and wr<=O15_B then obs_on<='1'; end if; 169 + if wc>=O16_L and wc<=O16_R and wr>=O16_T and wr<=O16_B then obs_on<='1'; end if; 170 + 171 + end process render; 172 + 173 + -- Priority: char=Red(100), obstacles=Yellow(110), ground/ceil/walls=Green(010), sky=Black 174 + color : process(char_on, ground_on, wall_on, ceiling_on, obs_on) 175 + begin 176 + if char_on = '1' then 177 + red <= '1'; green <= '0'; blue <= '0'; 178 + elsif obs_on = '1' then 179 + red <= '1'; green <= '1'; blue <= '0'; 180 + elsif ground_on = '1' or ceiling_on = '1' then 181 + red <= '0'; green <= '1'; blue <= '0'; 182 + elsif wall_on = '1' then 183 + red <= '0'; green <= '1'; blue <= '0'; 184 + else 185 + red <= '0'; green <= '0'; blue <= '0'; 186 + end if; 187 + end process color; 188 + 189 + end behavior;