Java实现贪吃蛇大作战小游戏(完整教程+源码)额外实现积分和变速功能

大家好,我是黄小黄同学!今天给大家带来的是小项目是 基于Java+Swing+IO流实现 的贪吃蛇大作战小游戏。实现了界面可视化、基本的吃食物功能、死亡功能、移动功能、积分功能,并额外实现了主动加速和鼓励机制。贪吃蛇大作战完整资源已上传,供大家下载交流学习~ Java实现贪吃蛇大作战完整资源下载

🍊效果展示:
在这里插入图片描述



1 开发环境及游戏展示

贪吃蛇大作战在设计与实验的过程中需要在Window 10系统中进行,并使用开发工具IntelliJ IDEA Community Edition 2020.3.2(jdk-15)完成代码的编写、编译、调试、测试等工作。程序需要的组件如贪吃蛇的蛇头、蛇身及背景图片等均使用图像软件Adobe Photoshop 2020制作。

1.1 游戏主界面

在这里插入图片描述

1.2 移动界面

在这里插入图片描述

1.3 奖励界面

1.游戏达到50分:
在这里插入图片描述
2.游戏达到100分:
在这里插入图片描述

1.4 F加速功能界面

按下F时,速度提高到100。
在这里插入图片描述

1.5 死亡界面

在这里插入图片描述


2 需求分析

贪吃蛇游戏是一个小型益智游戏,可用于人们日常的休闲、娱乐等场景。本次游戏设计涉及一维数组、Swing中的常用组件、GUI中的事件处理(事件监听器、键盘监听器)、类的封装与继承、static静态变量、包装类、随机数等方面的知识。
具体需求概要如下:

  1. 初始化界面为800×800大小,且游戏界面应保持在屏幕中央,窗口应有“贪吃蛇”字样;
  2. 游戏界面应有必要的提示文字,提示游戏的得分和蛇的当前速度。开始界面应有操作提示文字(轻按空格游戏以开始/暂停游戏、按住F以加速),文字颜色应美观;
  3. 在程序中初始化蛇的位置(靠近面板左侧)、蛇的方向(默认向右)、蛇的长度(默认为3),并初始化食物的位置;
  4. 游戏的开始与暂停的实现:通过空格键控制游戏的开始与暂停;
  5. 蛇移动功能的实现:用W、S、A、D或↑、↓、←、→控制蛇的运动方向为上、下、左、右进行游戏;
  6. 当蛇头接触活动外围时:蛇头接触界面最右(左)端则从对称的左(右)端出现,以此类推,当蛇头接触界面最上(下)端则从对称的下(上)端出现;
  7. 蛇吃食物的功能的实现:游戏过程中,蛇头触碰到食物时,即为吃食物。此时蛇的长度应加1,速度应增加10,得分增加10,并刷新食物的位置(随机位置);
  8. 蛇加速功能的实现:当按住“F”键时,蛇加速运动,速度值达到100;当松开“F”键时,蛇恢复至默认速度10;
  9. 蛇的死亡判定:当蛇头触碰到蛇身时,蛇死亡,游戏结束,界面靠近中央提示:“你的小蛇已经死亡,按下空格重新开始!”;
  10. 游戏的奖励机制的实现:当得分为10时,游戏提示“Good!”字样;当得分为50时,游戏提示“Good!!!”字样;当得分为100时,游戏提示“Perfect!!!”字样;当得分达到200时,则游戏提示“无人能挡!!!”的字样;以上提示字样均位于蛇头;

🦁 基本操作表如下:
在这里插入图片描述


3 系统设计

3.1 系统总体功能设计

此贪吃蛇程序大方向上包含贪吃蛇的移动功能、贪吃蛇的主动加速功能、游戏规则判断功能、主界面控制功能、贪吃蛇吃食物功能。其中贪吃蛇的移动功能中包含移动方向的按键控制以及贪吃蛇的自动移动;游戏规则判断功能包括蛇的死亡判断、游戏开始与暂停判断以及越界规则;主界面控制功能包含蛇的初始化以及食物的初始化;贪吃蛇吃食物功能包括蛇身增长、蛇速度增加、积分增加和食物刷新位置。具体功能结构图如下:
在这里插入图片描述

3.2 系统总体流程设计

