【使用java swing制作简易贪吃蛇游戏】软件实习项目二

一、项目准备

需求分析:
实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子,上下左右控制“蛇”的移动,吃到“豆子”以后“蛇”的身体加长一点,得分增加,“蛇”碰到边界或,蛇头与蛇身相撞,蛇死亡,游戏结束。为游戏设计初始欢迎界面,游戏界面,游戏结束界面。
编程语言及开发工具:
java 基于IDEA

二、实现过程

在屏幕区域内绘制出一条小蛇,并且在与蛇不重合的屏幕区域内随机出现一个食物,游戏者通过键盘操纵游戏小蛇上下左右移动来吃到食物,当食物成功被小蛇吃到后,会在另外的区域重新刷新出食物,而小蛇由于吃到食物,身体会增长。
在这里插入图片描述
具体情况详见代码及其注释。由于时间关系,我所做的贪吃蛇略去了拓展功能部分。

三、代码部分

Main类

package com.company;

import javax.swing.*;

public class Main {
    public static void main(String[] args) {
        // 创建窗口
        JFrame frame = new JFrame("贪吃蛇");
        // 固定窗口大小
        frame.setResizable(false);
        // 设置窗口出现位置和大小
        frame.setBounds(540,10,675,675);
        // 让窗口可关闭
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 添加游戏面板的组件
        frame.add(new GamePanel());
        // 设置窗口可见性
        frame.setVisible(true);
    }
}

DATA类

package com.company;

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

public class DATA {private static URL bodyURL = (Main.class.getResource("绿块.png"));
    private static ImageIcon body = new ImageIcon(bodyURL);
    private static ImageIcon food = new ImageIcon(Main.class.getResource("蛋.png"));

    private static ImageIcon up = new ImageIcon(Main.class.getResource("蛇向上.png"));
    private static ImageIcon down = new ImageIcon(Main.class.getResource("蛇向下.png"));
    private static ImageIcon left = new ImageIcon(Main.class.getResource("蛇向左.png"));
    private static ImageIcon right = new ImageIcon(Main.class.getResource("蛇向右.png"));

    public static ImageIcon getBody() {
        return body;
    }

    public static void setBody(ImageIcon body) {
        DATA.body = body;
    }

    public static ImageIcon getUp() {
        return up;
    }

    public static void setUp(ImageIcon up) {
        DATA.up = up;
    }

    public static ImageIcon getDown() {
        return down;
    }

    public static void setDown(ImageIcon down) {
        DATA.down = down;
    }

    public static ImageIcon getLeft() {
        return left;
    }

    public static void setLeft(ImageIcon left) {
        DATA.left = left;
    }

    public static ImageIcon getRight() {
        return right;
    }

    public static void setRight(ImageIcon right) {
        DATA.right = right;
    }

    public static ImageIcon getFood() {
        return food;
    }

    public static void setFood(ImageIcon food) {
        DATA.food = food;
    }
}

此部分用于存放游戏所需外部素材,例如蛇头、蛇身图片等。在这里插入图片描述

GamePanel类

package com.company;

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.Arrays;
import java.util.Random;

public class GamePanel extends JPanel implements KeyListener, ActionListener {
    // 设置蛇头的方向
    String snakeHead;
    // 蛇的长度
    int length;
    int[] snakeX;
    int[] snakeY;
    // 游戏状态:开始=true - 停止=false
    boolean isStart = false;
    // 定时器:第一个参数就是定时执行时间
    Timer timer = new Timer(170, this);
    // 食物
    int foodX;
    int foodY;
    // 让食物出现的位置随机
    Random random = new Random();
    // 游戏是否结束:结束为=true - 游戏中=false
    boolean isFail = false;
    // 游戏是否胜利:胜利为true - 没胜利为false
    boolean isVictory = false;
    // 游戏分数
    int score;

    public GamePanel() {
        // 初始化面板
        init();
        // 设置焦点事件
        this.setFocusable(true);
        // 给面板添加键盘监听事件
        this.addKeyListener(this);
        timer.start();
    }

    public void init() {
        // 初始化蛇头向右
        snakeHead = "right";
        // 初始化蛇有三节,包括小脑袋
        length = 3;
        snakeX = new int[1000];
        snakeY = new int[1000];
        snakeX[0] = 75;
        snakeY[0] = 75;
        snakeX[1] = 50;
        snakeY[1] = 75;
        snakeX[2] = 25;
        snakeY[2] = 75;
        // 初始化实物数据
        foodX = 75 + 25 * random.nextInt(21);
        foodY = 75 + 25 * random.nextInt(19);
        // 让生成的食物不会和蛇重合
        for (int i = 0; i < length; i++) {
            if (foodX == snakeX[i] && foodY == snakeY[i]) {
                foodX = 75 + 25 * random.nextInt(21);
                foodY = 100 + 25 * random.nextInt(19);
                i = 0;
            }
        }

        // 初始化游戏分数
        score = 0;
    }

