首页 > 其他分享 >八、贪吃蛇之状态机设计

八、贪吃蛇之状态机设计

时间:2024-05-08 11:44:06浏览次数:28  
标签:begin end direct cnt else 状态机 game 贪吃蛇 设计

八、贪吃蛇之状态机设计

贪吃游戏采用mealy状态机。

1. 游戏状态控制状态机

用一段式编码来完成游戏控制过程:

 

 

各状态说明:

(1) RESTART:复位后进入重启状态,屏幕显示欢迎界面,6秒后进入游戏难度选择界面,等待选择难度。

(2) START:用SW[2:0]选择游戏难度,按下KEY[3:0]任意键,开始游戏。进入PLAY状态。

(3) PLAY:按上下左右方向键,控制蛇身移动,蛇身最长16格,吃食物获得分数显示在数码管上。

(4) DIE:当蛇撞墙、撞自身或分数达到100时,蛇身闪烁3秒,屏幕显示总分,游戏结束。

//游戏控制模块,根据游戏状态,产生相应控制信号

module game_ctrl_unit

(

    input clk, //25MHz

    input rst_n,

 

    input key0_right, //选方向

    input key1_left,

    input key2_down,

    input key3_up,

    input [2:0] sw, //选难度

 

    input hit_wall, //撞墙

    input hit_body, //撞自身

    input [11:0]bcd_data, //分数

 

    output reg snake_display, //蛇整体显示标识

    output reg [1:0]game_status //当前游戏状态

);

 

localparam RESTART = 2'b00; //游戏重启

localparam START = 2'b01; //游戏开始

localparam PLAY = 2'b10; //游戏进行

localparam DIE = 2'b11; //游戏结束

 

reg [32:0]cnt_clk ;

reg [31:0]flash_cnt ; //蛇闪烁时间计数器

 

//状态机定义初始状态,并描述状态转移与输出

