Java GUI实现贪吃蛇游戏

贪吃蛇是一款经典的游戏,玩法相对简单但富有挑战性。以下是贪吃蛇游戏的基本玩法说明:

  1. 目标:控制一条蛇,在游戏区域内吃到尽可能多的食物,使蛇身变长,同时避免撞到自己的身体或游戏区域的边界。

  2. 控制:通常使用方向键(上、下、左、右)或滑动屏幕来控制蛇的移动方向,使其朝着食物的方向前进。

  3. 食物和增长:在游戏区域内随机生成食物。当蛇头接触到食物时,蛇身增长一个单位,并且得分会增加。

  4. 增加难度:随着蛇身不断增长,游戏会变得更加困难。蛇的身体会占据更多的空间,同时移动速度可能加快。

  5. 失败条件:游戏结束的条件包括蛇头撞到自己的身体或者撞到游戏区域的边界。

  6. 计分:游戏通常会记录你的得分,即吃到的食物数量或者游戏时长。

贪吃蛇是一款简单而又令人上瘾的游戏,你可以在各种平台上找到不同版本的贪吃蛇游戏。希望你能享受这个经典游戏带来的乐趣!

以下是Java实现的基本贪吃蛇游戏代码,你可以根据自己的需求进行修改和完善:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

public class SnakeGame extends JFrame implements KeyListener {

    private static final long serialVersionUID = 1L;

    private JPanel panel;
    private static JLabel scoreLabel, gameOverLabel;
    private static int score = 0;
    private static int highScore = 0;
    private static boolean gameOver = false;

    private static final int ROWS = 30, COLS = 30;
    private static final int CELL_SIZE = 20;

    private Snake snake;
    private Food food;
    private Timer timer;

    public static void main(String[] args) {
        new SnakeGame().setVisible(true);
    }

    public SnakeGame() {
        setTitle("贪吃蛇游戏");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);

        panel = new JPanel();
        panel.setPreferredSize(new Dimension(ROWS * CELL_SIZE, COLS * CELL_SIZE));
        getContentPane().add(panel);
        addKeyListener(this);

        scoreLabel = new JLabel("得分: 0  最高分: " + highScore);
        panel.add(scoreLabel);

        gameOverLabel = new JLabel("游戏结束");
        gameOverLabel.setForeground(Color.RED);
        gameOverLabel.setVisible(false);
        panel.add(gameOverLabel);

        snake = new Snake();
        food = new Food(snake);
        food.generate();