    // 画组件
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 设置面板背景色
        this.setBackground(Color.white);
        // 绘制游戏区域
        g.fillRect(25, 50, 600, 575);
        // 绘制蛇头
        if (snakeHead.equals("up")) {
            DATA.getUp().paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (snakeHead.equals("down")) {
            DATA.getDown().paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (snakeHead.equals("left")) {
            DATA.getLeft().paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (snakeHead.equals("right")) {
            DATA.getRight().paintIcon(this, g, snakeX[0], snakeY[0]);
        }
        // 绘制蛇的身体
        for (int i = 1; i < length; i++) {
            DATA.getBody().paintIcon(this, g, snakeX[i], snakeY[i]);
        }
        // 画食物
        DATA.getFood().paintIcon(this, g, foodX, foodY);
        // 绘制局内游戏信息
        g.setColor(Color.black);
        g.setFont(new Font("仿宋", Font.BOLD, 15));
        g.drawString("长度:" + length, 25, 20);
        g.drawString("分数:" + score, 25, 40);
        // 绘制游戏暂停时的 提示信息
        if (!isStart) {
            g.setColor(Color.white);
            g.setFont(new Font("仿宋", Font.BOLD, 40));
            g.drawString("按下空格开始游戏!", 125, 300);
        }
        // 绘制游戏失败时的 提示信息
        if (isFail) {
            g.setColor(Color.red);
            g.setFont(new Font("仿宋", Font.BOLD, 40));
            g.drawString("失败,按下空格重新开始", 125, 300);
        }
        // 绘制游戏胜利时的 提示信息

        if (isVictory) {
            g.setColor(Color.red);
            g.setFont(new Font("宋体", Font.BOLD, 35));
            g.drawString("胜利,你是为数不多的天才", 125, 300);
            g.drawString("按下空格重新开始新一轮游戏", 100, 350);
        }
    }

    // 键盘监听事件,某个键按下执行方法
    @Override
    public void keyPressed(KeyEvent e) {
        /*
            当用户按下空格时:先判断游戏有没有结束,
            如果游戏结束那么就重新开始
            如果游戏没有结束那么就继续原来的游戏
         */
        if (e.getKeyCode() == KeyEvent.VK_SPACE) {
            if (isFail || isVictory) {
                isFail = false;
                isVictory = false;
                init();
            } else {
                isStart = !isStart;
            }
            repaint();
        }
        // 让用户用键盘的上下左右键来操作蛇头,
        // 并且让蛇不能直接回头,当蛇在往上走,那么就不能立刻往下走
        if (e.getKeyCode() == KeyEvent.VK_UP) {
            snakeHead = snakeHead.equals("down") ? "down" : "up";
        } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            snakeHead = snakeHead.equals("up") ? "up" : "down";
        } else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
            snakeHead = snakeHead.equals("right") ? "right" : "left";
        } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
            snakeHead = snakeHead.equals("left") ? "left" : "right";
        }
    }

    // 定时执行的操作
    @Override
    public void actionPerformed(ActionEvent e) {
        // 如果游戏处于开始状态,并且没有结束,则小蛇可以移动
        if (isStart && !isFail && !isVictory) {
            // 身体移动:右移:即让后一个移到前一个的位置即可!
            for (int i = length - 1; i > 0; i--) {
                snakeX[i] = snakeX[i - 1];
                snakeY[i] = snakeY[i - 1];
            }
            //  头部移动,通过方向控制,;
            if (snakeHead.equals("right")) {
                snakeX[0] = snakeX[0] + 25;
                if (snakeX[0] > 600) snakeX[0] = 25;
            } else if (snakeHead.equals("left")) {
                snakeX[0] = snakeX[0] - 25;
                if (snakeX[0] < 25) snakeX[0] = 600;
            } else if (snakeHead.equals("up")) {
                snakeY[0] = snakeY[0] - 25;
                if (snakeY[0] < 50) snakeY[0] = 600;
            } else if (snakeHead.equals("down")) {
                snakeY[0] = snakeY[0] + 25;
                if (snakeY[0] > 600) snakeY[0] = 50;
            }
            // 吃食物:当蛇头和食物的坐标一致时,算吃到食物
            if (snakeX[0] == foodX && snakeY[0] == foodY) {
                length++;
                // 每吃一个食物,增加10积分
                score = score + 10;
                // 长度等于300,游戏获胜
                // 当length到达一定的值,蛇移动的速度就变快
                if (length == 300) {
                    isVictory = true;
                } else if (length == 25) {
                    timer = new Timer(145, this);
                } else if (length == 50) {
                    timer = new Timer(125, this);
                } else if (length == 100) {
                    timer = new Timer(100, this);
                } else if (length == 200) {
                    timer = new Timer(70, this);
                }
                // 重新生成食物
                foodX = 75 + 25 * random.nextInt(21);
                foodY = 75 + 25 * random.nextInt(19);
                // 让生成的食物不会和蛇重合
                for (int i = 0; i < length; i++) {
                    if (foodX == snakeX[i] && foodY == snakeY[i]) {
                        foodX = 75 + 25 * random.nextInt(21);
                        foodY = 75 + 25 * random.nextInt(19);
                        i = 0;
                    }
                }
            }
            // 结束判断,头和身体的坐标一致时,游戏结束
            for (int i = 2; i < length; i++) {
                if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
                    System.out.println(Arrays.toString(snakeX));
                    System.out.println(Arrays.toString(snakeY));
                    timer.setDelay(170);//死亡重置定时器
                    isFail = true;
                }
            }
            // 需要不断的更新页面实现动画
            repaint();
        }
        // 让时间动起来!
        timer.start();
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

}

