贪吃蛇项目

贪吃蛇

需求说明书

文件编号:2022[1] 06[2] 01[3] 

完成日期:2024年 07月15日

编制:一只普通柚子

日期:7月15日

审核:一只普通柚子

日期:7月15日

批准:一只普通柚子

日期:7月15日

目录

1.   任务概述....................................................... 3

1.1.      目标........................................................ 3

1.2.    系统(或用户)的特点................... 3

2.   假定和约束................................................... 3

3.   需求规定....................................................... 3

3.1.      软件功能说明..................................... 3

3.2.      对功能的一般性规定........................ 3

3.3.      对性能的一般性规定........................ 4

3.4.      其他专门要求..................................... 4

3.5.      对安全性的要求................................. 4

4.   运行环境规定............................................... 4

4.1.      设备及分布.......................................... 4

4.2.      支撑软件............................................... 4

4.3.      接口........................................................ 4

4.4.      程序运行方式..................................... 5

5.   尚需解决的问题........................................... 5

  1. 任务概述
    1. 目标

开发意图:提供一个简单有趣,易上手的贪吃蛇游戏,以满足用户在休闲娱乐时的需求。

应用目标:进行贪吃蛇游戏;含各种难度级别的游戏模式;适用于不同年龄阶段的用户;确保游戏在不同系统都可以正常运行;保证游戏流畅,占有空间小,响应快。

作用范围:

1.休闲娱乐,消磨时间。

2.挑战自我,提高反应速度和策略规划能力。              

3.用于社交,与朋友进行分数比较和挑战。

开发背景:

          在暑期里复习GUI编程,提高专业能力。

    1. 系统(或用户)的特点
  1. 难度多样化:包含简单,正常,困难三种模式。
  2. 个性化设置:允许用户自定义游戏内皮肤,以适应个人偏好
  1. 假定和约束

本产品预计四天完成。

  1. 需求规定
    1. 软件功能说明

3.1.1 软件功能列表

  1. 游戏主系统:

功能1:控制贪吃蛇移动

功能2:吃食物增加长度

功能3:碰撞检测(墙壁或自身)

功能4:游戏结束判定

         

  1. 游戏难度子系统

功能1:简单 200ms

功能2:正常 100ms

功能3:困难 40ms

  1. 用户设置子系统

  功能1:更改游戏皮肤

3.1.2 主要业务流程分析

  1. 启动游戏:用户打开游戏软件,进入主界面。
  2. 选择模式:用户通过鼠标点击左下方按钮选择游戏难度。
  3. 控制移动:用户通过键盘控制贪吃蛇移动方向。
  4. 吃食物:贪吃蛇吃到食物,长度增加,食物再次随机刷新。
  5. 游戏结束:贪吃蛇撞墙或撞到自身,游戏结束。

3.1.3 软件部署结构分析

    1. 对功能的一般性规定
  1. 用户界面一致性设计,游戏界面为900*750。
  2. 响应式设计:键盘操作时有视觉反馈。
    1. 对性能的一般性规定
  1. 响应速度快,用户操作后可迅速给出反馈。
  2. 稳定性强:长时间运行时不会出现错误异常等情况。
    1. 其他专门要求
  1. 数据安全
  2. 多平台兼容Windows,macOS,Linux,iOS,Android在安装JDK后都可运行
    1. 对安全性的要求
  1. 保证在各种情况下软件能够稳定运行。
  2. 对数据进行保护,确保用户输入的数据不会被非法获取,篡改和泄露。
  3. 合理设置权限,只有授权的操作才能被执行。
  1. 运行环境规定
    1. 设备及分布

主机类型:个人计算器

网络类型:有线网络,无线网络,移动网络,离线都可以运行。

存贮器容量:几百KB到几MB左右

其他特殊设备:外接键盘

设备分布图:

    1. 支撑软件

操作系统:Windows操作系统。

数据库管理系统:简单的计算器代码不需要用到数据库管理系统。

其他支撑软件:集成开发环境(IDE)。

    1. 接口
  1. 该程序并未设计接口
    1. 程序运行方式

 独立运行程序

  1. 尚需解决的问题

问题1:游戏地图相对简单,更多游戏地图待开发

问题2:现阶段只适用于java运行环境,并未打包为程序应用

问题3:游戏在高难度下是否会出现不支持的情况

问题4:还不能帮助用户存储,查询,管理历史成绩

代码实现

package YMP.GUI.Snake;
​
import javax.swing.*;
​
//游戏的主启动类
public class startGame {
    public static void main(String[] args) {
        JFrame frame=new JFrame();
​
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
​
        frame.setBounds(10,10,900,750);
        frame.setResizable(false);//设置窗口大小不可变
        frame.setTitle("贪吃蛇");
​
        //正常的游戏界面是在游戏面板上!
        frame.add(new gamePanel());
        frame.setVisible(true);
​
​
​
    }
}
​