开始进入贪吃蛇程序时首先判断是否按下空格键,如果按下空格键则游戏开始。游戏开始后判断是否有按键输入,若有按键输入则根据按键设置改变蛇的移动方向或者进行加速操作;若没有按键操作则蛇继续保持原方向运动。在蛇运动过程中判断蛇是否吃到食物,若吃到食物则游戏得分加10,蛇的移动速度也相应增加;不管是否吃到食物都进行蛇是否死亡的判断,若死亡则游戏结束;若蛇没有死亡则继续判断是否有空格输入,若有则游戏暂停,反之则继续判断按键,根据按键改变蛇的运动状态,继续游戏,直到蛇死亡,游戏结束。
在这里插入图片描述


4 功能设计

4.1 贪吃蛇移动及加速功能设计

贪吃蛇的移动功能主要依赖于选择语句和键盘监听器来实现,用W、S、A、D或↑、↓、←、→控制蛇的运动方向为上、下、左、右进行游戏。当按下F键时,蛇加速运动。
在这里插入图片描述

4.2 贪吃蛇吃食物加速及死亡判定功能的设计

在贪吃蛇吃食物以及死亡判定的过程中,使用到了以下参数:

  • Timer类的一个参数:int 类型的time,程序中调用timer.setDelay(time)方法更改定时器的参数(time越小,蛇运动越快);
  • 记录蛇死亡与否的参数:boolean 类型的isDied(true则蛇死,false则蛇活),默认为false;
  • 蛇的长度:int 类型的length(初始为3);
  • 积分参数:int 类型的score(初始为0),程序中通过循环控制每吃一次食物加10分;
  • 蛇头的坐标:int类型的snakeX[0]与snakeY[0],分别储存蛇头的横纵坐标;
  • 蛇身的坐标:int[] 类型的snakeX[i]和snakeY[i],分别储存每一节蛇身的横纵坐标(i≠0);
  • 食物的坐标:int 类型的foodX,foodY,分别储存食物的横纵坐标,foodX与foodY均为使用Random类中的nextInt()方法产生的随机数,故食物的坐标是随机的。
    以下使用上述参数时便不再赘述。

4.2.1 贪吃蛇吃食物加速功能的设计

当蛇头的坐标snakeX[0]与snakeY[0]分别与食物的坐标foodX,foodY相等时,得分score增加10,蛇身长度length加1,Timer参数time减10,从而完成蛇吃到食物后的加分,蛇身加长及加速功能。该功能的流程设计图如下:
在这里插入图片描述

4.2.2 贪吃蛇死亡判定功能的设计

当贪吃蛇吃到自己的时候蛇死亡,即蛇头坐标snakeX[0]与snakeY[0]分别与蛇身坐标snakeX[i]和snakeY[i]相等时,即蛇死亡。此时isDied=!isDied。
在这里插入图片描述

4.3 贪吃蛇主动加速功能的设计

贪吃蛇的主动加速功能即在游戏过程中按住F键,蛇的移动速度加快,若按住后松开,则蛇的速度恢复默认值。这主要通过GUI中的键盘监听器来实现,实现了键盘监听器的两个方法,keyPressed()与keyReleased()分别监听按下F键的操作和松开F键的操作。其次用到了参数time,程序中改变time的值通过调用timer.setDelay(time)方法(timer为Timer类的一个对象)从而改变定时器的频率,达到蛇速度加快的效果。
在这里插入图片描述

4.4 贪吃蛇奖励机制功能的设计

贪吃蛇奖励机制功能主要使用了选择结构以及通过paintComponent(Graphics g)方法中的画笔工具来实现。当游戏达到一定的得分时,程序会调用画笔工具中的g.drawString(“XXX”,snakeX[0],snakeY[0])方法,在蛇头位置绘制出提示文字。
在这里插入图片描述


5 项目结构与项目实现

5.1 项目结构及类间关系

在这里插入图片描述
在这里插入图片描述

5.2 项目完整源码

5.2.1 Images类

  • 该类为静态类,主要存储贪吃蛇组件的图片对象。
package snakegame;

import javax.swing.*;
import java.net.URL;

