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

简介: 文章目录1 开发环境及游戏展示1.1 游戏主界面1.2 移动界面1.3 奖励界面1.4 F加速功能界面1.5 死亡界面2 需求分析3 系统设计3.1 系统总体功能设计3.2 系统总体流程设计4 功能设计4.1 贪吃蛇移动及加速功能设计4.2 贪吃蛇吃食物加速及死亡判定功能的设计4.2.1 贪吃蛇吃食物加速功能的设计4.2.2 贪吃蛇死亡判定功能的设计4.3 贪吃蛇主动加速功能的设计4.4 贪吃蛇奖励机制功能的设计5 项目结构与项目实现5.1 项目结构及类间关系5.2 项目完整源码5.2.1 Images类

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);
    }
}


相关文章
|
10月前
|
安全 Java API
Java中的Lambda表达式:简洁与功能的结合
Java中的Lambda表达式:简洁与功能的结合
570 211
|
9月前
|
消息中间件 人工智能 Java
抖音微信爆款小游戏大全:免费休闲/竞技/益智/PHP+Java全筏开源开发
本文基于2025年最新行业数据,深入解析抖音/微信爆款小游戏的开发逻辑,重点讲解PHP+Java双引擎架构实战,涵盖技术选型、架构设计、性能优化与开源生态,提供完整开源工具链,助力开发者从理论到落地打造高留存、高并发的小游戏产品。
|
9月前
|
存储 数据可视化 Java
Java Stream API 的强大功能
Java Stream API 是 Java 8 引入的重要特性,它改变了集合数据的处理方式。通过声明式语法,开发者可以更简洁地进行过滤、映射、聚合等操作。Stream API 支持惰性求值和并行处理,提升了代码效率和可读性,是现代 Java 开发不可或缺的工具。
192 0
Java Stream API 的强大功能
|
10月前
|
前端开发 JavaScript Java
Java 项目实战城市公园信息管理系统开发流程与实用功能实现指南
本系统基于Java开发,采用Spring Boot后端框架与Vue.js前端框架,结合MySQL数据库,构建了一个高效的城市公园信息管理系统。系统包含管理员、用户和保洁人员三大模块,涵盖用户管理、园区信息查询、订票预约、服务管理等功能,提升公园管理效率与服务质量。
285 6
|
10月前
|
安全 Java 数据库
Java 项目实战病人挂号系统网站设计开发步骤及核心功能实现指南
本文介绍了基于Java的病人挂号系统网站的技术方案与应用实例,涵盖SSM与Spring Boot框架选型、数据库设计、功能模块划分及安全机制实现。系统支持患者在线注册、登录、挂号与预约,管理员可进行医院信息与排班管理。通过实际案例展示系统开发流程与核心代码实现,为Java Web医疗项目开发提供参考。
452 2
|
9月前
|
存储 小程序 Java
热门小程序源码合集:微信抖音小程序源码支持PHP/Java/uni-app完整项目实践指南
小程序已成为企业获客与开发者创业的重要载体。本文详解PHP、Java、uni-app三大技术栈在电商、工具、服务类小程序中的源码应用,提供从开发到部署的全流程指南,并分享选型避坑与商业化落地策略,助力开发者高效构建稳定可扩展项目。
|
10月前
|
机器学习/深度学习 算法 Java
Java 大视界 -- Java 大数据机器学习模型在生物信息学基因功能预测中的优化与应用(223)
本文探讨了Java大数据与机器学习模型在生物信息学中基因功能预测的优化与应用。通过高效的数据处理能力和智能算法,提升基因功能预测的准确性与效率,助力医学与农业发展。
|
安全 Java
Java并发编程笔记之CopyOnWriteArrayList源码分析
并发包中并发List只有CopyOnWriteArrayList这一个,CopyOnWriteArrayList是一个线程安全的ArrayList,对其进行修改操作和元素迭代操作都是在底层创建一个拷贝数组(快照)上进行的,也就是写时拷贝策略。
19727 0
|
Java 安全
Java并发编程笔记之读写锁 ReentrantReadWriteLock 源码分析
我们知道在解决线程安全问题上使用 ReentrantLock 就可以,但是 ReentrantLock 是独占锁,同时只有一个线程可以获取该锁,而实际情况下会有写少读多的场景,显然 ReentrantLock 满足不了需求,所以 ReentrantReadWriteLock 应运而生,ReentrantReadWriteLock 采用读写分离,多个线程可以同时获取读锁。
3352 0
|
Java
Java并发编程笔记之FutureTask源码分析
FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。
4490 0