LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;USE IEEE.STD_LOGIC_ARITH.ALL;USE IEEE.STD_LOGIC_UNSIGNED.ALL;
ENTITY bat_n_ball IS PORT ( v_sync : IN STD_LOGIC; pixel_row : IN STD_LOGIC_VECTOR(9 DOWNTO 0); pixel_col : IN STD_LOGIC_VECTOR(9 DOWNTO 0); bat_x : IN STD_LOGIC_VECTOR (9 DOWNTO 0); -- current bat x position serve : IN STD_LOGIC; -- initiates serve red : OUT STD_LOGIC; Sw: in STD_LOGIC_VECTOR(6 downto 0); green : OUT STD_LOGIC; blue : OUT STD_LOGIC );END bat_n_ball;
ARCHITECTURE Behavioral OF bat_n_ball IS CONSTANT bsize : INTEGER := 10; -- ball size in pixels SIGNAL bat_w : INTEGER := 75; -- bat width in pixels CONSTANT bat_h : INTEGER := 5; -- bat height in pixels SIGNAL score : INTEGER :=0; -- distance ball moves each frame CONSTANT ball_speed : STD_LOGIC_VECTOR (9 DOWNTO 0) := CONV_STD_LOGIC_VECTOR (6, 10); SIGNAL ball_on : STD_LOGIC; -- indicates whether ball is at current pixel position SIGNAL bat_on : STD_LOGIC; -- indicates whether bat at over current pixel position SIGNAL game_on : STD_LOGIC := '0'; -- indicates whether ball is in play -- current ball position - intitialized to center of screen SIGNAL ball_x : STD_LOGIC_VECTOR(9 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(320, 10); SIGNAL ball_y : STD_LOGIC_VECTOR(9 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(240, 10); -- bat vertical position CONSTANT bat_y : STD_LOGIC_VECTOR(9 DOWNTO 0) := CONV_STD_LOGIC_VECTOR(400, 10); -- current ball motion - initialized to (+ ball_speed) pixels/frame in both X and Y directions SIGNAL ball_x_motion, ball_y_motion : STD_LOGIC_VECTOR(9 DOWNTO 0) := ball_speed;BEGIN red <= NOT bat_on; -- color setup for red ball and cyan bat on white background green <= NOT ball_on; blue <= NOT ball_on; -- process to draw round ball -- set ball_on if current pixel address is covered by ball position balldraw : PROCESS (ball_x, ball_y, pixel_row, pixel_col) IS VARIABLE vx, vy : STD_LOGIC_VECTOR (9 DOWNTO 0); BEGIN IF pixel_col <= ball_x THEN -- vx = |ball_x - pixel_col| vx := ball_x - pixel_col; ELSE vx := pixel_col - ball_x; END IF; IF pixel_row <= ball_y THEN -- vy = |ball_y - pixel_row| vy := ball_y - pixel_row; ELSE vy := pixel_row - ball_y; END IF; IF ((vx * vx) + (vy * vy)) < (bsize * bsize) THEN -- test if radial distance < bsize ball_on <= game_on; ELSE ball_on <= '0'; END IF; END PROCESS; -- process to draw bat -- set bat_on if current pixel address is covered by bat position batdraw : PROCESS (ball_x, pixel_row, pixel_col) IS VARIABLE vx, vy : STD_LOGIC_VECTOR (9 DOWNTO 0); BEGIN IF ((pixel_col >= ball_x - bat_w) OR (ball_x <= bat_w)) AND pixel_col <= ball_x + bat_w AND pixel_row >= bat_y - bat_h AND pixel_row <= bat_y + bat_h THEN bat_on <= '1'; ELSE bat_on <= '0'; END IF; END PROCESS; -- process to move ball once every frame (i.e. once every vsync pulse) mball : PROCESS VARIABLE temp : STD_LOGIC_VECTOR (10 DOWNTO 0); BEGIN WAIT UNTIL rising_edge(v_sync); IF serve = '1' AND game_on = '0' THEN -- test for new serve game_on <= '1'; ball_y_motion <= (NOT ball_speed) + 1; -- set vspeed to (- ball_speed) pixels ELSIF ball_y <= bsize THEN -- bounce off top wall ball_y_motion <= ball_speed; -- set vspeed to (+ ball_speed) pixels ELSIF ball_y + bsize >= 480 THEN -- if ball meets bottom wall ball_y_motion <= (NOT ball_speed) + 1; -- set vspeed to (- ball_speed) pixels game_on <= '0'; -- and make ball disappear bat_w <= 75; END IF; -- allow for bounce off left or right of screen IF ball_x + bsize >= 640 THEN -- bounce off right wall ball_x_motion <= (NOT ball_speed) + 1; -- set hspeed to (- ball_speed) pixels ELSIF ball_x <= bsize THEN -- bounce off left wall ball_x_motion <= ball_speed; -- set hspeed to (+ ball_speed) pixels END IF; -- allow for bounce off bat IF (ball_x + bsize/2) >= (ball_x - bat_w) AND (ball_x - bsize/2) <= (ball_x + bat_w) AND (ball_y + bsize/2) >= (bat_y - bat_h) AND (ball_y - bsize/2) <= (bat_y + bat_h) THEN ball_y_motion <= (NOT ball_speed) + 1; -- set vspeed to (- ball_speed) pixels bat_w<=bat_w-1; END IF; -- compute next ball vertical position -- variable temp adds one more bit to calculation to fix unsigned underflow problems -- when ball_y is close to zero and ball_y_motion is negative temp := ('0' & ball_y) + (ball_y_motion(9) & ball_y_motion); IF game_on = '0' THEN ball_y <= CONV_STD_LOGIC_VECTOR(440, 10); ELSIF temp(10) = '1' THEN ball_y <= (OTHERS => '0'); ELSE ball_y <= temp(9 DOWNTO 0); END IF; -- compute next ball horizontal position -- variable temp adds one more bit to calculation to fix unsigned underflow problems -- when ball_x is close to zero and ball_x_motion is negative temp := ('0' & ball_x) + (ball_x_motion(9) & ball_x_motion); IF temp(10) = '1' THEN ball_x <= (OTHERS => '0'); ELSE ball_x <= temp(9 DOWNTO 0); END IF; END PROCESS;END Behavioral;