java实现贪吃蛇小游戏

前言

本文主要是记录一下我自己之前学习java的时候写的一个java中GUI小程序,代码可能比较简陋,但对于初学者小白学习应该够用了。很多初学者觉得GUI没必要学习,但是做一点GUI小项目练手更能了解java的面向对象思想。因我的水平有限,若有不足之处请评论留言,谢谢。

开发环境

本程序是在jdk1.8和idea环境开发的,因为我的电脑分辨率是2.5K,因此显示大小可能与你们下载不同,窗口大小需要根据自身修改!

项目结构图

因为是我写这篇随笔2年前的代码所以多多少少不太规范,我也懒得重构。

Snake类代码

package snake;

import com.google.gson.Gson;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.Writer;

/**
 * @author Tireless
 */
public class Snake {
    public static void main(String[] args) {
        //利用JFrame创建窗体
        JFrame frame = new JFrame();
        Container conn = frame.getContentPane();
        conn.setLayout(null);

        //黑色画布大小及坐标
        SnakePanel panel = new SnakePanel();
        panel.setBounds(0, 0, 900, 730);


        JButton btnSave = new JButton("保存");

        //按钮大小及坐标
        btnSave.setBounds(300, 680, 100, 30);
        JButton btnLoad = new JButton("加载存档");

        btnLoad.setBounds(500, 680, 100, 30);
        conn.add(panel);
        conn.add(btnLoad);
        conn.add(btnSave);

        //窗体坐标大小
        frame.setBounds(200, 200, 900, 760);
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        btnSave.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                SnakeInfo si = new SnakeInfo();
                si.setDirection(panel.direction);
                si.setSnakex(panel.snakex);
                si.setSnakey(panel.snakey);
                si.setLen(panel.len);
                si.setFoodx(panel.foodx);
                si.setFoody(panel.foody);
                si.setScore(panel.score);
//                序列化对象
                Gson gson = new Gson();
                String snakeStr = gson.toJson(si);
                try (Writer writer = new FileWriter("a.txt")) {
                    writer.write(snakeStr);
                    writer.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        });
        /*
         * 调用接口定义Save按钮方法,用于响应按下后保存游戏数据
         * */
        btnLoad.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    InputStream is = new FileInputStream("a.txt");
                    int ia = is.available();
                    byte[] bytes = new byte[ia];
                    is.read(bytes);
                    String snakeStr = new String(bytes);
                    Gson gson = new Gson();
                    SnakeInfo si = gson.fromJson(snakeStr, SnakeInfo.class);
                    panel.direction = si.getDirection();
                    panel.snakey = si.getSnakey();
                    panel.snakex = si.getSnakex();
                    panel.score = si.getScore();
                    panel.len = si.getLen();
                    panel.foody = si.getFoody();
                    panel.foodx = si.getFoodx();
                    is.close();
                    panel.repaint();
                    panel.setFocusable(true);
                    panel.addKeyListener(panel);
                    panel.requestFocus();

                } catch (Exception e1) {
                    e1.printStackTrace();
                }

            }
        });
    }
}

SnaleInfo代码

package snake;

/**
 * @author Tireless
 */
public class SnakeInfo {
    private int len;
    private int score;
    private int[] snakex;
    private int[] snakey;
    private int foodx;
    private int foody;
    private String direction;
/**
 * 以下是get set获取方法
 */

    public void setLen(int len) {
        this.len = len;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public void setSnakex(int[] snakex) {
        this.snakex = snakex;
    }

    public void setSnakey(int[] snakey) {
        this.snakey = snakey;
    }

    public void setFoodx(int foodx) {
        this.foodx = foodx;
    }

    public void setFoody(int foody) {
        this.foody = foody;
    }

    public void setDirection(String direction) {
        this.direction = direction;
    }

    public int getLen() {
        return len;
    }

    public int getScore() {
        return score;
    }

    public int[] getSnakex() {
        return snakex;
    }

    public int[] getSnakey() {
        return snakey;
    }
    public int getFoodx() {
        return foodx;
    }

    public int getFoody() {
        return foody;
    }

    public String getDirection() {
        return direction;
    }
}

SnakePanel代码

package snake;

import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.swing.*;
import java.awt.*;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.util.Random;

/**
 * @author Tireless
 */
public class SnakePanel extends JPanel implements KeyListener, ActionListener {
    ImageIcon up = new ImageIcon("up.png");
    ImageIcon down = new ImageIcon("down.png");
    ImageIcon food = new ImageIcon("food.png");
    ImageIcon left = new ImageIcon("left.png");
    ImageIcon body = new ImageIcon("body.png");
    ImageIcon right = new ImageIcon("right.png");
    ImageIcon title = new ImageIcon("title.jpg");//导入素材
    /*
    定义变量
    */
//蛇身坐标
    int[] snakex = new int[700];
    int[] snakey = new int[700];
    int len = 3;//蛇身长度
    int score = 0;//得分
    boolean isStarted = false;//用于判断是否游戏开始
    boolean isFailed = false;//判断是否撞到自身
    String direction = "R";//U上  D下   L左   R右   初始时蛇头方向
    Timer timer = new Timer(100, this);//定义计时器用于监测刷新
    Random random = new Random();//创建随机数
    int foodx = random.nextInt(34) * 25 + 25;
    int foody = random.nextInt(24) * 25 + 75;//   食物坐标