//Images类用于封装图片路径以及获取图片(使用静态对象便于用类名直接访问)
public class Images {
    //将图片的路径封装成一个对象
    public static URL bodyURL=Images.class.getResource("/snake_images/body.jpg");
    public static URL backURL=Images.class.getResource("/snake_images/back.jpg");
    public static URL snakeDownURL=Images.class.getResource("/snake_images/snakeDown.jpg");
    public static URL snakeLeftURL=Images.class.getResource("/snake_images/snakeLeft.jpg");
    public static URL snakeRightURL=Images.class.getResource("/snake_images/snakeRight.jpg");
    public static URL snakeUpURL=Images.class.getResource("/snake_images/snakeUp.png");
    public static URL foodURL=Images.class.getResource("/snake_images/food.jpg");
    //将图片封装为程序中的对象
    public static ImageIcon bodyImg=new ImageIcon(bodyURL);
    public static ImageIcon backImg=new ImageIcon(backURL);
    public static ImageIcon snakeDownImg=new ImageIcon(snakeDownURL);
    public static ImageIcon snakeUpImg=new ImageIcon(snakeUpURL);
    public static ImageIcon snakeRightImg=new ImageIcon(snakeRightURL);
    public static ImageIcon snakeLeftImg=new ImageIcon(snakeLeftURL);
    public static ImageIcon foodImg=new ImageIcon(foodURL);
}

5.2.2 HighestScore

  • 该类实现历史最高分功能。
package snakegame;

import org.w3c.dom.Text;

import java.io.*;

//该类用于给游戏添加历史最高分功能
public class HighestScore {
    static int score = 0;//最高分的存储

    public void highest() throws IOException {
        //得分为最高分时存储
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(String.valueOf(Text.class.getResourceAsStream("贪吃蛇大作战/score.txt"))));
        if (GamePanel.score > score) {
            score = GamePanel.score;
            String s1 = String.valueOf(score);
            bos.write(s1.getBytes());
        }
        bos.close();
    }

    //用于游戏开始时从文件读取最高分的值
    public void readHighest() throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(String.valueOf(Text.class.getResourceAsStream("贪吃蛇大作战/score.txt"))));
        byte[] bys = new byte[1024];
        int len;
        while ((len = bis.read(bys)) != -1) {
            System.out.print(new String(bys, 0, len));//测试用
            String s2 = new String(bys, 0, len);
            score = Integer.valueOf(s2);
        }
        bis.close();
    }
}

5.2.3 GamePanel类

  • 该类用于绘制贪吃蛇游戏面板,以及实现游戏具体逻辑功能。
package snakegame;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.Random;

//贪吃蛇游戏面板的绘制
public class GamePanel extends JPanel {
    Timer timer;
    int time=100;
    static int score;//记录游戏分数
    //蛇属性部分
    boolean isDied;
    int length;//设置蛇长
    String direction;//蛇头朝向
    //分别储存蛇身的X,Y坐标
    int[] snakeX=new int[300];
    int[] snakeY=new int[300];
    //判断游戏是否开始
    boolean isStart=false;
    int foodX,foodY;//食物的X,Y坐标
    //贪吃蛇初始化方法
    public void init(){
        length=3;
        snakeX[0]=175;
        snakeY[0]=275;
        snakeX[1]=150;
        snakeY[1]=275;
        snakeX[2]=125;
        snakeY[2]=275;
        foodX=300;
        foodY=400;
        score=0;
        isDied=false;//蛇默认状态为活着
        direction="R";//U,D,L,R分别表示蛇头朝向上,下,左,右
    }