package YMP.GUI.Snake;
​
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
​
//游戏面板
public class gamePanel extends JPanel implements KeyListener , ActionListener {
​
    //定义蛇的数据结构
    int length;//蛇的长度
    int []snakeX=new int[600];//蛇的X坐标25*25
    int []snakeY=new int[500];//蛇的Y坐标25*25
​
    //方向
    String orientation;
​
​
    //食物的坐标
    int foodX;
    int foodY;
    Random random=new Random();
​
​
    //成绩
    int score;
​
​
​
    //游戏当前的状态:开始,停止
    boolean isStart=false;//默认停止!
​
​
    //游戏失败状态
    boolean isFaild=false;
​
​
    //定时器,以毫秒为单位
    Timer timer=new Timer(100,this);//100毫秒执行一次
​
​
    //构造器
    public gamePanel(){
        this.setLayout(null);
        init();
        //获得焦点和键盘事件
        this.setFocusable(true);//获得焦点事件
        this.addKeyListener(this);//获得键盘监听事件
        timer.start();//游戏一开始定时器就启动
​
        //菜单按钮
        JButton button=new JButton();
        button.setIcon(Data.set);
        button.setBackground(Color.white);
        button.setFocusable(false);
​
        ButtonGroup buttonGroup=new ButtonGroup();
​
​
        JDialog dialog=new JDialog();
        dialog.setSize(400,400);
        dialog.setTitle("更多");
        dialog.setFont(new Font("宋体",Font.BOLD,24));
        dialog.setLayout(new GridLayout(3,3));
​
        JCheckBox checkboxNormal=new JCheckBox("难度:正常");
        JCheckBox checkboxSimple=new JCheckBox("难度:简单");
        JCheckBox checkboxDifficlty=new JCheckBox("难度:困难");
​
        checkboxNormal.setFont(new Font("宋体",Font.BOLD,24));
        checkboxDifficlty.setFont(new Font("宋体",Font.BOLD,24));
        checkboxSimple.setFont(new Font("宋体",Font.BOLD,24));
​
        buttonGroup.add(checkboxNormal);
        buttonGroup.add(checkboxSimple);
        buttonGroup.add(checkboxDifficlty);
​
        dialog.add(checkboxNormal);
        dialog.add(checkboxSimple);
        dialog.add(checkboxDifficlty);
​
        checkboxNormal.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                timer.setDelay(100);
            }
        });
​
        checkboxSimple.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                timer.setDelay(200);
            }
        });
​
        checkboxDifficlty.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                timer.setDelay(40);
            }
        });
​
​
​
​
​
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dialog.setVisible(true);
            }
        });
        button.setBounds(10,680,32,32);
        this.add(button);
​
​
​
    }
​
​
​
    //初始化方法
    public void init(){
        length=3;
        snakeX[0]=100; snakeY[0]=100;//脑袋的坐标
        snakeX[1]=75; snakeY[1]=100;//第一个身体的坐标
        snakeX[2]=50; snakeY[2]=100;//第二个身体的坐标
        orientation="R";//初始方向向右
​
        //把食物随机分布在界面上
        foodX=25+25*random.nextInt(34);
        foodY=75+25*random.nextInt(24);
​
​
        //初始成绩
        score=0;
​
​
​
​
    }
​
​
​
​
​
    //绘制面板,游戏所有东西使用此方法的画笔来画
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);//清屏
        this.setBackground(Color.white);
​
        //绘制静态面板
        Data.header.paintIcon(this,g,25,0);//头部广告栏
​
        g.fillRect(25,75,850,600);//默认的游戏界面
​
​
        //画积分
        g.setColor(new Color(0x72D9E2));
        g.setFont(new Font("宋体",Font.BOLD,18));
        g.drawString("长度"+length,450,30);
        g.drawString("分数"+score,450,55);
​
​
        //画食物
        Data.food.paintIcon(this,g,foodX,foodY);
​
​
        //把小蛇放上去
        if (orientation.equals("R")){
            Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);//脑袋初始化向右,通过方向来判断
        }else if (orientation.equals("L")){
            Data.left.paintIcon(this,g,snakeX[0],snakeY[0]);
        }else if (orientation.equals("U")){
            Data.up.paintIcon(this,g,snakeX[0],snakeY[0]);
        }else if (orientation.equals("D")){
            Data.down.paintIcon(this,g,snakeX[0],snakeY[0]);
        }
​
​
        //身体生成
        for (int i=1;i<length;i++){
            Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);
        }
​
​
​
        //游戏状态
        if(isStart==false){
            g.setColor(Color.white);
            //设置字体
            g.setFont(new Font("宋体",Font.BOLD,40));
            g.drawString("按下空格开始游戏",300,300);
        }
