我使用 Altera 中的 DE2-115 FPGA 在VHDL中编写蛇形游戏。我已经使用VGA协议将FPGA与显示器连接起来以显示游戏。
我有一个问题是显示蛇并在显示器上移动所有推底(FPGA有4个,上/下/左/右)
在代码中,使用 SQ_X1 和 SQ_Y1 来每次推送底部处于低位状态时进行移动。
还有其他方法可以进行动作吗?没有按任何底部(带有循环或类似的东西)和改变方向,按下底部以模拟蛇的运动?
ARCHITECTURE behavior OF hw_image_generator IS
SIGNAL SQ_X1,SQ_Y1: INTEGER RANGE 0 TO 1688:=400; --initial position X
SIGNAL SQ_X2,SQ_Y2: INTEGER RANGE 0 TO 1688:=600; --initial position Y
SIGNAL DRAW: STD_LOGIC;
BEGIN
SQ(column,row,SQ_X1,SQ_Y1,DRAW); -- function that print a square (head of snake with SQ variables)
PROCESS(disp_ena, row, column, down, up, left, right)
BEGIN
IF(disp_ena = '1') THEN --display time
IF (column=19 or column=1901 or row=19 or row=1181) THEN -- print the border
red <= (OTHERS => '1');
green <= (OTHERS => '0');
blue <= (OTHERS => '0');
ELSE
red <= (OTHERS => '0');
green <= (OTHERS => '0');
blue <= (OTHERS => '0');
END IF;
IF (DRAW = '1') THEN -- it comes from a package that print a square (head of snake)
red <= (OTHERS => '1');
green <= (OTHERS => '1');
blue <= (OTHERS => '1');
END IF;
--up, down right and left are input of FPGA (push bottom)
--SQs are the current postions of X and Y and the add is to make the movement
IF(up='0' AND down='1' AND right='1' AND left='1' )THEN
IF (SQ_X1-40 > 20) THEN
SQ_X1<=SQ_X1-40;
END IF;
END IF;
IF(up='1' AND down='0' AND right='1' AND left='1')THEN
IF (SQ_X1+40 < 1180) THEN
SQ_X1<=SQ_X1+40;
END IF;
END IF;
IF(tup='1' AND down='1' AND right='0' AND left='1')THEN
IF (SQ_Y1+40 < 1900) THEN
SQ_Y1<=SQ_Y1+40;
END IF;
END IF;
IF(up='1' AND down='1' AND right='1' AND left='0')THEN
IF (SQ_Y1-40 > 20) THEN
SQ_Y1<=SQ_Y1-40;
END IF;
END IF;
END IF;
END PROCESS;
END BEHAVIOR;
答案 0 :(得分:1)
首先,我建议您将显示和位置更新功能拆分为单独的流程,以使事情更加清晰。
你似乎已经拥有了显示过程所需的一切,除了像Paebbels在评论中提到的那样,这应该是一个同步(即时钟)过程。我假设你的时钟名为clk
。
PROCESS(clk)
BEGIN
IF rising_edge(clk) THEN
--display time
IF(disp_ena = '1') THEN
-- print the border
IF (column=19 or column=1901 or row=19 or row=1181) THEN
red <= (OTHERS => '1');
green <= (OTHERS => '0');
blue <= (OTHERS => '0');
ELSE
red <= (OTHERS => '0');
green <= (OTHERS => '0');
blue <= (OTHERS => '0');
END IF;
IF (DRAW = '1') THEN
red <= (OTHERS => '1');
green <= (OTHERS => '1');
blue <= (OTHERS => '1');
END IF;
END IF;
END IF;
END PROCESS;
对于职位更新,您需要两件事:
第一点很容易实现。首先,声明方向状态信号。
type direction_t is (DIR_UP, DIR_DOWN, DIR_LEFT, DIR_RIGHT);
signal direction : direction_t;
然后,创建方向状态过程。
process(clk) begin
if rising_edge(clk) then
if rst = '1' then
direction <= DIR_UP;
else
if up = '0' then
direction <= DIR_UP;
elsif down = '0' then
direction <= DIR_DOWN;
elsif left = '0' then
direction <= DIR_LEFT;
elsif right = '0' then
direction <= DIR_RIGHT;
end if;
end if;
end if;
end process;
我在此假设你有一个名为rst
的复位信号,并且该复位是同步高电平有效。适应您的口味。
此外,请注意,虽然这个特定示例并非严格必要,但作为一般最佳做法:
up
,down
,left
和right
如果来自其他时钟域,则应正确重新同步,或完全异步(如按钮)。 up
,down
,left
和right
如果直接来自按钮,或其他&#34;弹性&#34;机械设备。最后,您需要创建一个定时脉冲的时钟使能信号,并作为位置更新的时基。创建这种信号的一种简单方法通常是使用计数器来分频时钟,但如果时钟太快,如果它是视频时钟可能就是你的情况,你最终会得到一个太大的计数器,这是负面的影响时间。对此有各种解决方案,但在您的情况下,您可以使用row
和column
信号在每次到达视频帧结束时生成脉冲,如下所示:
signal update_ce : std_logic;
-- (...)
process(clk) begin
if rising_edge(clk) then
-- adapt the value to your taste
if disp_ena = '1' and column = 1901 and row = 1181 then
update_ce <= '1';
else
update_ce <= '0';
end if;
end if;
end process;
如果更新速度过快,您可能需要再次使用计数器对此信号的频率进行分频,但至少您的计数器不必数以百万计。鉴于此信号,您现在可以更新您的位置:
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
-- adapt starting position to your taste
SQ_X1<= 100;
SQ_Y1<= 100;
elsif update_ce = '1' then
case direction is
when DIR_UP =>
if SQ_X1 - 1 > 20 then
SQ_X1 <= SQ_X1 - 1;
end if;
when DIR_DOWN =>
if SQ_X1 + 1 < 1180 then
SQ_X1 <= SQ_X1 + 1;
end if;
when DIR_LEFT =>
if SQ_Y1 - 1 > 20 then
SQ_Y1 <= SQ_Y1 - 1;
end if;
when others =>
-- DIR_RIGHT
if SQ_Y1 - 1 > 20 then
SQ_Y1 <= SQ_Y1 - 1;
end if;
end case;
end if;
end if;
end process;