        timer = new Timer(100, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                snake.update();
                checkGameOver();
                panel.repaint();
            }
        });
        timer.start();
        pack();
        setLocationRelativeTo(null);
    }

    private void checkGameOver() {
        if (snake.checkCollision()) {
            gameOver = true;
            gameOverLabel.setVisible(true);
            timer.stop();

            if (score > highScore) {
                highScore = score;
                scoreLabel.setText("得分: " + score + "  最高分: " + highScore);
            }
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (!gameOver) {
            int keyCode = e.getKeyCode();
            if (keyCode == KeyEvent.VK_UP) {
                snake.changeDirection(Snake.UP);
            } else if (keyCode == KeyEvent.VK_DOWN) {
                snake.changeDirection(Snake.DOWN);
            } else if (keyCode == KeyEvent.VK_LEFT) {
                snake.changeDirection(Snake.LEFT);
            } else if (keyCode == KeyEvent.VK_RIGHT) {
                snake.changeDirection(Snake.RIGHT);
            }
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    @Override
    public void keyTyped(KeyEvent e) {
    }

    public class Snake {

        private LinkedList<Point> segments;
        private int direction;

        public static final int UP = 1, DOWN = -1, LEFT = 2, RIGHT = -2;

        public Snake() {
            segments = new LinkedList<Point>();
            segments.add(new Point(3, 0));
            segments.add(new Point(2, 0));
            segments.add(new Point(1, 0));
            segments.add(new Point(0, 0));
            direction = RIGHT;
        }

        public void changeDirection(int newDirection) {
            if (direction + newDirection != 0) {
                direction = newDirection;
            }
        }

        public void update() {
            Point head = segments.getFirst();
            Point newHead = (Point) head.clone();

            if (direction == UP) {
                newHead.translate(0, -1);
            } else if (direction == DOWN) {
                newHead.translate(0, 1);
            } else if (direction == LEFT) {
                newHead.translate(-1, 0);
            } else if (direction == RIGHT) {
                newHead.translate(1, 0);
            }

            segments.addFirst(newHead);
            if (!food.checkCollision(newHead.x, newHead.y)) {
                segments.removeLast();
            } else {
                score++;
                scoreLabel.setText("得分: " + score + "  最高分: " + highScore);
                food.generate();
            }
        }

        public boolean checkCollision() {
            Point head = segments.getFirst();
            if (head.x < 0 || head.x >= COLS || head.y < 0 || head.y >= ROWS) {
                return true;
            }
            for (int i = 1; i < segments.size(); i++) {
                if (segments.get(i).equals(head)) {
                    return true;
                }
            }
            return false;
        }

        public void draw(Graphics g) {
            for (Point p : segments) {
                g.setColor(Color.GREEN);
                g.fillRect(p.x * CELL_SIZE, p.y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
            }
        }
    }

    public class Food {
        private int x, y;
        private Snake snake;
        private Random rand;

        public Food(Snake snake) {
            this.snake = snake;
            rand = new Random();
        }

        public void generate() {
            do {
                x = rand.nextInt(COLS);
                y = rand.nextInt(ROWS);
            } while (snake.segments.contains(new Point(x, y)));
        }

        public boolean checkCollision(int x, int y) {
            if (this.x == x && this.y == y) {
                return true;
            }
            return false;
        }

        public void draw(Graphics g) {
            g.setColor(Color.RED);
            g.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
        }
    }

    @Override
    public void paint(Graphics g) {
        g.setColor(Color.LIGHT_GRAY);
        g.fillRect(0, 0, getWidth(), getHeight());
        snake.draw(g);
        food.draw(g);
    }
}

这个代码实现的贪吃蛇游戏界面为:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/154614.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Apache ActiveMQ RCE

影响版本 Apache ActiveMQ < 5.18.3 利用条件 需要访问到61616端口(默认)。 漏洞分析 这里需要的是Apache ActiveMQ < 5.18.3,我这里直接下的5.18.2 https://github.com/apache/activemq/commit/958330df26cf3d5cdb63905dc2c6882e98781d8f 在新版本中添加了一个Ope…

YOLO目标检测——钢表面缺陷检测数据集下载分享【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;钢材质量控制、钢材缺陷检测数据集说明&#xff1a;钢表面缺陷检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富标签说明&#xff1a;使用lableimg标注软件标注&#xff0c;标注框质量高&#xff0c;含voc(xml)、coco(json)和…

AdServices归因和iAd归因集成

AdServices framework 是 Apple 专门为 ASA 提供的归因框架 。尤其在ATT 政策推出以后&#xff0c;app 获取用户 IDFA 的比例大幅降低&#xff0c;传统的依靠IDFA 的方法也无法准确归因。 但是 Apple 为 ASA 开了一个后门&#xff0c;其他广告渠道无法获取用户的 IDFA 作为身份…

【读点论文】FMViT: A multiple-frequency mixing Vision Transformer-期待源码

FMViT: A multiple-frequency mixing Vision Transformer Abstract transformer模型近年来在计算机视觉任务中得到了广泛的应用。然而&#xff0c;由于自关注的时间和内存复杂度是二次的&#xff0c;并且与输入token的数量成正比&#xff0c;大多数现有的(Vision transformer,…

性能测试【第三篇】Jmeter的使用

线程数:10 ,设置10个并发 Ramp-Up时间(秒):所有线程在多少时间内启动,如果设置5,那么每秒启动2个线程 循环次数:请求的重复次数,如果勾选"永远"将一直发送请求 持续时间时间:设置场景运行的时间 启动延迟:设置场景延迟启动时间 响应断言 响应断言模式匹配规则 包括…

进程间通信

进程间通信 是什么&#xff1f; 两个或者多个进程实现数据层面的交互 为什么&#xff1f; 怎么办&#xff1f; a.进程间通信的本质:必须让不同的进程看到同一份"资源" b."资源"就是特定形式的内存空间 c.这个"资源"谁提供?一般是操作系统&…

EtherCAT从站EEPROM分类附加信息详解:SM(同步管理器)

0 工具准备 1.EtherCAT从站EEPROM数据&#xff08;本文使用DE3E-556步进电机驱动器&#xff09;1 分类附加信息——SM&#xff08;同步管理器&#xff09; 1.1 分类附加信息规范 在EEPROM字64开始的区域存储的是分类附加信息&#xff0c;这里存储了包括设备信息、SM配置、FM…

小程序如何添加打印机来打印订单

在采云小程序中&#xff0c;支持打印订单的小票、标签、发货单和电子面单。小票打印机用于打印小票&#xff0c;类似于超市小票、外卖小票等。标签打印机用于打印商品标签&#xff0c;类似于奶茶上面粘贴的标签&#xff0c;用于表示饮料名称和规格等。货单打印机用于打印发货单…

关于 内部类 你了解多少?(详解!!)

目录 1. 什么是内部类&#xff1f; 2. 内部类的分类 3. 内部类 3.1 实例内部类 3.2 静态内部类 4. 局部内部类 5. 匿名内部类 6.对象的打印 “不积跬步无以至千里&#xff0c;不积小流无以成江海。”每天坚持学习&#xff0c;哪怕是一点点&#xff01;&#xff01;&a…

sqlserver配置管理器无法启动解决方案

在SQL server configuration manager配置管理器中遇到SQL server browser呈灰色&#xff0c;无法启动 右击选择属性 进入服务 将启动模式改为自动 可以启动了

Java面向对象2

代码块 代码块的构造顺序优先于构造器 细节

redis运维(七)基础通用命令

一 基础通用命令 备注&#xff1a; 与具体数据类型无关Tab键 自动补全补充&#xff1a; redis 命令是不区分大小写 通用不到 10 个提升逼格的 redis 命令 后续&#xff1a; slowlog、rename-command、monitor、set ① help command 需求&#xff1a; 显示有关redis命令的…

DVWA - 4

文章目录 JavaScriptlowmedium JavaScript 前端攻击。token 不能由前端生成&#xff0c;js 很容易被攻击者获取&#xff0c;从而伪造 token。同样其他重要的参数也不能由前端生成。 low 不修改输入&#xff0c;点击提交报错: 根据提示改成 success&#xff0c;还是报错&…

趣学python编程 (一、计算机基础知识科普)

未来是高度科技化和智能化的时代。过去不识字的叫“文盲”&#xff0c;如今不懂点计算机知识&#xff0c;则可能是新时代的“文盲”。不论从事什么行业&#xff0c;了解下计算机和编程都是有益的。Python 连续多年占据最受欢迎的编程语言榜首&#xff0c;未来Python有机会成为像…

C++之异常处理

目录 一、C语言处理错误 1、终止程序 2、返回错误码 二、C异常 异常的抛出和匹配原则 异常安全 异常规范 异常优缺点 一、C语言处理错误 传统处理错误的两种方式&#xff1a; 1、终止程序 使用assert是直接终止程序&#xff0c;包含头文件assert.h即可 缺点&#xf…

NEFTune: 通过简单的噪声提升指令精调效果

NEFTune指的是Noise Embedding Finetuning&#xff08;噪声嵌入精调&#xff09;&#xff0c;提出自论文&#xff1a;NEFTune: NOISY EMBEDDINGS IMPROVE INSTRUCTION FINETUNING。 NEFTune方法的原理仅使用一句话就可以描述清楚&#xff1a;在finetune过程的词向量中引入一些…

众安保险面试题

文章目录 1.说一下Java内存模型?2.List、Set、Map的区别?3.介绍一下设计模式?4.MySQL存储结构?5.索引失效的场景?6.为什么使用函数索引会失效?7.Spring事务有哪两种?7.1 编程式事务@RestController7.2 声明式事务8.@Transactional实现原理?9.事务如何合并@Transactiona…

es head 新增字段、修改字段、批量修改字段、删除字段、删除数据、批量删除数据

目录 一、新增字段 二、修改字段值 三、批量修改字段值 ​四、删除字段 五、删除数据/文档 六、批量删除数据/文档 一、新增字段 put http://{ip}:{port}/{index}/_mapping/{type} 其中&#xff0c;index是es索引、type是类型 数据&#xff1a; {"_doc"…

听GPT 讲Rust源代码--library/core/src(7)

题图来自 Hello, crustaceans.[1] File: rust/library/core/src/ptr/metadata.rs 在Rust的源代码中&#xff0c;rust/library/core/src/ptr/metadata.rs 文件的作用是定义了与指针&#xff08;ptr&#xff09;和元数据&#xff08;metadata&#xff09;相关的结构体和 trait&am…

C#源代码生成器深入讲解二

在阅读本文前需掌握源代码生成器相关知识C#源代码生成器深入讲解一 C#源代码生成器深入讲解二—增量生成器 源代码生成器有个非常大的弊病&#xff0c;每次都会遍历所有的语法树来分析,这样就有个问题&#xff0c;每次可能只修改了很少一部分或者只有很少一部分的代码需要分析…