    //构造方法
    public GamePanel() throws IOException {
        init();

        if(GamePanel.score>HighestScore.score){
            new HighestScore().highest();
        }
        //焦点定位到当前面板
        this.setFocusable(true);
        //监听器的实现部分
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                super.keyPressed(e);
                int keyCode = e.getKeyCode();
                //按下空格以开始游戏,以及方向键的控制
                if (keyCode == KeyEvent.VK_SPACE) {
                    if(isDied){
                        init();
                    }else {
                        isStart = !isStart;
                        repaint();//重绘
                    }
                } else if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_W) {
                    direction = "U";
                } else if (keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_S) {
                    direction = "D";
                } else if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_A) {
                    direction = "L";
                } else if (keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_D) {
                    direction = "R";
                }
            }
        });
        //贪吃蛇加速功能的实现
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int keyCode=e.getKeyCode();
                if(keyCode==KeyEvent.VK_F){
                    time=10;
                    timer.setDelay(time);//按下F时加速
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
                int keyCode=e.getKeyCode();
                if(keyCode==KeyEvent.VK_F){
                    time=100;
                    timer.setDelay(time);//松开F键减速恢复默认速度
                }
            }
        });
        //对定时器进行初始化,并实现监听器
            timer = new Timer(time, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    //当游戏处于开始状态且蛇活着时蛇活动,且后一节身子到前一节身子的位置上(每一节身子为25乘25像素)
                    if (isStart && isDied == false) {
                        //蛇身运动部分
                        for (int i = length - 1; i > 0; i--) {
                            snakeX[i] = snakeX[i - 1];
                            snakeY[i] = snakeY[i - 1];
                        }
                        //蛇头运动部分
                        if ("D".equals(direction)) {
                            snakeY[0] += 25;
                        }
                        if ("U".equals(direction)) {
                            snakeY[0] -= 25;
                        }
                        if ("L".equals(direction)) {
                            snakeX[0] -= 25;
                        }
                        if ("R".equals(direction)) {
                            snakeX[0] += 25;
                        }
                        //防止超出边界
                        if (snakeX[0] > 750) {
                            snakeX[0] = 25;
                        }
                        if (snakeX[0] < 25) {
                            snakeX[0] = 750;
                        }
                        if (snakeY[0] < 100) {
                            snakeY[0] = 725;
                        }
                        if (snakeY[0] > 725) {
                            snakeY[0] = 100;
                        }
                        //吃食物的动作,吃食物加10分且蛇身变长,蛇的速度提升10
                        if ((snakeX[0] == foodX && snakeY[0] == foodY)) {
                            length++;//蛇身长度加1
                            foodX = (new Random().nextInt(30) + 1) * 25;//随机生成X坐标[25,750]
                            foodY = (new Random().nextInt(26) + 4) * 25;//随机生成Y坐标[100,725]
                            score += 10;//吃一次食物积分加10
                            try {
                                new HighestScore().highest();
                            } catch (IOException ioException) {
                                ioException.printStackTrace();
                            }
                            if(time>10)
                                timer.setDelay(time-=10);//吃一次食物速度增加10
                        }
                        //蛇的死亡机制判定
                        for (int i = 1; i < length; i++) {
                            if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
                                isDied = !isDied;
                            }
                        }
                        repaint();
                    }
                }
            });
            timer.start();//定时器启动
    }

    //绘制面板部分
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        //填充背景颜色
        this.setBackground(new Color(164, 219, 246));
        //绘制初始蛇头的图片(默认右方朝向)
        Images.backImg.paintIcon(this,g,10,10);
        //调整画笔的颜色并绘制一个矩形面板
        g.setColor(new Color(219,226,219));
        g.fillRect(10,70,770,685);
        //蛇头的绘制;上下左右不同情况
        if("L".equals(direction)){
            Images.snakeLeftImg.paintIcon(this,g,snakeX[0],snakeY[0]);
        }
        if("R".equals(direction)){
            Images.snakeRightImg.paintIcon(this,g,snakeX[0],snakeY[0]);
        }
        if("U".equals(direction)){
            Images.snakeUpImg.paintIcon(this,g,snakeX[0],snakeY[0]);
        }
        if("D".equals(direction)){
            Images.snakeDownImg.paintIcon(this,g,snakeX[0],snakeY[0]);
        }
        //蛇身的绘制
        for(int i=1;i<length;i++) {
            Images.bodyImg.paintIcon(this, g, snakeX[i], snakeY[i]);
        }
        //食物绘制
       Images.foodImg.paintIcon(this,g,foodX,foodY);
        //游戏的文字提示语
        if(!isStart&&!isDied){
            g.setColor(new Color(12, 191, 222));
            g.setFont(new Font("楷体",Font.BOLD,40));
            g.drawString("轻按空格以开始/暂停游戏!",150,330);
            g.setColor(new Color(246, 2, 31));
            g.setFont(new Font("宋体",Font.CENTER_BASELINE,30));
            g.drawString("按住F以加速",300,380);
        }
        //游戏的得分显示
        g.setColor(new Color(248, 4, 74));
        g.setFont(new Font("楷体",Font.BOLD,30));
        g.drawString("得分:"+score,420,90);
        //游戏的最高分展示模块
        try {
            new HighestScore().readHighest();
        } catch (IOException e) {
            e.printStackTrace();
        }
        g.setColor(new Color(183, 25, 238));
        g.setFont(new Font("楷体",Font.BOLD,30));
        g.drawString("历史最高分:"+HighestScore.score,10,90);
        //蛇的速度提示
        g.setColor(new Color(248, 136, 36));
        g.setFont(new Font("楷体",Font.BOLD,30));
        g.drawString("当前速度:"+String.valueOf(110-time),550,90);
        //游戏的奖励鼓励机制
        if(score==10){
            g.setColor(new Color(127, 232, 20));
            g.setFont(new Font("微软雅黑",Font.BOLD,50));
            g.drawString("Good!",snakeX[0],snakeY[0]);
        }
        else if(score==50){
            g.setColor(new Color(17, 231, 250));
            g.setFont(new Font("微软雅黑",Font.BOLD,50));
            g.drawString("Good!!!",snakeX[0],snakeY[0]);
        }else if(score==100){
            g.setColor(new Color(248, 196, 6));
            g.setFont(new Font("微软雅黑",Font.BOLD,50));
            g.drawString("Perfect!!!",snakeX[0],snakeY[0]);
        }else if(score==200){
            g.setColor(new Color(248, 245, 26));
            g.setFont(new Font("微软雅黑",Font.BOLD,50));
            g.drawString("无人能挡!!!",snakeX[0],snakeY[0]);
        }
        //小蛇死亡时面板的绘制
        if(isDied){
            g.setColor(new Color(6, 115, 248));
            g.setFont(new Font("微软雅黑",Font.BOLD,30));
            g.drawString("你的小蛇已经死亡,按下空格重新开始!",170,330);
        }
    }
}