    public SnakePanel() {
        this.setFocusable(true);
        this.addKeyListener(this);
        init();
        timer.start();
    }//用于初始化


    @Override
    public void paint(Graphics g) {
        this.setBackground(Color.BLACK);
        title.paintIcon(this, g, 25, 11);
        g.fillRect(25, 75, 850, 600);//定义画板

        if (direction.equals("R")) {
            right.paintIcon(this, g, snakex[0], snakey[0]);
        } else if (direction.equals("U")) {
            up.paintIcon(this, g, snakex[0], snakey[0]);
        } else if (direction.equals("D")) {
            down.paintIcon(this, g, snakex[0], snakey[0]);
        } else if (direction.equals("L")) {
            left.paintIcon(this, g, snakex[0], snakey[0]);
        }//判断方向调用图片

        for (int i = 0; i < len; i++) {
            body.paintIcon(this, g, snakex[i], snakey[i]);
        }  //蛇身长度

        if (!isStarted) {
            g.setColor(Color.WHITE);
            g.setFont(new Font("宋体", Font.BOLD, 30));
            g.drawString("按下空格键 开始/暂停 游戏", 300, 400);
        }
        if (isFailed) {
            g.setColor(Color.WHITE);
            g.setFont(new Font("宋体", Font.BOLD, 30));
            g.drawString("游戏结束,请重新按下空格加载游戏", 200, 400);
        }
        //绘制食物坐标
        food.paintIcon(this, g, foodx, foody);

        g.setColor(Color.WHITE);
        g.setFont(new Font("宋体", Font.BOLD, 20));
        g.drawString("长度:" + len, 760, 37);
        g.drawString("分数:" + score, 760, 57);

    }//游戏显示文字

    public void init() {
        len = 3;
        score = 0;
        isFailed = false;
        isStarted = false;
        direction = "R";
        snakex[0] = 100;
        snakex[1] = 75;
        snakex[2] = 50;
        snakey[0] = 100;
        snakey[1] = 100;
        snakey[2] = 100;
    }//蛇身坐标位置


    @Override
    public void keyTyped(KeyEvent e) {

    }

    //监听按键进行判断方向
    @Override
    public void keyPressed(KeyEvent e) {
        int Keycode = e.getKeyCode();
        if (Keycode == KeyEvent.VK_SPACE) {
            if (isFailed) {
                init();
            } else {
                isStarted = !isStarted;
            }
        } else if (Keycode == KeyEvent.VK_UP && !direction.equals("D")) {
            direction = "U";
        } else if (Keycode == KeyEvent.VK_DOWN && !direction.equals("U")) {
            direction = "D";
        } else if (Keycode == KeyEvent.VK_RIGHT && !direction.equals("L")) {
            direction = "R";
        } else if (Keycode == KeyEvent.VK_LEFT && !direction.equals("R")) {
            direction = "L";
        }
        repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (isStarted && !isFailed) {
            for (int i = len; i > 0; i--) {
                snakex[i] = snakex[i - 1];
                snakey[i] = snakey[i - 1];
            }//蛇身与蛇头位置关联

            switch (direction) {
                case "R":
                    snakex[0] = snakex[0] + 25;
                    if (snakex[0] > 850) {
                        snakex[0] = 25;
                    }
                    break;
                case "L":
                    snakex[0] = snakex[0] - 25;
                    if (snakex[0] < 25) {
                        snakex[0] = 850;
                    }
                    break;
                case "D":
                    snakey[0] = snakey[0] + 25;
                    if (snakey[0] > 650) {
                        snakey[0] = 75;
                    }
                    break;
                case "U":
                    snakey[0] = snakey[0] - 25;
                    if (snakey[0] < 75) {
                        snakey[0] = 650;
                    }
                    break;
                default:
                    break;
            }

            if (snakex[0] == foodx && snakey[0] == foody) {
                playSound();
                len++;
                score = score + 2;
                foodx = random.nextInt(34) * 25 + 25;
                foody = random.nextInt(24) * 25 + 75;
            }//蛇吃到食物后蛇身加长并且食物在其他处随机出现
            for (int i = 1; i < len; i++) {
                //判断是否蛇头撞到蛇身
                if (snakex[0] == snakex[i] && snakey[0] == snakey[i]) {
                    isFailed = true;
                }
            }
        }
        repaint();
    }

    //    吃到物体音频
    private void playSound() {
        try {
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File("beep.wav"));
            Clip clip = AudioSystem.getClip();
            clip.open(audioInputStream);
            clip.start();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }//用于吃到食物后声音播放
}

运行效果

游戏开始

游戏中

游戏失败

资源下载

项目完整源代码已经在我的码云分享了有需要的请自行下载:https://gitee.com/jingzhaoghost/snake

posted @ 2022-02-14 10:44  Tireless  阅读(188)  评论(0编辑  收藏  举报