61010104I SEE YOU敏捷性游戏

发布者:系统管理员发布时间:2013-10-10浏览次数:0

I SEE YOU敏捷性游戏
              学号:61010104
          姓名:肖薇
1、申请题目:(I SEE YOU
n      题目,命题描述(5号宋体)
这是一个基于FPGA和点阵板实现的敏捷性小游戏,玩家通过键盘上下左右键移动,躲避对方追捕。
 
2、课题背景:
n      存在问题、应用背景
此游戏旨在锻炼人的敏捷性,游戏虽小,但游戏过程激烈,可玩性强。本款游戏在市场上虽有雷同,但确实出自我的设计,并加入了独有的创新之处,如边界跳跃和墙体定时消失,增加了游戏难度和趣味性。
3、项目规划:
n      功能、指标、规模
1、功能
1)在16*16的LED板上无规则的布置各种形状的墙体,墙体用红色灯表示。一个黄灯表示玩家1,一个绿灯表示玩家2。
2)由两个玩家用键盘分别控制控制玩家1、2上下左右移动。
3)玩家在规定时间内追捕到对方则游戏结束。
2、指标
游戏分为两个模式:模式一中墙体不会消失,模式二中墙体定时批量消失一增大游戏难度。本游戏共设置两张地图:地图一无边界,玩家可从任意边界跳跃到对应边界,对思维敏捷性要求较高,地图二有边界,玩家只能在该区域运动。
3、规模
用矩阵控制点阵板显示,难度适中,代码千行,逻辑门五千余个。
n      面板(显示)、操作、规则
1、面板
2、操作
    操作完全在键盘上进行,游戏未开始时,1、2键进行模式选择,A、D键进行地图选择,F键开始选择,C键返回上一级,E键确认。游戏开始后,0、1、2、5为玩家一的方向键,8、9、A、D为玩家二的方向键。
3、规则
游戏进行过程中,玩家2负责追捕玩家1,50秒之内追捕到则玩家2胜利,50秒内没有追捕到则玩家1胜利。
n      ,输入、输出接口
键盘输入接口;点阵板扫描输出接口;指示灯输出接口;数码管输出接口。
4、实现方案:
n      核心问题
1 键盘同时控制点阵板两个人物移动。
2 状态机的设置。
3 墙体随时间消失的实现。
4 游戏结束的判定。
n      系统解决方案
1.利用不同按键的输出信号确定不同的移动方向。两个人的移动用同一个时钟脉冲控制。
2.状态机主要实现以下功能:游戏准备状态中,按下F键,游戏选择开始。按下1和2键分别选择模式1和模式2。在模式一二的状态下,按A、D键选择地图,A键向上加地图张数,D键向下减地图张数,此游戏中总地图可以设置多张,但是由于时间关系只设置了两张。选择好地图张数后,按下E键,游戏开始。在此过程中,任何时候按下C键则返回上一游戏状态。游戏过程中任何时候按下F键,游戏退出。
3.在计时模块中每个固定的时间点引出一个脉冲信号,在地图模块中预存一些点,即一些墙体,在这些信号到来时分批等量减少,实现墙体定期消失。
4.在一定的时钟下不断扫描,判断黄灯和绿灯是否在同一个位置,若是,则输出游戏结束信号1。计时器自游戏开始计时至50秒后,游戏结束,发出结束信号2。
 
5、系统结构:
n      系统框图
n      模块功能描述
1、state
这是控制本游戏流畅进行的状态机。游戏共分六个状态,故用六位二进制数表示。
000是游戏初始状态,按下F键后游戏进入001游戏选择状态。这时准备进行游戏模式的选择。按1键选择模式一,状态机转入010状态。按2键选择状态二,状态机转图011状态。在模式一二状态下,按A、D键选择地图,A是地图数加法键,D是地图数减法键。选择地图完成后,按E键,010状态转为模式一游戏进行状态100,011状态转为模式二游戏进行状态101。在选择过程中任意时刻按C键,可转回上一状态。在100和101状态下按F键转入000状态。状态机流程图见下:
2、map-map
这是本游戏最重要的一个模块。本模块主要分为五个部分。
第一部分是游戏地图和结束画面的预置。用矩阵的方法预存好两张地图,地图分别为无边界可跨边界跳跃型和有边界不可跨边界跳跃型。在此部分,还要预置玩家一二的初始位置,两者对应在对角线的边上的点。预置两张结束画面,第一张是在五十秒内万家一追捕到玩家二后游戏结束,显示I CATCH YOU,第二张是五十秒时间到,玩家没有被追捕到,而跳出的游戏结束画面,显示一张得意地笑脸。
 
