0

0

Java编写小游戏教程:不贪吃蛇游戏

王林

王林

发布时间:2023-04-27 12:22:07

|

1247人浏览过

|

来源于亿速云

转载

    如何利用java编写个

    如何利用Java编写个

    代码

    蛇、药丸的抽象

    坐标 Point.java

    记录横纵坐标值。

    package cn.xeblog.snake.model;
    
    import java.util.Objects;
    
    /**
     * 坐标
     *
     * @author anlingyi
     * @date 2022/8/2 3:35 PM
     */
    public class Point {
    
        public int x;
    
        public int y;
    
        public Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Point point = (Point) o;
            return x == point.x && y == point.y;
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(x, y);
        }
    
        @Override
        public String toString() {
            return "Point{" +
                    "x=" + x +
                    ", y=" + y +
                    '}';
        }
    
    }

    移动方向 Direction.java

    立即学习Java免费学习笔记(深入)”;

    提供上、下、左、右四个移动方向的枚举。

    package cn.xeblog.snake.model;
    
    /**
     * @author anlingyi
     * @date 2022/8/2 5:25 PM
     */
    public enum Direction {
        UP,
        DOWN,
        LEFT,
        RIGHT
    }

    蛇 Snake.java

    存储蛇身坐标信息,提供蛇身移动、移除蛇尾坐标、获取蛇头、蛇尾坐标、蛇身长度等方法。

    Convai Technologies Inc.
    Convai Technologies Inc.

    对话式 AI API,用于设计游戏和支持端到端的语音交互

    下载

    这里讲一下蛇移动的实现原理:游戏开始时,会固定一个移动方向,蛇会一直朝着这个方向移动,我们可以通过方向键改变蛇的移动方向,蛇的移动其实就是将蛇身的坐标移动一下位置,比如蛇身长度(不包含蛇头)为6,移动时,只需将蛇身位置为5的坐标移到位置为6的坐标去,位置为4的坐标移动到位置为5的坐标去,简单来说就是将前一个的坐标换到它后面一个去,这是蛇身的移动,蛇头的移动需要单独计算,如果是上下方向移动,那就是对y坐标的加减操作,向上运动需要减一个蛇身的高度,向下则与之相反,需要加一个蛇身的高度,左右运动同理。

    package cn.xeblog.snake.model;
    
    import java.util.List;
    
    /**
     * 蛇
     *
     * @author anlingyi
     * @date 2022/8/2 3:32 PM
     */
    public class Snake {
    
        public static int width = 10;
    
        public static int height = 10;
    
        /**
         * 蛇身坐标列表
         */
        public List body;
    
        public Snake(List body) {
            this.body = body;
        }
    
        /**
         * 添加蛇身坐标
         *
         * @param x
         * @param y
         */
        public void add(int x, int y) {
            this.body.add(new Point(x * width, y * height));
        }
    
        /**
         * 移除蛇尾坐标
         */
        public void removeLast() {
            int size = size();
            if (size == 0) {
                return;
            }
    
            this.body.remove(size - 1);
        }
    
        /**
         * 获取蛇头坐标
         *
         * @return
         */
        public Point getHead() {
            if (size() > 0) {
                return this.body.get(0);
            }
    
            return null;
        }
    
        /**
         * 获取蛇尾坐标
         *
         * @return
         */
        public Point getTail() {
            int size = size();
            if (size > 0) {
                return this.body.get(size - 1);
            }
    
            return null;
        }
    
        /**
         * 蛇身长度
         *
         * @return
         */
        public int size() {
            return this.body.size();
        }
    
        /**
         * 蛇移动
         *
         * @param direction 移动方向
         */
        public void move(Direction direction) {
            if (size() == 0) {
                return;
            }
    
            for (int i = this.size() - 1; i > 0; i--) {
                // 从蛇尾开始向前移动
                Point point = this.body.get(i);
                Point nextPoint = this.body.get(i - 1);
                point.x = nextPoint.x;
                point.y = nextPoint.y;
            }
    
            // 蛇头移动
            Point head = getHead();
            switch (direction) {
                case UP:
                    head.y -= height;
                    break;
                case DOWN:
                    head.y += height;
                    break;
                case LEFT:
                    head.x -= width;
                    break;
                case RIGHT:
                    head.x += width;
                    break;
            }
        }
    
    }

    药丸 Pill.java

    存储“药丸“的坐标、类型信息。

    package cn.xeblog.snake.model;
    
    /**
     * 药丸
     *
     * @author anlingyi
     * @date 2022/8/2 4:49 PM
     */
    public class Pill {
    
        public static int width = 10;
    
        public static int height = 10;
    
        /**
         * 坐标
         */
        public Point point;
    
        /**
         * 药丸类型
         */
        public PillType pillType;
    
        public enum PillType {
            /**
             * 红色药丸
             */
            RED(5),
            /**
             * 蓝色药丸
             */
            BLUE(2),
            /**
             * 绿色药丸
             */
            GREEN(1),
            ;
    
            /**
             * 分数
             */
            public int score;
    
            PillType(int score) {
                this.score = score;
            }
        }
    
        public Pill(int x, int y, PillType pillType) {
            this.point = new Point(x * width, y * height);
            this.pillType = pillType;
        }
    
    }

    游戏界面

    初始化一些信息,比如游戏界面的宽高、定时器、一些状态标识(是否停止游戏、游戏是否胜利)、监听一些按键事件(空格键开始/暂停游戏、四个方向键控制蛇移动的方向),绘制游戏画面。

    当检测到游戏开始时,初始化蛇、“药丸”的位置信息,然后启动定时器每隔一段时间重新绘制游戏画面,让蛇可以动起来。

    当检测到蛇咬到自己或者是蛇撞墙时,游戏状态将会被标记为“游戏失败”,绘制游戏结束画面,并且定时器停止,如果蛇身为0,则游戏结束,游戏状态标记为“游戏胜利”。

    package cn.xeblog.snake.ui;
    
    import cn.xeblog.snake.model.Direction;
    import cn.xeblog.snake.model.Pill;
    import cn.xeblog.snake.model.Point;
    import cn.xeblog.snake.model.Snake;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Random;
    
    /**
     * @author anlingyi
     * @date 2022/8/2 3:51 PM
     */
    public class SnakeGameUI extends JPanel implements ActionListener {
    
        /**
         * 宽度
         */
        private int width;
    
        /**
         * 高度
         */
        private int height;
    
    
        /**
         * 蛇
         */
        private Snake snake;
    
        /**
         * 药丸
         */
        private Pill pill;
    
        /**
         * 移动方向
         */
        private Direction direction;
    
        /**
         * 停止游戏标记
         */
        private boolean stop;
    
        /**
         * 游戏状态 0.初始化 1.游戏胜利 2.游戏失败
         */
        private int state = -1;
    
        /**
         * 定时器
         */
        private Timer timer;
    
        /**
         * 移动速度
         */
        private int speed = 100;
    
        /**
         * 分数
         */
        private int score;
    
        /**
         * 特殊药丸列表
         */
        private ArrayList specialPill;
    
        public SnakeGameUI(int width, int height) {
            this.width = width;
            this.height = height;
            this.timer = new Timer(speed, this);
            this.stop = true;
    
            initPanel();
        }
    
        /**
         * 初始化
         */
        private void init() {
            this.score = 0;
            this.state = 0;
            this.stop = true;
            this.timer.setDelay(speed);
    
            initSnake();
            initPill();
            generatePill();
            repaint();
        }
    
        /**
         * 初始化游戏面板
         */
        private void initPanel() {
            this.setPreferredSize(new Dimension(this.width, this.height));
            this.addKeyListener(new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                    if (stop && e.getKeyCode() != KeyEvent.VK_SPACE) {
                        return;
                    }
    
                    switch (e.getKeyCode()) {
                        case KeyEvent.VK_UP:
                            if (direction == Direction.DOWN) {
                                break;
                            }
    
                            direction = Direction.UP;
                            break;
                        case KeyEvent.VK_DOWN:
                            if (direction == Direction.UP) {
                                break;
                            }
    
                            direction = Direction.DOWN;
                            break;
                        case KeyEvent.VK_LEFT:
                            if (direction == Direction.RIGHT) {
                                break;
                            }
    
                            direction = Direction.LEFT;
                            break;
                        case KeyEvent.VK_RIGHT:
                            if (direction == Direction.LEFT) {
                                break;
                            }
    
                            direction = Direction.RIGHT;
                            break;
                        case KeyEvent.VK_SPACE:
                            if (state != 0) {
                                init();
                            }
    
                            stop = !stop;
                            if (!stop) {
                                timer.start();
                            }
                            break;
                    }
                }
            });
        }
    
        /**
         * 初始化蛇
         */
        private void initSnake() {
            this.direction = Direction.LEFT;
            int maxX = this.width / Snake.width;
            int maxY = this.height / Snake.height;
    
            this.snake = new Snake(new ArrayList<>());
            this.snake.add(maxX - 2, 3);
            this.snake.add(maxX - 1, 3);
            this.snake.add(maxX - 1, 2);
            this.snake.add(maxX - 1, 1);
            for (int i = maxX - 1; i > 0; i--) {
                this.snake.add(i, 1);
            }
            for (int i = 1; i < maxY - 1; i++) {
                this.snake.add(1, i);
            }
            for (int i = 1; i < maxX - 1; i++) {
                this.snake.add(i, maxY - 2);
            }
        }
    
        /**
         * 初始化药丸
         */
        private void initPill() {
            this.specialPill = new ArrayList<>();
            for (int i = 0; i < 5; i++) {
                this.specialPill.add(Pill.PillType.RED);
            }
            for (int i = 0; i < 10; i++) {
                this.specialPill.add(Pill.PillType.BLUE);
            }
    
            Collections.shuffle(specialPill);
        }
    
        /**
         * 生成药丸
         */
        private void generatePill() {
            // 是否获取特殊药丸
            boolean getSpecialPill = new Random().nextInt(6) == 3;
            Pill.PillType pillType;
            if (getSpecialPill && this.specialPill.size() > 0) {
                // 生成特殊药丸
                int index = new Random().nextInt(this.specialPill.size());
                pillType = this.specialPill.get(index);
                this.specialPill.remove(index);
            } else {
                // 生成绿色药丸
                pillType = Pill.PillType.GREEN;
            }
    
            // 随机坐标
            int x = new Random().nextInt(this.width / Pill.width - 1);
            int y = new Random().nextInt(this.height / Pill.height - 1);
            this.pill = new Pill(x, y, pillType);
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
    
            Graphics2D g2 = (Graphics2D) g;
            g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    
            g2.setColor(new Color(66, 66, 66));
            g2.fillRect(0, 0, this.width, this.height);
    
            if (this.snake != null) {
                // 画蛇
                g2.setColor(new Color(255, 255, 255));
                for (int i = this.snake.size() - 1; i >= 0; i--) {
                    Point point = this.snake.body.get(i);
                    if (i == 0) {
                        // 蛇头
                        g2.setColor(new Color(255, 92, 92));
                    } else {
                        g2.setColor(new Color(215, 173, 173));
                    }
    
                    g2.fillRect(point.x, point.y, Snake.width, Snake.height);
                }
            }
    
            if (this.pill != null) {
                // 画药丸
                Color pillColor;
                switch (this.pill.pillType) {
                    case RED:
                        pillColor = new Color(255, 41, 41);
                        break;
                    case BLUE:
                        pillColor = new Color(20, 250, 243);
                        break;
                    default:
                        pillColor = new Color(97, 255, 113);
                        break;
                }
    
                g2.setColor(pillColor);
                g2.fillOval(pill.point.x, pill.point.y, Pill.width, Pill.height);
            }
    
            if (state > 0) {
                // 显示游戏结果
                String tips = "游戏失败!";
                if (state == 1) {
                    tips = "游戏胜利!";
                }
                g2.setFont(new Font("", Font.BOLD, 20));
                g2.setColor(new Color(208, 74, 74));
                g2.drawString(tips, this.width / 3, this.height / 3);
    
                g2.setFont(new Font("", Font.PLAIN, 18));
                g2.setColor(Color.WHITE);
                g2.drawString("得分:" + this.score, this.width / 2, this.height / 3 + 50);
            }
    
            if (stop) {
                g2.setFont(new Font("", Font.PLAIN, 18));
                g2.setColor(Color.WHITE);
                g2.drawString("按空格键开始/暂停游戏!", this.width / 4, this.height - 50);
            }
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            // 是否吃药
            boolean isAte = false;
            if (!this.stop) {
                // 移动蛇
                this.snake.move(this.direction);
                Point head = this.snake.getHead();
                if (head.equals(this.pill.point)) {
                    // 吃药了
                    isAte = true;
                    // 药丸分数
                    int getScore = this.pill.pillType.score;
                    // 累计分数
                    this.score += getScore;
                    for (int i = 0; i < getScore; i++) {
                        // 移除蛇尾
                        this.snake.removeLast();
                        if (this.snake.size() == 0) {
                            // 游戏胜利
                            this.state = 1;
                            this.stop = true;
                            break;
                        }
                    }
    
                    pill = null;
                    if (this.score % 10 == 0) {
                        int curSpeed = this.timer.getDelay();
                        if (curSpeed > 30) {
                            // 加速
                            this.timer.setDelay(curSpeed - 10);
                        }
                    }
                }
    
                if (state == 0) {
                    // 判断蛇有没有咬到自己或是撞墙
                    int maxWidth = this.width - this.snake.width;
                    int maxHeight = this.height - this.snake.height;
                    boolean isHitWall = head.x > maxWidth || head.x < 0 || head.y > maxHeight || head.y < 0;
                    boolean isBiting = false;
                    for (int i = this.snake.size() - 1; i > 0; i--) {
                        if (head.equals(this.snake.body.get(i))) {
                            isBiting = true;
                            break;
                        }
                    }
    
                    if (isHitWall || isBiting) {
                        // 游戏失败
                        this.state = 2;
                        this.stop = true;
                    }
                }
            }
    
            if (this.stop) {
                this.timer.stop();
            } else if (isAte) {
                // 重新生成药丸
                generatePill();
            }
    
            repaint();
        }
    
    }

    启动类

    游戏启动入口。

    package cn.xeblog.snake;
    
    import cn.xeblog.snake.ui.SnakeGameUI;
    
    import javax.swing.*;
    
    /**
     * 启动游戏
     *
     * @author anlingyi
     * @date 2022/8/2 3:41 PM
     */
    public class StartGame {
    
        public static void main(String[] args) {
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            frame.setVisible(true);
            frame.setResizable(false);
            frame.setTitle("不贪吃蛇");
            frame.setSize(400, 320);
            frame.setLocationRelativeTo(null);
            JPanel gamePanel = new SnakeGameUI(400, 300);
            frame.add(gamePanel);
            gamePanel.requestFocus();
        }
    
    }

    相关文章

    java速学教程(入门到精通)
    java速学教程(入门到精通)

    java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

    下载

    相关标签:

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

    相关专题

    更多
    Java 桌面应用开发(JavaFX 实战)
    Java 桌面应用开发(JavaFX 实战)

    本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

    61

    2026.01.14

    php与html混编教程大全
    php与html混编教程大全

    本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

    31

    2026.01.13

    PHP 高性能
    PHP 高性能

    本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

    72

    2026.01.13

    MySQL数据库报错常见问题及解决方法大全
    MySQL数据库报错常见问题及解决方法大全

    本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

    20

    2026.01.13

    PHP 文件上传
    PHP 文件上传

    本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

    21

    2026.01.13

    PHP缓存策略教程大全
    PHP缓存策略教程大全

    本专题整合了PHP缓存相关教程,阅读专题下面的文章了解更多详细内容。

    7

    2026.01.13

    jQuery 正则表达式相关教程
    jQuery 正则表达式相关教程

    本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

    4

    2026.01.13

    交互式图表和动态图表教程汇总
    交互式图表和动态图表教程汇总

    本专题整合了交互式图表和动态图表的相关内容,阅读专题下面的文章了解更多详细内容。

    49

    2026.01.13

    nginx配置文件详细教程
    nginx配置文件详细教程

    本专题整合了nginx配置文件相关教程详细汇总,阅读专题下面的文章了解更多详细内容。

    11

    2026.01.13

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    Kotlin 教程
    Kotlin 教程

    共23课时 | 2.5万人学习

    C# 教程
    C# 教程

    共94课时 | 6.7万人学习

    Java 教程
    Java 教程

    共578课时 | 45.8万人学习

    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号 技术交流群
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号