5.2.4 Start类

  • 页面的总体布局与程序的入口。
package snakegame;

import javax.swing.*;
import java.awt.*;
import java.io.IOException;

//贪吃蛇总体界面布局以及程序的主方法
public class Start {
    public static void main(String[] args) throws IOException {
        JFrame jf=new JFrame("贪吃蛇");
        //获取屏幕的大小,并使用数据使窗口位置居中
        int width= Toolkit.getDefaultToolkit().getScreenSize().width;
        int height= Toolkit.getDefaultToolkit().getScreenSize().height;
        jf.setBounds((width-800)/2,(height-800)/2,800,800);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setResizable(false);//设置窗口大小不能更改
        //添加GamePanel面板
        GamePanel panel=new GamePanel();
        jf.add(panel);
        jf.setVisible(true);
    }
}
  • 43
    点赞
  • 67
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 30
    评论
Java实现贪吃蛇小游戏可以使用Java Swing和AWT库来实现界面和交互,使用Java集合框架来实现蛇身体的存储和移动,以及使用定时器来控制游戏的速度和刷新。 具体实现步骤如下: 1. 定义一个Snake类代表蛇,包含蛇头的坐标、蛇的长度以及蛇的方向等属性,以及包含蛇身体的坐标列表等属性和方法。 2. 定义一个Food类代表食物,包含食物的坐标等属性和方法。 3. 定义一个GamePanel类代表游戏面板,继承自JPanel类,包含游戏的主要逻辑和交互,如蛇的移动、食物的生成和判断、游戏结束等。 4. 在GamePanel类中,使用定时器Timer来控制游戏的速度和刷新,以及使用Java集合框架来实现蛇身体的存储和移动,以及检测蛇头是否撞墙或撞到自己身体等。 下面是Java代码实现的伪代码: ```java // 定义Snake类 class Snake { // 蛇头的坐标 int x, y; // 蛇的长度 int length; // 蛇的方向 int direction; // 蛇身体的坐标列表 List<Point> body; // 蛇的移动方法 void move(); // 检测蛇头是否撞到自己身体的方法 boolean checkCollision(); } // 定义Food类 class Food { // 食物的坐标 int x, y; // 食物的生成方法 void generate(); } // 定义GamePanel类 class GamePanel extends JPanel implements ActionListener { // 蛇和食物的实例 Snake snake; Food food; // 定时器 Timer timer; // 构造方法 public GamePanel() { // 初始化蛇和食物 snake = new Snake(); food = new Food(); food.generate(); // 创建定时器 timer = new Timer(100, this); timer.start(); } // 绘制游戏界面的方法 void paintComponent(Graphics g); // 处理定时器事件的方法 void actionPerformed(ActionEvent e); // 处理按键事件的方法 void keyPressed(KeyEvent e); // 判断游戏是否结束的方法 boolean isGameOver(); } ``` 上述代码中,Snake类包含蛇头的坐标、长度和方向等属性,以及蛇身体的坐标列表和移动、检测撞墙和撞到自己身体等方法。Food类包含食物的坐标和生成方法。GamePanel类继承自JPanel类,包含游戏的主要逻辑和交互,如蛇的移动、食物的生成和判断、游戏结束等,并使用定时器控制游戏的速度和刷新。在main方法中,创建GamePanel实例并添加到JFrame中即可实现贪吃蛇小游戏

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兴趣使然黄小黄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值