图 地图
  
图 结束画面
第二部分是键盘控制人物移动,因为是双人游戏故用了两组方向键,上一组方向键是反向设置的,是为了方便两个人游戏,两个人可以面对面游戏,手上的方向控制不会相互干扰,体现了人性化设置的一面。具体方向对应是第一组:1-左、2-上、3-右、5-下;第二组::8-左、9-上、A-右、D-下。具体图见下:
而在点阵板上的具体操控设置原理是按下方向键后,判断该行进方向是否有障碍物,如果没有则该方向的点亮起,而原来的点灭掉,如果有,则无动作,这样就实现了键盘控制点阵板上的点移动。双人移动的时候因为处于一个进程,故共用一个按键上升沿。
第三部分是墙体消失部分。这一部分墙体依时间点消失。在10s、15s、20s、25s、30s、35s、40s、45s时每次消失四个点,即四堵墙。时间信号由时间模块给出。比如在15s时会消失掉四个点,即这四个点在15s之后再也不会出现,所以时间模块给出的是在15s之后持续有效的信号。而在这个信号到来之后,预定的四堵墙会消失,即将该坐标点的信号置零,并且再也不会出现。
 
图 墙消失前                              图 墙消失后
第四部分是游戏结束的判断。第一类结束判定方式是,在时钟上升沿的激励下,不断扫描点阵板,如果玩家一二的坐标相等,则游戏结束,发出游戏结束的信号一;第二类结束判定方式是,如果时间模块给出50s时间到的信号,则游戏结束,发出游戏结束信号二。
第五部分是为之后的点阵模块做铺垫的。第五部分分为两个步骤。步骤一,将将同一时期的矩阵合并。因为本游戏中是按点阵板上灯的颜色设置矩阵的,红、黄、绿三个点分别用三个矩阵表示。而同一时刻三种颜色的点会同时存在于点阵板上,故要用另外一个矩阵将这三个矩阵合并。步骤二,由于扫描矩阵显示模块需要串行输入信号,故这里用一个循环语句将输出矩阵信号转换为串行输出信号。
3、display
    本模块是点阵板的扫描显示模块。由它产生列扫描信号,并将从map-map模块输出的矩阵串行输出信号在列扫描下显示在点阵板上。其输入扫描频率为1000Hz。并由开始信号出发扫描开始。
4、time-setting
时间模块主要分为两个部分。
第一部分是计时模块。本来设置的是三位计时,但遗憾的是最终百位没有用到,具体原因之后详述。本计时模块采用正计时,频率为1Hz,在追捕成功或50s时间到的情况下停止计时并保持在该时间状态,直至清零信号到来并清零。
第二部分是墙体消失信号的给出。在每一个墙体消失的时间点,将给出一个disappear的信号,此信号在大于该时间点的条件下始终为1。共给出8个这样的消失信号。
5、led
本模块是在游戏全过程中用指示灯指示游戏进行的状态。游戏初始状态用一个指示灯指示,这个指示灯提示此时应该按下F键使得游戏进入选择状态。在游戏选择状态下,有两个指示灯提示玩家所选模式。玩家按下1、2键分别对应一二模式的指示灯亮起。玩家在按下确认键E游戏开始后,会有一个指示灯提示游戏进行中。
6、hard-setting
本模块支持玩家选择不同难度的地图。玩家按A键,则游戏地图数增加,按D键,地图数减小。本游戏可设置许多地图,鉴于实际考虑,只设置了两张难度不同的地图。游戏所用地图张数在数码管上显示。
7、keyboard
键盘按键信号及输出对应四位二进制数。
8、decode4-8
数码管八段译码器。
9、分频器
将FPGA开发板上自带的2MHz时钟分频为1Hz、2Hz、100Hz、1000Hz。
 
