贪吃蛇游戏(java)(全注释)

没想到发的第一篇关于java的博客会是这个,写作业用来练手,顺道就搬上来了。

代码肯定不最优的,欢迎大家一起来探讨~

先搬个效果图~

然后结构~

        一共分成4个部分,Define包下有蛇,食物和成绩数据的类,主要包括他们的初始化和像蛇的移动之类的东西;SetWindow包里是主函数的入口,包括窗口和面板的建立过程代码;RunPanel是游戏面板 ,大部分内容都在这个类里,最后是Resource包,包括图片的导入加载。

思路分析~

1、框架搭建,这是我一开始搞的,后面直接代码里小修改,做一件事总是要先规划规划怎么做

2、构建流程,当然,实际写代码时候我可没整这玩意,脑子里知道该做什么就好

之后就是源码~

窗体(游戏界面)MainScene:

package Game.SetWindow;

import Game.RunPanel;
import javax.swing.*;

public class MainScene extends JPanel{
    //
    public static void main(String[] args) {
        //定义类
        InterFace initwindow = new InterFace();
        //建立基础界面
        initwindow.InitWindow();
        //建立游戏面板
        initwindow.add(new RunPanel());
    }
    //内部类
    static class InterFace extends JFrame {
        //界面初始化函数
        public void InitWindow() {
            setTitle("贪吃蛇游戏           ——Woodenman杜");    //标题
            setBounds(0, 0, 820, 820);      //界面大小设定
            setResizable(false);    //设定大小不可改变
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);     //设定界面可关闭
            setLocationRelativeTo(null);    //设置屏幕中央打开
            setVisible(true);   //界面显示
        }
    }
}

 图片加载A_LoadImg:

加了个A就是单纯为了让它排到最前面,其实在Game包下建个类导入可能更好看一点

package Resource;

import java.awt.*;

public class A_LoadImg {
    //游戏标题
    public static Image logo = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Logo.jpg"));
    public static Image gamename = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Gname.jpg"));
    //四个方向的蛇头
    public static Image upsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/UpSnake.jpg"));
    public static Image downsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/DownSnake.jpg"));
    public static Image rightsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/RightSnake.jpg"));
    public static Image leftsnake = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/LeftSnake.jpg"));
    //蛇身
    public static Image body = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Body.jpg"));
    //食物
    public static Image food = Toolkit.getDefaultToolkit().getImage(A_LoadImg.class.getResource("/Resource/Food.jpg"));
}

 蛇对象Snake:

package Game.Define;

public class Snake {
    public int length; //蛇长
    public int x[] = new int[60];    //蛇的x坐标
    public int y[] = new int[60];    //蛇的y坐标
    public char dir;    //蛇的移动方向
    //游戏状态
        // 0未开始
        // 1结束
        // 2暂停
        // 3进行中
        // 5选择等级
        // 6通关
    public byte over;

    public Snake() {
        init();
    }
    //蛇的初始化
    public void init(){
        length = 4;
        dir = 'R';
        over = 0;
        x[0] = 30+125; y[0] = 140+100;
        x[1] = 30+100; y[1] = 140+100;
        x[2] = 30+75; y[2] = 140+100;
        x[3] = 30+50; y[3] = 140+100;
    }

    //蛇的移动和边界检测
    public void go(){
        //蛇身移动
        for(int i = length-1; i > 0; i--){
            x[i] = x[i-1];
            y[i] = y[i-1];
        }
        //蛇头移动
        if(dir == 'L')
        {
            x[0] -= 25;
            if(x[0] < 30) over = 1;
        }
        else if(dir == 'R')
        {
            x[0] += 25;
            if(x[0] > 755) over = 1;
        }
        else if(dir == 'U')
        {
            y[0] -= 25;
            if(y[0] < 140) over = 1;
        }
        else if(dir == 'D')
        {
            y[0] += 25;
            if(y[0] > 740) over = 1;
        }
    }

}

食物Food:

package Game.Define;

import java.util.Random;

public class Food {
    //食物坐标
    public int x;
    public int y;
    //随机数
    Random random = new Random();
    //构造体
    public Food() {
        init();
    }
    //建立新的食物点
    public void set(){
        x = 30 + 25*random.nextInt(30);
        y = 140 + 25*random.nextInt(25);
    }
    //食物点初始化
    public void init(){
        x = 30 + 175;
        y = 140 + 175;
    }
}

 成绩数据Score:

package Game.Define;
public class Score{
    public int result;  //游戏得分
    public int grade;   //游戏难度
    public int PeopleGrade;     //人工设定的游戏难度
    //构造函数
    public Score() {
        init();
    }
    //数据初始化
    public void init(){
        result = 0;
        PeopleGrade = 0;
        grade = 1;
    }
    //等级判定
    public int graded(int length){
        return (length - 4) / 5 + 1;
    }