游戏面板类,包含各种操作功能,是游戏的主要模块。

四、程序演示

界面:

在这里插入图片描述

功能介绍:

一、蛇初始长度为三,按下空格后开始游戏,默认向右移动。
二、蛇越过边界后会从另一边的边界返回游戏区域。当蛇头触碰到蛇身时,游戏结束。
三、按下空格暂停、继续游戏。
四、当蛇身长度分别为达到、十、十五、二十时,蛇的移动速度都会增加,上限约为初始速度的3倍,死亡后速度重置。当长度达到30时,默认玩家达成游戏胜利。

遇到的问题:

如图
在这里插入图片描述
当蛇吃到食物的瞬间,长度并未增长,同时界面左上角固定出现一瞬间的身体方块。推测是画笔模块每次渲染间隔的原因。由于快要考试,没有时间修改,先挖个坑以后再说。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个基础版的贪吃游戏的代码,使用Java Swing编写,其中包括游戏面板、的移动控制、食物的生成等功能。你可以在此基础上进行改进,添加更多的功能。 ```java import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.LinkedList; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.Timer; public class SnakeGame extends JPanel implements ActionListener, KeyListener { private static final long serialVersionUID = 1L; private static final int WIDTH = 500; private static final int HEIGHT = 500; private static final int SIZE = 10; private static final int MAX_LENGTH = (WIDTH / SIZE) * (HEIGHT / SIZE) - 1; private static final int DELAY = 100; private static final int UP = 0, DOWN = 1, LEFT = 2, RIGHT = 3; private LinkedList<Point> snake; private Point food; private int direction; private boolean gameOver; private Timer timer; private Random random; public SnakeGame() { setPreferredSize(new Dimension(WIDTH, HEIGHT)); setBackground(Color.BLACK); setFocusable(true); addKeyListener(this); snake = new LinkedList<Point>(); snake.add(new Point(WIDTH / 2, HEIGHT / 2)); food = new Point(); random = new Random(); newFood(); direction = -1; gameOver = false; timer = new Timer(DELAY, this); timer.start(); } public static void main(String[] args) { JFrame frame = new JFrame("Snake Game"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setResizable(false); frame.add(new SnakeGame()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); if (gameOver) { g.setColor(Color.WHITE); g.drawString("Game Over", WIDTH / 2 - 25, HEIGHT / 2); return; } g.setColor(Color.RED); g.fillOval(food.x, food.y, SIZE, SIZE); g.setColor(Color.GREEN); for (Point p : snake) { g.fillOval(p.x, p.y, SIZE, SIZE); } } @Override public void actionPerformed(ActionEvent e) { if (gameOver) { return; } move(); checkCollision(); checkFood(); repaint(); } private void move() { Point head = snake.getFirst(); Point next = new Point(); switch (direction) { case UP: next.setLocation(head.x, head.y - SIZE); break; case DOWN: next.setLocation(head.x, head.y + SIZE); break; case LEFT: next.setLocation(head.x - SIZE, head.y); break; case RIGHT: next.setLocation(head.x + SIZE, head.y); break; } snake.addFirst(next); snake.removeLast(); } private void checkCollision() { Point head = snake.getFirst(); if (head.x < 0 || head.x >= WIDTH || head.y < 0 || head.y >= HEIGHT) { gameOver = true; return; } for (Point p : snake.subList(1, snake.size())) { if (head.equals(p)) { gameOver = true; return; } } } private void checkFood() { if (snake.getFirst().equals(food)) { newFood(); if (snake.size() == MAX_LENGTH) { gameOver = true; return; } } else { snake.removeLast(); } } private void newFood() { int x = random.nextInt(WIDTH / SIZE) * SIZE; int y = random.nextInt(HEIGHT / SIZE) * SIZE; food.setLocation(x, y); for (Point p : snake) { if (food.equals(p)) { newFood(); return; } } } @Override public void keyPressed(KeyEvent e) { int code = e.getKeyCode(); if (code == KeyEvent.VK_UP && direction != DOWN) { direction = UP; } else if (code == KeyEvent.VK_DOWN && direction != UP) { direction = DOWN; } else if (code == KeyEvent.VK_LEFT && direction != RIGHT) { direction = LEFT; } else if (code == KeyEvent.VK_RIGHT && direction != LEFT) { direction = RIGHT; } } @Override public void keyTyped(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值