n      模块接口标注(参数、协议)
1、时钟输入
2、键盘
3、点阵板输出
4、指示灯输出
5、计时数码管输出
6、地图选择数码管输出
 
6、状态流程图:
n      系统工作状态流程
7、各主要模块仿真结果波形
n      各模块的仿真波形,详细注释输入输出功能端口
1.键盘模块波形图:
输入输出功能端口:
CLK:输入2MHz时钟信号
KEY_down_:输出按下键的脉冲
col[3..0]:列扫描信号
row[3..0]:行输入信号
q[3..0]:4位键盘码信号
从波形可以看出,可以成功产生列扫描信号,而且按下F键,和4键后可以输出相应的键值,且能产生按键脉冲。
 
2. 状态机模块波形图:
输入输出功能端口:
CLK:时钟信号
1、2、A、B、C、D、E、F:键盘按键信号
X1:暂停信号
STATE:输出状态信号
波形000是游戏初始状态,按下F键后游戏进入001游戏选择状态。这时准备进行游戏模式的选择。按1键选择模式一,状态机转入010状态。按2键选择模式二,状态机转图011状态。按E键,010状态转为模式一游戏进行状态100,011状态转为模式二游戏进行状态101。在选择过程中任意时刻按C键,可转回上一状态。在100和101状态下按F键转入000状态。可见状态机功能可以实现。
 
3.50s计时显示模块波形图:
输入输出功能端口:
A[3..0]: 4位键盘按键码
State:当前状态
CLK1Hz:1Hz时钟信号
SecH:秒高位
SecM:秒中位
SceL:秒低位
波形意义:
可以看出在计时模式状态中可以实现计时的功能。
 
4.本系统仿真涉及两个16*16自定义矩阵向量,超出Quatus 提供的pin脚上限,故游戏控制模块仿真无法实现,实际中采用直接烧进FPGA中调试,此处模块仿真略。
 
 
8、课程设计总结
n      预期的目标与当前实现功能的差异详细注释
1、    预期本不是双人游戏,而是一个玩家一个敌人。敌人由FPGA自行控制,在每个时钟上升沿扫描玩家所在位置,并根据玩家位置确定自己的前进方向。这一段代码并不是很难编译,而且我已经编写出来了,但由于敌人对前进方向的每一次判断都要扫描整个点阵板,再者我选择的点阵扫面显示办法可能也不是最节约逻辑门的一种,故将此段程序编译后程序报错,显示错误为逻辑门过多,达到九千多个。
       附此段程序(打包的程序中没有,故在此附上):
if (x
     if (y
            if (redmatrix(des_y-1)(des_x)='0')then--上移一位
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y-1)(des_x):='1';       
                        des_y:=des_y-1; 
                 elsif (redmatrix(des_y)(des_x-1)='0')then--向左
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y)(des_x-1):='1';       
                        des_x:=des_x-1;
                 elsif (redmatrix(des_y+1)(des_x)='0')then--向下
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y+1)(des_x):='1';       
                        des_y:=des_y+1;
                 elsif (redmatrix(des_y)(des_x+1)='0')then--向右
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y)(des_x+1):='1';       
                        des_x:=des_x+1;
                 end if;         
    elsif y>des_y then
            if (redmatrix(des_y+1)(des_x)='0')then--向下
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y+1)(des_x):='1';       
                        des_y:=des_y+1;
            elsif (redmatrix(des_y)(des_x-1)='0')then--向左
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y)(des_x-1):='1';       
                        des_x:=des_x-1;
                 elsif (redmatrix(des_y)(des_x+1)='0')then--向右
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y)(des_x+1):='1';       
                        des_x:=des_x+1;
                 elsif (redmatrix(des_y-1)(des_x)='0')then--上移一位
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y-1)(des_x):='1';       
                        des_y:=des_y-1;
                 end if;
   end if;
