基于Java的贪吃蛇小游戏

一、开发思路

    设定一个一定大小的且大小不可变的游戏窗口

    在创建的窗口上绘制游戏的基本面板样式

    使用提前保存的素材图标绘制一条静态的小蛇

    使小蛇能够移动;实际只需蛇头坐标移动,每节身体覆盖前一节身体坐标,设置定时器Timer timer =new Timer();监听时间让小蛇能移动

    监听键盘操作,使用户能通过键盘控制蛇的方向

    定义一个食物坐标,用random随机数类实现食物随机生成

    小蛇吃到食物时身体长度+1,实际是蛇头坐标与食物坐标重合时

    boolean定义游戏失败的判断,当蛇头与任何身体部位坐标重合(或撞到边界)则游戏失败,可再设置积分系统,每吃到一次食物加一定分数
二 新建一个Data类,作为图片资源

package snake;

import java.net.URL;

import javax.swing.ImageIcon;

public class Data {

    public static URL headerURL = Data.class.getResource("/statics/header.png");
    public static ImageIcon header;

    static {
        assert headerURL != null;
        header = new ImageIcon(headerURL);
    }

    public static URL upURL = Data.class.getResource("/statics/up.png");
    public static URL downURL = Data.class.getResource("/statics/down.png");
    public static URL leftURL = Data.class.getResource("/statics/left.png");
    public static URL rightURL = Data.class.getResource("/statics/right.png");

    public static ImageIcon up = new ImageIcon(upURL);
    public static ImageIcon down = new ImageIcon(downURL);
    public static ImageIcon left = new ImageIcon(leftURL);
    public static ImageIcon right = new ImageIcon(rightURL);

    public static URL bodyURL = Data.class.getResource("/statics/body.png");
    public static ImageIcon body;

    static {
        assert bodyURL != null;
        body = new ImageIcon(bodyURL);
    }

    public static URL foodURL = Data.class.getResource("/statics/food.png");
    public static ImageIcon food;

    static {
        assert foodURL != null;
        food = new ImageIcon(foodURL);
    }

}

三 绘制静态游戏窗口

package snake;


import javax.swing.JFrame;
import javax.swing.WindowConstants;
//创建主窗口
public class MainFrame{

    public MainFrame(){
        init();
    }

    public void init(){
        JFrame frame = new JFrame();

        frame.setSize(915, 745);
        frame.setResizable(false);//窗口不可拉伸
        frame.setTitle("贪吃蛇小游戏");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        frame.add(new GamePanel());

        frame.setVisible(true);
    }
}

四 游戏面板类 GamePanel

package snake;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

import javax.swing.JPanel;
import javax.swing.Timer;

//游戏面板
public class GamePanel extends JPanel implements ActionListener{

    //定义游戏数据
    int panel_Width;
    int panel_Height;

    int snake_Speed = 300;//刷新时间

    //定义蛇的数据结构
    int length;	//蛇的长度
    int[] snake_X = new int[600];
    int[] snake_Y = new int[600];
    String snake_Orientation; 	//蛇头朝向

    //食物的坐标
    int food_X;
    int food_Y;
    Random random = new Random();

    //定义游戏状态
    boolean isStrat = false; //默认暂停状态

    //游戏失败
    boolean isFail = false;

    //游戏积分
    int score;
    int food_Value;//食物分数

    //游戏难度
    int level;

    //cheat
    boolean cheat = false;

    //定时器
    Timer timer = new Timer(snake_Speed, this);

    //构造器
    public GamePanel() {
        init();
        //获得焦点和键盘事件
        this.setFocusable(true);	//获得焦点事件
        this.addKeyListener(new keyboardListener());
        timer.start();//游戏一开始,定时器就启动
    }

    //初始化
    public void init(){
        panel_Width = 850;
        panel_Height = 600;

        length = 3;
        snake_X[0] = 100;snake_Y[0] = 100;	//头的坐标
        snake_X[1] = 75;snake_Y[1] = 100;	//第一节身体的坐标
        snake_X[2] = 50;snake_Y[2] = 100;	//第二节身体的坐标
        snake_Orientation = "right";	//初始头的方向为右

        //食物随机分布在界面上

        food_X = 25 + 25*random.nextInt(33);//生成1到34的随机数
        food_Y = 75 + 25*random.nextInt(23);

        score = 0;
        food_Value = 5;

        level = 1;
    }