always @(posedge clk or negedge rst_n) begin

    if (!rst_n) begin

        cnt_clk<=0;

        flash_cnt<=0;

        snake_display<=1;

        game_status<=RESTART; //复位后进入重启状态

    end

 

    else begin

        case (game_status)

            RESTART:begin

                cnt_clk<=cnt_clk+1;

                if(cnt_clk>150000000)begin

                    //欢迎界面

                    if(sw[0]||sw[1]||sw[2]) begin

                        game_status <= START;

                        //选择游戏难度

                    end

                end

                else begin

                    game_status <= RESTART;

                end

            end

 

            START:begin

                if((~key0_right) || (~key1_left)

                   || (~key2_down) || (~key3_up))

                   game_status <= PLAY; //按键开始

                else

                    game_status <= START;

            end

 

            PLAY:begin

                if(hit_wall || hit_body || bcd_data[11:8]>=1'd1)

                    game_status <= DIE;

                else    

                    game_status <= PLAY;

            end

 

            //蛇身闪烁,间隔0.5秒

            DIE:begin

                if(flash_cnt <= 100_000_000) begin //

                    flash_cnt <= flash_cnt+1'b1;

                    if(flash_cnt == 12_500_000) begin

                        snake_display <= 1'b0;

                    end

                    else if(flash_cnt == 25_000_000) begin

                        snake_display <= 1'b1;

                    end

                    else if(flash_cnt == 37_500_000) begin

                        snake_display <= 1'b0;

                    end

                    else if(flash_cnt == 50_000_000) begin

                        snake_display <= 1'b1;

                    end

                    else if(flash_cnt == 62_500_000) begin

                        snake_display <= 1'b0;

                    end

                    else if(flash_cnt == 75_000_000) begin

                        snake_display <= 1'b1;

                    end

                end

                //游戏结束,按任意键,重新开始

                else if((~key0_right) || (~key1_left)

                   || (~key2_down) || (~key3_up))begin

                    cnt_clk<=0;

                    flash_cnt<=0;

                    game_status <= RESTART;

                   end

 

                else begin

                    game_status <= DIE;

                end

            end

 

            default: begin

                game_status <= RESTART;

            end 

        endcase

    end

end

endmodule

 

其中,在RESTART状态,cnt_clk >150000000,这里用大于而不是判断相等,原因是如果等了6秒,没有及时选择难度,就错过了,所有用大于。在DIE状态,cnt_clk和flash_cnt都要清零,是为了游戏重启后,和初始状态一样。

2. 蛇身方向控制状态机

蛇身方向状态用三段式代码编写,分上下左右四个状态。

 

 

 

(1) 第一段:状态转换时序逻辑,初始化状态。

//蛇身方向初始化状态

always @(posedge clk or negedge rst_n) begin

    if (!rst_n) begin

        speed<=24'd12500000;

        direct_r<=RIGHT;

    end

   

这里初始化的方向是右,实际是根据key值判断。

 

(2) 第二段:状态转换的组合逻辑。

always @(*) begin

    case(direct_r)

        UP: begin

            if(~key1_left)

                direct_next = LEFT;

            else if(~key0_right)

                direct_next = RIGHT;

            else    

                direct_next = UP;

        end

        DOWN: begin

            if(~key1_left)

                direct_next = LEFT;

            else if(~key0_right)

                direct_next = RIGHT;

            else    

                direct_next = DOWN;

        end

        LEFT: begin

            if(~key3_up)

                direct_next = UP;

            else if(~key2_down)

                direct_next = DOWN;

            else    

                direct_next = LEFT;

        end

        RIGHT: begin

            if(~key3_up)

                direct_next = UP;

            else if(~key2_down)

                direct_next = DOWN;

            else    

                direct_next = RIGHT;

        end

    endcase

end

 

 

(3) 第三段:根据当前状态和输入产生输出的时序逻辑。

if(direct_r==UP)begin

    if(cube_y[0] == 1)

        hit_wall <= 1; //撞上墙

    else    

        cube_y[0] <= cube_y[0]-1;

end

 

else if(direct_r==DOWN)begin

    if(cube_y[0] == 28)

        hit_wall <= 1; //撞下墙

    else

        cube_y[0] <= cube_y[0]+1;

end

 

if(direct_r==LEFT)begin

    if(cube_x[0] == 1)

        hit_wall <= 1; //撞左墙

    else    

        cube_x[0] <= cube_x[0]-1;

end

 

else if(direct_r==RIGHT)begin

    if(cube_x[0] == 38)

        hit_wall <= 1; //撞右墙

    else

        cube_x[0] <= cube_x[0]+1;

end

 

参考文献

https://mp.weixin.qq.com/s/YSrbtbRneUtc1d8IYhk-RA

标签:begin,end,direct,cnt,else,状态机,game,贪吃蛇,设计
From: https://www.cnblogs.com/halflife/p/18179367

相关文章

  • 九、贪吃蛇之蛇身控制
    九、贪吃蛇之蛇身控制1. 目标(1) 游戏难度决定蛇身移动的速度;(2) 蛇身增长;(3) 蛇身移动。 2. 蛇身速度控制用计数器来控制蛇身移动的时间间隔,间隔短,移动快,游戏难度就越难。在游戏难度选择界面,用SW[2:0]选择难度。//蛇身移动速度else begin  clk_cnt<= clk......
  • python-设计并实现计算不同职称的教师工资
    【题目描述】设计教师接口,该接口包含教师工资计算方法。应用(一)中的高校人员信息包,设计不同职称的教师类:教授,副教授,讲师,教师的基本信息包括姓名、性别、出生年月、职称、课时工作量等属性。注意学校对教师每月工资的计算规定如下:固定工资+课时补贴;教授的固定工资为5000元,每个课时补......
  • python-设计异常处理类Cexception,并基于异常处理类设计并实现日期类Date
    【题目描述】定义一个异常类Cexception解决日期类实现中的自定义异常处理。设计的日期类应包含以下内容:① 有三个成员数据:年、月、日;② 有设置日期的成员函数;③ 有用格式"月/日/年"输出日期的成员函数;④ 要求在日期设置及有参构造函数中添加异常处理。【源代码程序......
  • python-设计并实现平面点类Point
    【题目描述】定义一个平面点类Point,对其重载运算符关系运算符,关系运算以距离坐标原点的远近作为基准,远的为大。程序完成对其的测试。【源代码程序】importmathclassPoint():    def__init__(self,x,y):        self.x=x        self.y=y   ......
  • 02-大厂电商设计解析之商品管理系统
    1雪花算法使用IdWorkeridWorker=newIdWorker(1,1);for(inti=0;i<10000;i++){longid=idWorker.nextId();System.out.println(id);}配置分布式ID生成器将IdWorker.java拷贝到util包在工程的resources下新增applicationContext-service.xml<!‐‐雪花ID生......
  • 软件设计师:结构化开发方法
    模块化模块独立软件模块应尽量做到高内聚、低耦合,提高模块的独立性耦合性无直接耦合:没有直接关系数据耦合:传递简单的数据值标记耦合:传递数据结构控制耦合:传递控制变量外部耦合:软件之外的环境联结公共耦合:公共数据环境内容耦合:通过非正常入口/直接访问内部数据内聚......
  • 前端使用 Konva 实现可视化设计器(9)- 另存为SVG
    请大家动动小手,给我一个免费的Star吧~大家如果发现了Bug,欢迎来提Issue哟~github源码gitee源码示例地址另存为SVG这一章增强了另存为的能力,实现“另存为SVG”,大概是全网唯一的实例分享了吧。灵感来源:react-konva-custom-context-canvas-for-use-with-canvas2svg大......
  • BOSHIDA AC/DC电源模块的设计与实现技巧
    BOSHIDAAC/DC电源模块的设计与实现技巧AC/DC电源模块是一种常用的电源模块,用于将交流电转换为直流电,为各种电子设备提供电力。在设计和实现AC/DC电源模块时,有一些重要的技巧需要注意。 首先,选择适当的拓扑结构对于AC/DC电源模块的性能至关重要。常见的拓扑结构包括线性电源......
  • 便携式手提测试仪设计资料:474-便携式手提万兆网络协议测试仪
    便携式手提万兆网络协议测试仪一、平台简介   便携式手提万兆网络协议测试仪,以FPGA万兆卡和X86主板为基础,构建便携式的手提设备。   FPGA万兆卡是以Kintex-7XC7K325TPCIeX4的双路万兆光纤网络卡,支持万兆网络数据的收发和网络协议的定制设计。  ......
  • 二叉搜索树的接口设计
    #include<stdio.h>#include<stdbool.h>#include<stdlib.h>typedefintElementType;typedefstructTNode*Position;typedefPositionBinTree;/*二叉树类型*/structTNode{/*树结点定义*/ElementTypeData;/*结点数据*/......