elsif x
       if (y
            if (redmatrix(des_y-1)(des_x)='0')then--上移一位
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y-1)(des_x):='1';       
                        des_y:=des_y-1;
                 elsif (redmatrix(des_y)(des_x+1)='0')then--向右
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y)(des_x+1):='1';       
                        des_x:=des_x+1; 
                 elsif (redmatrix(des_y)(des_x-1)='0')then--向左
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y)(des_x-1):='1';       
                        des_x:=des_x-1;
                 elsif (redmatrix(des_y+1)(des_x)='0')then--向下
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y+1)(des_x):='1';       
                        des_y:=des_y+1;
 
                 end if;         
    elsif y>des_y then
            if (redmatrix(des_y+1)(des_x)='0')then--向下
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y+1)(des_x):='1';       
                        des_y:=des_y+1;
                 elsif (redmatrix(des_y)(des_x+1)='0')then--向右
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y)(des_x+1):='1';       
                        des_x:=des_x+1;
            elsif (redmatrix(des_y)(des_x-1)='0')then--向左
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y)(des_x-1):='1';       
                        des_x:=des_x-1;
 
                 elsif (redmatrix(des_y-1)(des_x)='0')then--上移一位
                greenmatrix(des_y)(des_x):='0';
                        greenmatrix(des_y-1)(des_x):='1';       
                        des_y:=des_y-1;
                 end if;
    end if;
end if;
   end if;      
end if;
    后来又想出了一个让敌人伪随机运动的方法,就是预置好八个(如果逻辑门允许,将扩充到十六个)方向,敌人每接收到一个时钟上升沿即动作一次,若前方有墙阻挡,则弃置此动作机会,等待下一个时钟上升沿而执行下一个动作方向。这段程序我也编写好了,但编译后仍旧是同一个问题,预置了八个方向逻辑门就超出了FPGA所能承受的限度,只好将此方法也放弃。
附此段程序如下:
 if temp=7 then   temp:=0;
 else temp:=temp+1;
 end if;
 case temp is
    when 0=> if (redmatrix(des_y-1)(des_x)='0')then--上移一位
                greenmatrix(des_y)(des_x):='0';
                            greenmatrix(des_y-1)(des_x):='1';       
                            des_y:=des_y-1;
                            end if; 
    when 1=>if (redmatrix(des_y)(des_x-1)='0')then--向左
                greenmatrix(des_y)(des_x):='0';
                            greenmatrix(des_y)(des_x-1):='1';       
                            des_x:=des_x-1;
                            end if;
    when 2=>if (redmatrix(des_y)(des_x-1)='0')then--向左
                greenmatrix(des_y)(des_x):='0';
                            greenmatrix(des_y)(des_x-1):='1';       
                            des_x:=des_x-1;
                            end if;
    when 3=>if (redmatrix(des_y+1)(des_x)='0')then--向下
                greenmatrix(des_y)(des_x):='0';
                            greenmatrix(des_y+1)(des_x):='1';       
                            des_y:=des_y+1;
                            end if;
    when 4=>if (redmatrix(des_y-1)(des_x)='0')then--上移一位
                greenmatrix(des_y)(des_x):='0';
                            greenmatrix(des_y-1)(des_x):='1';       
                            des_y:=des_y-1;
                            end if; 
    when 5=>if (redmatrix(des_y)(des_x+1)='0')then--向右
                greenmatrix(des_y)(des_x):='0';
                            greenmatrix(des_y)(des_x+1):='1';       
                            des_x:=des_x+1;
                      end if;  
    when 6=>if (redmatrix(des_y+1)(des_x)='0')then--向下
                greenmatrix(des_y)(des_x):='0';
                            greenmatrix(des_y+1)(des_x):='1';       
                            des_y:=des_y+1;
                     end if;
    when 7=>if (redmatrix(des_y)(des_x+1)='0')then--向右
                greenmatrix(des_y)(des_x):='0';
                            greenmatrix(des_y)(des_x+1):='1';       
                            des_x:=des_x+1;
                      end if;
    end case; 
     将此游戏改成双人游戏后,控制敌人运动的频率模块失去了效用,该频率模块是在不同的时间点选择不同的频率输出,该模块编译成功,并且存在于打包的模块中,只可惜没有用到,只是空置。
