-- -- Ark.vhd -- -- This is the game logic -- -- Written by Tyler Brandon, Kevin Lister, Chris Blasko -- U of Alberta -- -- Total logic cells used: 588/1152 ( 51%) -- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_ARITH.all; use ieee.std_logic_UNSIGNED.all; LIBRARY lpm; USE lpm.lpm_components.ALL; entity Ark is port( Clock : in std_logic; --reset : in std_logic; move_left : in std_logic; move_right : in std_logic; v_sync : in std_logic; collide : out std_logic; blocks_gone : in std_logic; OBall_x : out std_logic_vector(10 downto 0); OBall_y : out std_logic_vector(10 downto 0); Opaddle_x : out std_logic_vector(10 downto 0); Olives : out std_logic_vector(1 downto 0); signal blockaddress : in std_logic_vector(9 downto 0); signal blockdata : out std_logic ); end Ark; architecture Ark_it of Ark is constant CDATA_WIDTH : integer := 1; --Game pre-defined values constant CBALL_WIDTH : std_logic_vector(10 downto 0) := "00000001010"; --10; constant CBALL_HEIGHT : std_logic_vector(10 downto 0) := "00000001010"; --10; constant CBALL_RADIUS : std_logic_vector(10 downto 0) := "00000000101"; --5; constant CBALL_START_X : std_logic_vector(10 downto 0) := "00101010100"; --340; constant CBALL_START_Y : std_logic_vector(10 downto 0) := "00110111000"; --440; constant CBALL_2_LEFT : std_logic_vector(10 downto 0) := "01001011101"; --605; constant CBALL_2_TOP : std_logic_vector(10 downto 0) := "00111010100"; --468; constant CBALL_2_RIGHT : std_logic_vector(10 downto 0) := "01001100111"; --615; constant CBALL_2_BOTTOM : std_logic_vector(10 downto 0) := "00111011110"; --478; constant CBALL_1_LEFT : std_logic_vector(10 downto 0) := "01001101100"; --620; constant CBALL_1_TOP : std_logic_vector(10 downto 0) := "00111010100"; --468; constant CBALL_1_RIGHT : std_logic_vector(10 downto 0) := "01001110110"; --630; constant CBALL_1_BOTTOM : std_logic_vector(10 downto 0) := "00111011110"; --478; constant CBALL_V_2 : std_logic_vector(10 downto 0) := "00000000010"; --2; constant CBALL_V_M2 : std_logic_vector(10 downto 0) := "11111111110"; --neg2; constant CBALL_V_5 : std_logic_vector(10 downto 0) := "00000000101"; --5; constant CBALL_V_M5 : std_logic_vector(10 downto 0) := "11111111011"; --neg5; constant CBALL_V_7 : std_logic_vector(10 downto 0) := "00000000111"; --7; constant CBALL_V_M7 : std_logic_vector(10 downto 0) := "11111111001"; --neg7; constant CPADDLE_TOP : std_logic_vector(10 downto 0) := "00111000010"; --450; constant CPADDLE_BOTTOM : std_logic_vector(10 downto 0) := "00111010001"; --465; constant CPADDLE_WIDTH : std_logic_vector(10 downto 0) := "00000110010"; --50; constant CPADDLE_START_X : std_logic_vector(10 downto 0) := "00101000000"; --320; constant CPADDLE_PART_1 : std_logic_vector(10 downto 0) := "00000000101"; --5; constant CPADDLE_PART_2 : std_logic_vector(10 downto 0) := "00000001010"; --10; constant CPADDLE_PART_3 : std_logic_vector(10 downto 0) := "00000010100"; --20; constant CPADDLE_PART_4 : std_logic_vector(10 downto 0) := "00000011110"; --30; constant CPADDLE_PART_5 : std_logic_vector(10 downto 0) := "00000101000"; --40; constant CPADDLE_PART_6 : std_logic_vector(10 downto 0) := "00000101101"; --45; constant CPADDLE_PART_7 : std_logic_vector(10 downto 0) := "00000110010"; --50; constant CBOARDER_TOP : std_logic_vector(10 downto 0) := "10000000000"; --0 constant CBOARDER_LEFT : std_logic_vector(10 downto 0) := "10000000000"; --0; constant CBOARDER_BOTTOM : std_logic_vector(10 downto 0) := "00111100000"; --480; constant CBOARDER_RIGHT : std_logic_vector(10 downto 0) := "01010000000"; --640; constant CZERO : std_logic_vector(10 downto 0) := "00000000000"; --640; constant CBLOCK_WIDTH : std_logic_vector(10 downto 0) := "00000011111"; --31; constant CBLOCK_HEIGHT : std_logic_vector(10 downto 0) := "00000001111"; --15; signal gaming : std_logic := '1'; signal ball_attached : std_logic := '1'; --Tells the game if the ball is attached to the paddle signal collision : std_logic := '0'; signal x_index : std_logic_vector(4 downto 0); signal y_index : std_logic_vector(4 downto 0); signal pre_x_index : std_logic_vector(4 downto 0); signal pre_y_index : std_logic_vector(4 downto 0); signal pre_left_index : std_logic_vector(4 downto 0); signal pre_top_index : std_logic_vector(4 downto 0); signal write : std_logic; signal write1 : std_logic; signal write2 : std_logic; signal wtoggle : std_logic; signal bdata_in : std_logic_vector(0 downto 0); signal block_data1 : std_logic; signal block_data2 : std_logic; signal bdata_out : std_logic_vector(0 downto 0); signal count_x : std_logic_vector(4 downto 0); signal count_y : std_logic_vector(4 downto 0); signal blockx : std_logic_vector(4 downto 0); signal blocky : std_logic_vector(4 downto 0); signal baddress : std_logic_vector(9 downto 0); signal loaded : std_logic; signal bcollision : std_logic; signal hold_write : std_logic_vector(1 downto 0); signal clock_count : std_logic_vector(1 downto 0); signal lives : std_logic_vector(1 downto 0); signal level : std_logic_vector(1 downto 0); signal reset1 : std_logic; signal bgone : std_logic; begin --Creates a timing counter to synchronize writing to the --block memory process( clock ) begin if rising_edge( clock ) then --if reset = '0' then -- clock_count <= (others => '0'); --else clock_count <= clock_count + '1'; --end if; end if; end process; --Sets up the blocks in memory process( clock, gaming ) variable countx : std_logic_vector(4 downto 0); variable county : std_logic_vector(4 downto 0); -- variable block_count : std_logic_vector(9 downto 0); begin if rising_edge( clock ) then --if reset = '0' then -- countx := (others => '0'); -- county := (others => '0'); -- block_count := (others => '0'); -- loaded <= '0'; if gaming = '0' then if loaded = '0' then --Make sure you don't do things twice if clock_count = "00" then --clock_count is a timer to synchronize the steps --to ensure the data is written to the memory properly write1 <= '0'; if countx = "10011" then --if countx = 19 then countx := (others => '0'); if county = "11101" then --if county = 29 then county := (others => '0'); loaded <= '1'; else county := county + '1'; end if; else countx := countx + '1'; end if; elsif clock_count = "01" then --Note: nothing is chagned for "10", thus writ1 is held high --if level = "00" then --block_data1 <= '0'; if countx < "10100" then if county > "00011" and county < "01110" then block_data1 <= '1'; write1 <= '1'; else block_data1 <= '0'; write1 <= '1'; end if; end if; --else -- if countx <= county then -- if county < "10100" then -- block_data1 <= '1'; -- write1 <= '1'; -- else -- block_data1 <= '0'; -- write1 <= '1'; -- end if; -- end if; --end if; --if level = "00" then end if; --elsif clock_count = "11" then -- write1 <= '0'; -- end if; end if; --if loaded = '0' then else loaded <= '0'; countx := (others => '0'); county := (others => '0'); write1 <= '0'; end if; end if; --if rising edge count_x <= countx; count_y <= county; end process; --Depending on the vertical sync pulse (v_sync), give different processes the ability to --change the block memory address. -- --"count_x" and "count_y" are from the setup process. --"x_index" and "y_index" are from the game logic process. --"blockaddress(4->0)" and "blockaddress(9->5)" are from the draw process. -- process begin if v_sync = '1' then baddress(4 downto 0) <= count_x(4 downto 0) or blockaddress(4 downto 0); baddress(9 downto 5) <= count_y(4 downto 0) or blockaddress(9 downto 5); else baddress(4 downto 0) <= count_x(4 downto 0) or x_index(4 downto 0); baddress(9 downto 5) <= count_y(4 downto 0) or y_index(4 downto 0); end if; end process; --Give the setup proceedure (write1) exclusive access to write to the block --memory anytime it wants. The game logic (write2) may only write to the --block memory when the vertical sync pulse is occuring (i.e. v_sync = 0) process begin if v_sync = '1' then write <= write1; else write <= write1 or write2; end if; end process; --Two different processes need the ability to write to --the block memeory. "OR" them to produce one input. bdata_in(0) <= block_data1 or block_data2; --Output the value currently being shown by the memeory blockdata <= bdata_out(0); --Is there a collision? process( v_sync) begin if rising_edge( v_sync ) then if collision = '0' then if bdata_out(0) = '1' then bcollision <= '1'; else bcollision <= '0'; end if; else bcollision <= '0'; end if; end if; end process; process begin if lives = "00" then --if reset = '0' or lives = "00" then reset1 <= '0'; else reset1 <= '1'; end if; end process; process( v_sync ) --Player variable paddle_x : std_logic_vector(10 downto 0); --= PADDLE_START_X; variable pre_paddle_x : std_logic_vector(10 downto 0); --:= CPADDLE_START_X; --Ball variable hor_velocity : std_logic_vector(10 downto 0); variable ver_velocity : std_logic_vector(10 downto 0); variable ball_x : std_logic_vector(10 downto 0); variable ball_y : std_logic_vector(10 downto 0); variable pre_ball_x : std_logic_vector(10 downto 0); variable pre_ball_y : std_logic_vector(10 downto 0); --Stuff variable distance : std_logic_vector(10 downto 0); -- variable lives : std_logic_vector(1 downto 0); -- variable level : integer range 1 to 3 := 1; begin --Let the game begin --reset, if reset = 0 (active low) if reset1 = '0' then --Asynchronous reset --let's start at level 1, and we'll give the player 2 extra lives --level := 1; gaming <= '0'; x_index <= (others => '0'); y_index <= (others => '0'); lives <= "11"; elsif v_sync'EVENT and v_sync = '0' then if gaming = '0' and loaded = '1' then gaming <= '1'; --Initialize variables paddle_x := CPADDLE_START_X; pre_paddle_x := CPADDLE_START_X; ball_attached <= '1'; hor_velocity := CBALL_V_2; ver_velocity := CBALL_V_M7; ball_x := CBALL_START_X; ball_y := CBALL_START_Y; pre_ball_x := CBALL_START_X; pre_ball_y := CBALL_START_Y; collision <= '0'; pre_left_index <= (others => '0'); pre_top_index <= (others => '0'); pre_x_index <= (others => '0'); pre_y_index <= (others => '0'); -- lives <= "11"; collide <= '0'; bgone <= '0'; --Setup the blocks for level 2 -- if level = 2 then -- for j in 0 to 19 loop -- for i in 0 to (j+1) loop --Setup the blocks for level 3 -- if level > 2 then -- for i in 1 to 8 loop -- for j in 4 to 20 loop -- for i in 11 to 18 loop -- for j in 4 to 20 loop -- --Now that everything is set, let's enter the "game loop" -- elsif gaming = '1' then write2 <= '0'; block_data2 <= '0'; collide <= '0'; --Check to see if any of the four conrners of the ball are touching a block -- if bcollision = '1' then collision <= '1'; --We have contact, set the collision flag collide <= '1'; write2 <= '1'; --Record all relevent information pre_x_index <= pre_left_index; pre_y_index <= pre_top_index; end if; --if collsion, remove the block if collision = '1' then --Process the collision collision <= '0'; --Remove the collision flag --Check to see where the ball came from, in order to determine which way --it will bounce off the block if pre_x_index /= x_index then hor_velocity := '0' - hor_velocity; end if; if pre_y_index /= y_index then ver_velocity := '0' - ver_velocity; end if; end if; --Record where the ball has been (for use in the next collision) pre_left_index <= x_index; pre_top_index <= y_index; pre_paddle_x := paddle_x; --Record the current position of the paddle --Move the paddle based on the player's --input if move_left = '0' then paddle_x := paddle_x - "1000"; --subtract 8 end if; if move_right = '0' then paddle_x := paddle_x + "1000"; --add 8 end if; --Check to see if the paddle has moved beyond the left or right edge --of the screen if paddle_x > CBOARDER_LEFT then paddle_x := CZERO; --Move it back to the edge of the screen elsif paddle_x > (CBOARDER_RIGHT-CPADDLE_WIDTH) then paddle_x := (CBOARDER_RIGHT-CPADDLE_WIDTH); --Move it back to the edge --of the screen end if; --If the left mouse button is pressed, release the ball if move_left = '0' and move_right = '0' then --mouse_left_button = '1' then ball_attached <= '0'; end if; --Record where the ball is currently pre_ball_x := ball_x; pre_ball_y := ball_y; --If the ball is "on" the paddle, move it with the paddle if ball_attached = '1' then ball_x := ball_x + (paddle_x - pre_paddle_x); else ball_x := ball_x + hor_velocity; --Move the ball horizontaly ball_y := ball_y + ver_velocity; --Move the ball verticaly end if; --Did the ball go off the edge of the screen? (the x) if ball_x > CBOARDER_LEFT then ball_x := CZERO; --Move it back to the edge hor_velocity := '0' - hor_velocity; --and change its direction elsif ball_x > (CBOARDER_RIGHT-CBALL_WIDTH) then ball_x := CBOARDER_RIGHT-CBALL_WIDTH; --Move it back to the edge hor_velocity := '0' - hor_velocity; --and change its direction end if; --Did the ball hit the paddle or go off the top or bottom of the screen? (the y) if ((ball_y > (CPADDLE_TOP - CBALL_HEIGHT)) and (ball_y < (CPADDLE_TOP + CBALL_HEIGHT))) then collide <= '1'; distance := ball_x - paddle_x; --When the ball hits different parts of the paddle, it will result in --the ball leaving the paddle at different angles. if distance < 0 then elsif distance < CPADDLE_PART_1 then hor_velocity := CBALL_V_M7; ver_velocity := CBALL_V_M2; elsif distance < CPADDLE_PART_2 then hor_velocity := CBALL_V_M5; ver_velocity := CBALL_V_M5; elsif distance < CPADDLE_PART_3 then hor_velocity := CBALL_V_M2; ver_velocity := CBALL_V_M7; elsif distance < CPADDLE_PART_4 then ver_velocity := '0' - ver_velocity; elsif distance < CPADDLE_PART_5 then hor_velocity := CBALL_V_2; ver_velocity := CBALL_V_M7; elsif distance < CPADDLE_PART_6 then hor_velocity := CBALL_V_5; ver_velocity := CBALL_V_M5; elsif distance < CPADDLE_PART_7 then hor_velocity := CBALL_V_7; ver_velocity := CBALL_V_M2; end if; elsif ball_y > CBOARDER_TOP then --Top of the screen? ball_y := CZERO; --Move the ball back onto the screen ver_velocity := '0' - ver_velocity; --and change its direction elsif ball_y > (CBOARDER_BOTTOM-CBALL_HEIGHT) then --Bottom of the screen? --There goes that ball if lives > "00" then --Does the player have any balls (lives) left? lives <= lives - '1'; --The ball went off the bottom of the screen, so subtract --one of the players lives. paddle_x := CPADDLE_START_X; --Move the paddle back to the center of the --screen ball_x := CBALL_START_X; --Place the new ball in the center of the screen ball_y := CBALL_START_Y; --and on top of the paddle hor_velocity := CBALL_V_2; --Initialize the new ball's horizontal velocity ver_velocity := CBALL_V_M7; --Initialize the new ball's vertical velocity ball_attached <= '1'; --Attach the ball to the paddle else --If the player was out of lives -- gaming <= '0'; --The game ends, and is reset to the start -- x_index <= (others => '0'); -- y_index <= (others => '0'); level <= "00"; --and the level is returned to 1 end if; end if; OBall_x <= ball_x; OBall_y <= ball_y; Opaddle_x <= paddle_x; Olives <= lives; --Check to see if the level is finished (all the blocks were hit) if blocks_gone = '1' then level <= level + '1'; --Increament the level --gaming <= '0'; --Have the game load the new level lives <= "00"; --x_index <= (others => '0'); --y_index <= (others => '0'); end if; if bcollision = '0' then --Check to seek if a block was hit --(Note: >>5 is bit shifting by 5 in C and C++. Or a fast way of dividing by 32) -- --Rather than checking the ball against all the blocks, check to see if a block --is in the same space as the ball, using the block arrays. x_index(4 downto 0) <= ball_x(9 downto 5); y_index(4 downto 0) <= ball_y(8 downto 4); end if; end if;--End if reset, gaming end if; --End if v_sync'EVENT and v_sync = '0' end process; --Setup asynchornous memory (we prefer to do all the timing ourselves) mem : lpm_ram_dq generic map( lpm_width => CDATA_WIDTH, lpm_type => "L_RAM_DQ", lpm_widthad => 10, lpm_numwords => "unused", lpm_file => "unused", lpm_indata => "unregistered", lpm_outdata => "unregistered", --lpm_hint => "unused", lpm_address_control => "unregistered" ) port map( data => bdata_in, address => baddress, we => write, -- inclock => clock, -- outclock => clock, q => bdata_out ); end Ark_it; --The end