​
​
        //游戏失败
        if(isFaild==true){
            g.setColor(Color.red);
            g.setFont(new Font("宋体",Font.BOLD,40));
            g.drawString("失败,按下空格重新开始",300,300);
        }
​
    }
​
​
    //事件监听--需要通过固定的事件来判断,1s-10此
    @Override
    public void actionPerformed(ActionEvent e) {
        if(isStart && isFaild==false){//如果游戏是开始状态,就让小蛇动起来
​
            //吃食物
            if (snakeX[0]==foodX&&snakeY[0]==foodY){
                length++;//长度加一
                score=score+10;//分数加10
​
​
                //再次随机食物
                foodX=25+25*random.nextInt(34);
                foodY=75+25*random.nextInt(24);
            }
​
​
            //移动
            for (int i=length-1;i>0;i--){
                snakeX[i]=snakeX[i-1];//向前移动一节
                snakeY[i]=snakeY[i-1];
            }
​
​
            //走向
            if (orientation.equals("R")){
                snakeX[0]=snakeX[0]+25;
​
                //边界判断
                if ((snakeX[0]>850)){
                    snakeX[0]=25;
                }
            } else if (orientation.equals("L")) {
                snakeX[0]=snakeX[0]-25;
​
                //边界判断
                if(snakeX[0]<25){
                    snakeX[0]=850;
                }
            } else if (orientation.equals("U")) {
                snakeY[0]=snakeY[0]-25;
​
                //边界判断
                if (snakeY[0]<75){
                    snakeY[0]=650;
                }
            } else if (orientation.equals("D")) {
                snakeY[0]=snakeY[0]+25;
​
                //边界判断
                if (snakeY[0]>650){
                    snakeY[0]=75;
                }
            }
​
            //失败判定,撞到自己算失败
            for (int i=1;i<length;i++){
                if (snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
                    isFaild=true;
                }
            }
​
            repaint();
        }
        timer.start();
    }
​
​
    @Override
    public void keyTyped(KeyEvent e) {
​
    }
​
//键盘监听器
    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode=e.getKeyCode();//获得键盘按键是哪一个
​
        if(keyCode==KeyEvent.VK_SPACE){//如果按下的是空格键
           if(isFaild){
               //重新开始
               isFaild=false;
               init();
           } else {
               isStart=!isStart;//取反
           }
​
           repaint();
​
        }
​
​
        //小蛇移动,向下时不能向上撞自己,同理。
        if (keyCode==KeyEvent.VK_UP && orientation!="D"){
            orientation="U";
        } else if (keyCode==KeyEvent.VK_DOWN && orientation!="U") {
            orientation="D";
        } else if (keyCode==KeyEvent.VK_LEFT && orientation!="R") {
            orientation="L";
        } else if (keyCode==KeyEvent.VK_RIGHT && orientation!="L") {
            orientation="R";
        }
​
    }
​
​
    @Override
    public void keyReleased(KeyEvent e) {
​
    }
}
​
​
​
​

package YMP.GUI.Snake;
​
import javax.swing.*;
import java.awt.*;
import java.net.URL;
​
//数据中心
public class Data {
    //相对路径
    //绝对路径  / 相当于当前的项目
​
    public static ImageIcon header=new ImageIcon("E:\\code\\java\\Hello\\src\\main\\java\\YMP\\GUI\\Snake\\Static\\header.png");
​
​
    public static ImageIcon up=new ImageIcon("E:\\code\\java\\Hello\\src\\main\\java\\YMP\\GUI\\Snake\\Static\\up.png");
​
​
    public static ImageIcon down=new ImageIcon("E:\\code\\java\\Hello\\src\\main\\java\\YMP\\GUI\\Snake\\Static\\down.png");
​
​
    public static ImageIcon left=new ImageIcon("E:\\code\\java\\Hello\\src\\main\\java\\YMP\\GUI\\Snake\\Static\\left.png");
​
​
    public static ImageIcon right=new ImageIcon("E:\\code\\java\\Hello\\src\\main\\java\\YMP\\GUI\\Snake\\Static\\right.png");
​
​
    public static ImageIcon food=new ImageIcon("E:\\code\\java\\Hello\\src\\main\\java\\YMP\\GUI\\Snake\\Static\\food.png");
​
​
    public static ImageIcon body=new ImageIcon("E:\\code\\java\\Hello\\src\\main\\java\\YMP\\GUI\\Snake\\Static\\body.png");
​
    public static ImageIcon set=new ImageIcon("E:\\code\\java\\Hello\\src\\main\\java\\YMP\\GUI\\Snake\\Static\\a.png");
​
​
​
​
​
}
​

  • 21
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值