2、本来游戏结束的判断是敌人发现对方,即敌人与玩家的水平或垂直连线上没有墙的阻隔游戏就结束。但后来改成双人游戏后发现如果这样设置就太容易被抓住,失去了游戏的可玩性,所以将规则改成了一方抓住另一方。
3、本来游戏中有墙体变幻一环,墙体变幻即某几堵墙从某处消失并在另一地方出现,在墙体在出现时必须让点阵扫描判断墙体出现的地方是否有玩家或敌人的存在,由于变换的墙多了,导致逻辑门数量不足,变换的墙少了导致看不出什么效果,所以将所有墙体变幻改为了墙体消失,以达到增大游戏难度的效果。
4、另外原设计中有技能点的使用,那是针对敌人运动速率的,现在改为了双人游戏,自然技能点的使用也就失去了意义。
n      可以进一步发挥提高的部分
1、可以把此游戏设置成通关模式,游戏一开始可以选择是逃犯(被追捕人)模式,或者是警察(追捕人)模式。逃犯模式在游戏的前几关比较容易逃脱,后几关则难度逐渐增加,逃犯通过了一关才能进入第二关。警察模式与逃犯模式难易度反之。这样增大了游戏规模,也增加了游戏的可玩性。
2、本游戏中,由于两个玩家按键控制点阵板移动时共用了一个时钟上升沿,而键盘并不是多点控制,所以同一时刻键盘只能识别一个动作,所以游戏过程中有时会出现同时按键但有一个人无法动作的现象。因为一个process里面只允许存在一个时钟上升沿,故可以考虑用两个进程分别控制两个人的运动,从而消除这一点游戏的小问题。
n      课程设计体会
本次课程设计收获很多,主要有以下几点:
1、自学了VHDL语言。虽然这门语言其实并不是很难,或者也许它很博大精深我们也只涉及了其中的一小部分。但是至少我体会了一种自学的过程,最初抱一本不感兴趣的书从头看起,毕竟是一门语言,还是有他的抽象之处的,所以凡是开始总是有些难很忧伤的。后来书上的东西并没有多少真正记住了,就开始上手quartus,先看看别人的程序,慢慢的熟悉了这门语言,在逐渐地自己编一些小东西小模块,看到编译成功,虽然都算不上成就,但也是很开心的一件事情。再后来运用一种语言成为了自己一种并不熟练地习惯,虽然还时常翻书,但总是比最初的生涩好了不知多少倍,直到现在跌跌撞撞的做出来点小玩意,这个过程和这门语言不会忘记了。
2、不享受这个过程,但是享受回忆这个过程。这个过程当然是无比纠结的,语言不熟悉,一本书不知道翻了多少遍,这里面的语法有很多类似却不同还十分严苛的地方,看了一遍书,下次有弄混了再看一遍,不断重复。好不容易基本语法过了,可是编译还有一堆形形色色的问题,求各路大神,终于也解决的差不多了,后来搭上线,上了点,烧进去,乱七八糟什么也没出来,后来问同学问出来点阵的另一种方法,想到自己编了半天功亏一篑,就觉得眼前除了黑还是黑,再之后,重编。这是一个心酸的过程却也是一个历练的过程,想做出来什么总是要吃苦的,现在想想,没什么不好。
3、调试的时候查错是一个极需耐心的活,一遍两遍三遍,各种问题就是出不来,每次从实验室出来都会想进展虽有但前路依旧茫茫,睡觉前都各种不爽。但是最终成功后突然觉得一切还是值得的,其实那种烦躁的心情每次都只存在与过程中,所以今后遇到时,我也更加会坚定地坚持下去的。
9、参考文献
1. VHDL数字电路设计教程, Volnei A. Pedroni, 乔庐峰/王志功 电子工业出版社
 
注:程序清单不要放在报告中,将最后能下载的正确的程序打包上传(程序中请写明注释)。