    @Override
    protected void paintComponent(Graphics g) {

        super.paintComponent(g);//清屏

        //绘制静态面板
        this.setBackground(Color.lightGray);

        //画下方游戏界面
        g.fillRect(25, 75, panel_Width, panel_Height);

        //画积分
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑", Font.BOLD, 15));
        g.drawString("长度:"+length, 750, 25);
        g.drawString("分数:"+score, 750, 40);
        g.drawString("难度:"+level, 750, 55);
        g.drawString("~糖豆人大作战~", 370, 30);


        //画食物
        Data.food.paintIcon(this, g, food_X, food_Y);

        //画小蛇
        if (snake_Orientation.equals("right")){
            Data.right.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝右的头部
        }else if(snake_Orientation.equals("left")){
            Data.left.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝左的头部
        }else if(snake_Orientation.equals("up")){
            Data.up.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝上的头部
        }else if(snake_Orientation.equals("down")){
            Data.down.paintIcon(this, g, snake_X[0], snake_Y[0]);//画朝下的头部
        }

        for (int i = 1; i < length; i++) {
            Data.body.paintIcon(this, g, snake_X[i], snake_Y[i]);//画每一节身体
        }


        //游戏状态
        if (isStrat == false){
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("按下空格开始游戏", 300, 300);
        }

        //游戏失败
        if (isFail == true){
            g.setColor(Color.red);
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("失败,按下空格重新开始", 220, 300);
        }

    }

    //键盘监听
    class keyboardListener extends KeyAdapter{
        @Override
        public void keyPressed(KeyEvent e) {
            int keyCode = e.getKeyCode();//获得按下的键
            if (keyCode == KeyEvent.VK_SPACE){
                if (isFail == true){
                    //空格控制重新开始
                    isFail = false;
                    init();
                }else {
                    //空格控制游戏暂停
                    isStrat = !isStrat;	//isStart取反
                }
                repaint();
            }

            //控制小蛇移动
            if (keyCode == KeyEvent.VK_UP){
                if (snake_Orientation != "down"){
                    snake_Orientation = "up";
                }
            }else if (keyCode == KeyEvent.VK_DOWN){
                if (snake_Orientation != "up"){
                    snake_Orientation = "down";
                }
            }else if (keyCode == KeyEvent.VK_LEFT){
                if (snake_Orientation != "right"){
                    snake_Orientation = "left";
                }
            }else if (keyCode == KeyEvent.VK_RIGHT){
                if (snake_Orientation != "left"){
                    snake_Orientation = "right";
                }
            }

            if (keyCode == KeyEvent.VK_C){
                cheat = !cheat;
            }
        }
    }

    //事件监听,通过固定的时间来刷新
    @Override
    public void actionPerformed(ActionEvent e) {
        if (isStrat == true && isFail == false){	//游戏开始,小蛇运动
            //身体跟随移动
            for (int i = length-1; i > 0; i--) {//向前移动一节(每个身体都到上一节身体的坐标)
                //新生成的身体不可见,否则有bug
                snake_X[length] = -50;
                snake_Y[length] = -50;

                snake_X[i] = snake_X[i-1];
                snake_Y[i] = snake_Y[i-1];
            }
            //头部运动判断,只需要控制头部的运动,其他身体都会跟着动
            if (snake_Orientation == "up"){
                snake_Y[0] = snake_Y[0]-25;
                if (snake_Y[0] < 75){
                    snake_Y[0] = panel_Height+50;
                }
            }else if (snake_Orientation == "down"){
                snake_Y[0] = snake_Y[0]+25;
                if (snake_Y[0] > panel_Height+50){
                    snake_Y[0] = 75;
                }
            }else if (snake_Orientation == "left"){
                snake_X[0] = snake_X[0]-25;
                if (snake_X[0] < 25){
                    snake_X[0] = panel_Width;
                }
            }else if (snake_Orientation == "right"){
                snake_X[0] = snake_X[0]+25;
                if (snake_X[0] > panel_Width){
                    snake_X[0] = 25;
                }
            }

            //吃食物
            if (snake_X[0] == food_X && snake_Y[0] == food_Y) {
                length++;
                score += food_Value;
                //重新生成食物
                food_X = 25 + 25 * random.nextInt(34);
                food_Y = 75 + 25 * random.nextInt(24);
            }

            //失败判定,头碰到身体就算失败
            if (cheat == false){
                for (int i = 1; i < length; i++) {	//遍历所有身体坐标
                    if (snake_X[0] == snake_X[i] && snake_Y[0] == snake_Y[i]){
                        isFail = true;
                        break;
                    }
                }
            }

            if (length > 5 && length < 10){
                level = 2;
                timer.stop();
                snake_Speed = 100;
            }
            if (length > 20 && length < 30){
                level = 3;
                timer.stop();
                snake_Speed = 50;
            }

            repaint();
        }
        timer.start();
    }

}

1. 游戏规则:蛇头碰到蛇身结束游戏

2. 根据积分等级,蛇的移动速度加快,积分越高,移动速度越快

3. 键盘:上下左右键控制蛇的移动方向

五 最后一个类,启动类 StartGame

package snake;
public class StartGame {
    public static void main(String[] args) {
        new MainFrame();
    }
}

六、效果截图