    //帧率判定(蛇的移动速度)
    public int speed(int length){ return 250 - (length - 4) * 5; }
}

 最后就是重头戏——游戏面板:

        稍微说一下吧,首先对象需要画出来->画笔,键盘操控->键盘监听,实质是高帧率刷新->定时器

结构上

首先所有的定义,定时器对象,内容对象等等

然后定时器,包括:游戏状态检测,是暂停了,选难度,还是游戏进行中;有没有吃到食物的判定;蛇是否碰到自身;界面刷新

之后键盘监听,顾名思义,就是所有会用到的按键识别,包括游戏状态、游戏难度、游戏操控的读入

最后画笔,包括基础背景界面,游戏界面的对象,各种内容提示的绘制

package Game;

import Game.Define.Food;
import Game.Define.Score;
import Game.Define.Snake;
import Resource.A_LoadImg;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class RunPanel extends JPanel implements ActionListener , KeyListener {
    //构造函数
    public RunPanel() {
        //定时器启动
        timer.start();
        //键盘监听
        this.setFocusable(true);
        this.addKeyListener(this);
    }
    //定义
    Snake snake = new Snake(); //snake
    Food food = new Food(); //food
    Score score = new Score();  //计分
    int delay = 250;
    boolean ans = false;
    Timer timer = new Timer(250,this);  //定时器
//定时器
    @Override
    public void actionPerformed(ActionEvent e) {
        //是否为进行状态
        if(snake.over == 3)  snake.go();
        if(score.PeopleGrade != 0){
            delay = 250 - score.PeopleGrade*25;
            score.grade = score.PeopleGrade;
            timer.setDelay(delay);
        }
        //增长检测
        if(snake.x[0] == food.x && snake.y[0]== food.y){
            snake.length++; //长度更新
            if(snake.length == 54) { snake.over = 6; } //通关判定
            food.set(); //食物点更新
            score.result += 1;  //得分更新

            //非人工选定难度状态下更新数据
            if(score.PeopleGrade == 0)
            {
                delay = score.speed(snake.length) > 30 ? score.speed(snake.length) : 25;    //帧率更新
                score.grade = score.graded(snake.length); //等级更新
                timer.setDelay(delay);
            }
        }
        //碰撞检测
                for(int i = 1; i < snake.length; i++){
                    if(snake.y[0] == snake.y[i] && snake.x[0] == snake.x[i]) snake.over = 1;
                }
        //界面刷新
        repaint();
        timer.start();
    }

//键盘监听
    @Override
    public void keyPressed(KeyEvent e) {
        //进入游戏状态
        if(e.getKeyCode() == KeyEvent.VK_ENTER){
            if(snake.over == 0) {
                snake.over = 3; //初始到进行
                //snake.init();
            }
            else if(snake.over == 1 || snake.over == 2){
                snake.over = 0; //结束到初始
            }
            else if(snake.over == 3) snake.over = 0;   //重置到初始状态
        }
        else if(e.getKeyCode() == KeyEvent.VK_SPACE){
            //暂停或者进行状态转换
            if(snake.over == 2) snake.over = 3;
            else if(snake.over == 3) snake.over = 2;
        }
        else if(e.getKeyCode() == KeyEvent.VK_G && snake.over == 0){
            snake.over = 5;
            ans = true;
        }
        //难度控制
        else if(e.getKeyCode() == KeyEvent.VK_1 && ans ){ score.PeopleGrade = 1; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_2 && ans ){ score.PeopleGrade = 2; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_2 && ans ){ score.PeopleGrade = 2; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_3 && ans ){ score.PeopleGrade = 3; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_4 && ans ){ score.PeopleGrade = 4; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_5 && ans ){ score.PeopleGrade = 5; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_6 && ans ){ score.PeopleGrade = 6; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_7 && ans ){ score.PeopleGrade = 7; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_8 && ans ){ score.PeopleGrade = 8; snake.over = 3; ans = false; }
        else if(e.getKeyCode() == KeyEvent.VK_9 && ans ){ score.PeopleGrade = 9; snake.over = 3; ans = false; }
        //方向控制
        else if(e.getKeyCode() == KeyEvent.VK_DOWN){
            if(snake.dir == 'U') snake.over = 1; else snake.dir = 'D';
        }else if(e.getKeyCode() == KeyEvent.VK_UP){
            if(snake.dir == 'D') snake.over = 1; else snake.dir = 'U';
        }else if(e.getKeyCode() == KeyEvent.VK_LEFT){
            if(snake.dir == 'R') snake.over = 1; else snake.dir = 'L';
        }else if(e.getKeyCode() == KeyEvent.VK_RIGHT){
            if(snake.dir == 'L') snake.over = 1; else snake.dir = 'R';
        }
    }
 //绘画方法重写
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        //设置基础界面的颜色
        setBackground(Color.orange);
        //载入游戏标题图片
        g.drawImage(A_LoadImg.logo,30,20,160,120,this);
        g.drawImage(A_LoadImg.gamename, 190,20,420,120,this);
        //画出游戏区域
        g.setColor(Color.DARK_GRAY);
        g.fillRect(30,140,750,625);
        g.setColor(Color.GREEN);
        g.drawRect(30,140,750,625);
        //计分区域
        g.setColor(Color.WHITE);
        g.setFont(new Font("隶书",Font.BOLD,25));
        g.drawString("长度" + snake.length,620,50);
        g.setColor(Color.WHITE);
        g.setFont(new Font("隶书",Font.BOLD,25));
        g.drawString("得分" + score.result, 620,90);
        g.setColor(Color.WHITE);
        g.setFont(new Font("隶书",Font.BOLD,25));
        g.drawString("游戏等级" + score.grade,620 ,130);
        //绘制蛇
        switch(snake.dir)
        {
            case 'L':
                g.drawImage(A_LoadImg.leftsnake ,snake.x[0], snake.y[0], 25 ,25,this);
                break;
            case 'R':
                g.drawImage(A_LoadImg.rightsnake ,snake.x[0], snake.y[0], 25 ,25,this);
                break;
            case 'U':
                g.drawImage(A_LoadImg.upsnake ,snake.x[0], snake.y[0], 25 ,25,this);
                break;
            case 'D':
                g.drawImage(A_LoadImg.downsnake ,snake.x[0], snake.y[0], 25 ,25,this);
                break;
        }
        for (int i = 1; i < snake.length; i++) {
            g.drawImage(A_LoadImg.body, snake.x[i], snake.y[i],25,25,this);
        }
        //绘制食物
        g.drawImage(A_LoadImg.food, food.x, food.y, 25,25,this);

        //游戏状态判断
        // 0未开始 1结束 2暂停 3进行中 5选择等级 6通关
        if(snake.over == 0){
            //刷新界面
            repaint();
            //初始化
            snake.init();
            food.init();
            score.init();
            //显示设置
            g.setColor(Color.WHITE);
            g.setFont(new Font("华文彩云",Font.BOLD,70));
            g.drawString("欢迎来到贪吃蛇游戏",70,400);
            g.setColor(Color.CYAN);
            g.setFont(new Font("楷书",Font.BOLD,30));
            g.drawString("Enter       开始/重置游戏",250,480);
            g.drawString("Space     暂停/继续游戏",250,530);
            g.drawString("g              选择游戏等级",250,580);
            g.drawString("箭头控制小蛇移动,长度54就~通关",200,670);

        }
        if(snake.over == 1){
            g.setColor(Color.RED);
            g.setFont(new Font("隶书",Font.BOLD,70));
            g.drawString("Game Over!", 200,400);
        }
        else if(snake.over == 2){
            g.setColor(Color.WHITE);
            g.setFont(new Font("隶书",Font.BOLD,50));
            g.drawString("游戏暂停,按下空格继续游戏",70,400);
        }
        if(snake.over == 5){
            g.setColor(Color.orange);
            g.setFont(new Font("隶书",Font.BOLD,50));
            g.drawString("请选择游戏难度(1-9)",150,400);

        }
        if(snake.over == 6){
            g.setColor(Color.red);
            g.setFont(new Font("隶书",Font.BOLD,50));
            g.drawString("恭喜你,游戏胜利!!!",150,400);
        }
        //repaint();
    }


    @Override public void keyTyped(KeyEvent e) {}     @Override public void keyReleased(KeyEvent e) {}
}

 我只是把这个类分开放了,代码原封不动。

  这个的核心就是画笔(画图片),键盘监听,定时器,这三个搞定了也就写出来了,定时器用的是swing下的,util的我写一半卡住了,键盘监听写一半也卡住了...........所以,继续学习哈哈

  • 14
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
非常感谢您的提问,我可以为您提供一个简单的Java贪吃蛇小游戏的代码,并附上注释,代码如下: ``` import java.awt.*; import java.awt.event.*; import javax.swing.*; public class SnakeGame extends JFrame implements ActionListener { private static final long serialVersionUID = 1L; private final int WIDTH = 300; // 游戏窗口的宽度 private final int HEIGHT = 300; // 游戏窗口的高度 private final int DOT_SIZE = 10; // 蛇身的大小 private final int ALL_DOTS = 900; // 游戏区域最多能容纳的蛇身数量 private final int RAND_POS = 29; // 食物出现的位置范围 private final int DELAY = 140; // 游戏速度,单位为毫秒 private int x[] = new int[ALL_DOTS]; // 蛇身的横坐标 private int y[] = new int[ALL_DOTS]; // 蛇身的纵坐标 private int dots; // 蛇身的数量 private int apple_x; // 食物的横坐标 private int apple_y; // 食物的纵坐标 private Timer timer; // 游戏计时器 private boolean leftDirection = false; // 蛇是否向左移动 private boolean rightDirection = true; // 蛇是否向右移动 private boolean upDirection = false; // 蛇是否向上移动 private boolean downDirection = false; // 蛇是否向下移动 private boolean inGame = true; // 游戏是否结束 public SnakeGame() { initGame(); } private void initGame() { // 初始化蛇身 dots = 3; for (int i = 0; i < dots; i++) { x[i] = 50 - i * DOT_SIZE; y[i] = 50; } // 初始化食物 locateApple(); // 初始化游戏窗口 setTitle("贪吃蛇小游戏"); setSize(WIDTH, HEIGHT); setResizable(false); setDefaultCloseOperation(EXIT_ON_CLOSE); // 添加键盘监听器 addKeyListener(new TAdapter()); // 初始化游戏计时器 timer = new Timer(DELAY, this); timer.start(); } private void locateApple() { // 随机生成食物的位置 int r = (int) (Math.random() * RAND_POS); apple_x = r * DOT_SIZE; r = (int) (Math.random() * RAND_POS); apple_y = r * DOT_SIZE; } private void checkApple() { // 检查蛇是否吃到了食物 if ((x[0] == apple_x) && (y[0] == apple_y)) { dots++; locateApple(); } } private void checkCollision() { // 检查蛇是否碰到了游戏区域的边缘或自己的身体 for (int i = dots; i > 0; i--) { if ((i > 4) && (x[0] == x[i]) && (y[0] == y[i])) { inGame = false; } } if (y[0] >= HEIGHT) { inGame = false; } if (y[0] < 0) { inGame = false; } if (x[0] >= WIDTH) { inGame = false; } if (x[0] < 0) { inGame = false; } if (!inGame) { timer.stop(); } } private void move() { // 移动蛇身 for (int i = dots; i > 0; i--) { x[i] = x[(i - 1)]; y[i] = y[(i - 1)]; } if (leftDirection) { x[0] -= DOT_SIZE; } if (rightDirection) { x[0] += DOT_SIZE; } if (upDirection) { y[0] -= DOT_SIZE; } if (downDirection) { y[0] += DOT_SIZE; } } private void doDrawing(Graphics g) { // 绘制游戏区域 if (inGame) { g.setColor(Color.red); g.fillOval(apple_x, apple_y, DOT_SIZE, DOT_SIZE); for (int i = 0; i < dots; i++) { if (i == 0) { g.setColor(Color.green); g.fillRect(x[i], y[i], DOT_SIZE, DOT_SIZE); } else { g.setColor(Color.blue); g.fillRect(x[i], y[i], DOT_SIZE, DOT_SIZE); } } Toolkit.getDefaultToolkit().sync(); } else { gameOver(g); } } private void gameOver(Graphics g) { // 游戏结束 String msg = "Game Over"; Font small = new Font("Helvetica", Font.BOLD, 14); FontMetrics metr = getFontMetrics(small); g.setColor(Color.black); g.setFont(small); g.drawString(msg, (WIDTH - metr.stringWidth(msg)) / 2, HEIGHT / 2); } @Override public void actionPerformed(ActionEvent e) { // 游戏计时器触发事件 if (inGame) { checkApple(); checkCollision(); move(); } repaint(); } private class TAdapter extends KeyAdapter { // 键盘监听器 @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) { leftDirection = true; upDirection = false; downDirection = false; } if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) { rightDirection = true; upDirection = false; downDirection = false; } if ((key == KeyEvent.VK_UP) && (!downDirection)) { upDirection = true; leftDirection = false; rightDirection = false; } if ((key == KeyEvent.VK_DOWN) && (!upDirection)) { downDirection = true; leftDirection = false; rightDirection = false; } } } public static void main(String[] args) { // 启动游戏 EventQueue.invokeLater(() -> { SnakeGame ex = new SnakeGame(); ex.setVisible(true); }); } } ``` 希望这个代码能够帮助到您,如果您有任何问题或需要进一步的帮助,请随时联系我。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

UmVfX1BvaW50

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

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

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

打赏作者

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

抵扣说明:

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

余额充值