基于GUI简易贪吃蛇

基于GUI简易贪吃蛇

首先定义一个JFrame窗口,之后会在窗口上加面板用来显示游戏。
StartGame.java

import javax.swing.*;

//游戏主启动
public class StartGame {
    public static void main(String[] args) {
        JFrame jFrame = new JFrame();

        jFrame.setBounds(300,100,900,800);//宽度和高度要按照一定比例
        jFrame.setResizable(false);//设置窗口大小不可变
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jFrame.setVisible(true);
    }
}

然后创建一个GamePanel.java用来些游戏的面板,使用画笔来完善具体的游戏元素。

public class GamePanel extends JPanel{
    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
    }
}

面板中首先要画出一个游戏的范围,这里设定蛇一块身体是2525大小,因此游戏区域的长和宽就需要与蛇的身体成比例。
这里设定了一个850
650的游戏区域

g.fillRect(25,25,850,650);

设置一个键盘监听实现按空格键开始游戏,这里将键盘监听设置为GamePanel的内部类。
先定义一个游戏状态变量

boolean isStart = false;//游戏状态默认未开始

将开始提示用画笔画到界面上

    if(!isStart){
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑",Font.BOLD,40));
        g.drawString("按空格开始游戏",300,300);
    }

键盘监听类

class GameListener extends KeyAdapter{
        @Override
        public void keyPressed(KeyEvent e) {
            int keyCode = e.getKeyCode();//获得键盘按键是哪一个
            //空格开始游戏
            if (keyCode == KeyEvent.VK_SPACE) {
                isStart = !isStart;//取反
                repaint();
            }
        }
    }

接下来要用画笔将蛇画出来,这里设定蛇的每一个身体都是由25*25大小的正方形组成,为了区分头与身体,头部用红色,身体用绿色,设定头部坐标(100,50),身体部分在X轴依次减25(初始状态向右)。

//定义蛇的数据结构
int length;//蛇的长度
final int size = 24;//蛇的尺寸,这里设置为24*24可以更好区分每一块身体
//设定蛇每一个身体的坐标
int[] snakeX = new int[600];
int[] snakeY = new int[600];
String direction;//初始方向
//设定一个初始化方法用于初始化数据
public void init(){
        length = 3;//初始长度
        snakeX[0] = 100;//头部坐标
        snakeY[0] = 50;
        snakeX[1] = 75;//第一个身体坐标
        snakeY[1] = 50;
        snakeX[2] = 50;//第二个身体坐标
        snakeY[2] = 50;
        direction = "R";//初始方向向右
    }

实现按方向键使蛇移动

利用键盘监听获得按的是哪一个方向

        if (keyCode == KeyEvent.VK_UP) {
            direction = "U";
        } else if (keyCode == KeyEvent.VK_DOWN) {
            direction = "D";
        } else if (keyCode == KeyEvent.VK_RIGHT) {
            direction = "R";
        } else if (keyCode == KeyEvent.VK_LEFT) {
            direction = "L";
        }

设置定时器定义刷新时间

Timer timer = new Timer(50,new timeListener());//50毫秒执行一次

定义一个内部类timeListener用于刷新画面实现蛇的移动

class timeListener implements ActionListener{
        @Override
        public void actionPerformed(ActionEvent e) {
            if(isStart){
                for (int i = length-1;i>0;i--){
                    //将后一节移动到前一节的位置
                    snakeX[i] = snakeX[i-1];
                    snakeY[i] = snakeY[i-1];
                }
                switch (direction) {
                    case "R":
                        snakeX[0] = snakeX[0] + 25;
                        break;
                    case "L":
                        snakeX[0] = snakeX[0] - 25;
                        break;
                    case "U":
                        snakeY[0] = snakeY[0] - 25;
                        break;
                    case "D":
                        snakeY[0] = snakeY[0] + 25;
                        break;
                }
                repaint();//重画页面
            }
            timer.start();//开启定时器
        }
    }

再用类似的方法在随机坐标画出一个食物。先定义食物的相关变量

int foodX;
int foodY;
Random random = new Random();

在init中添加初始化食物坐标代码

foodX = 25+25*random.nextInt(33);
foodY = 25+25*random.nextInt(23);

使用画笔将食物画出来

g.setColor(Color.yellow);
g.fillOval(foodX,foodY,25,25);

实现蛇吃食物事件,当蛇头部坐标与食物坐标重合时重新生成食物并让蛇的长度+1。
actionPerformed方法中

            if (snakeX[0]==foodX && snakeY[0]==foodY){
                length++;//长度增加
                //重新生成食物
                foodX = 25+25*random.nextInt(33);
                foodY = 25+25*random.nextInt(23);
            }

游戏失败的情况:

  1. 蛇碰到自己的身体

  2. 蛇碰到边界
    首先定义一个失败状态变量

    boolean isFail = false;//游戏失败状态

将以上两种情况代码添加到timeListener类中

        if(snakeX[0] > 850 || snakeX[0] < 25 || snakeY[0] > 650 || snakeY[0] < 25){ //边界判定
            isFail = true;
        }
        for (int i = 1;i < length;i++) {//重合判定
            if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
                isFail = true;
                break;
            }
        }

画出一个失败的画面

    if(isFail){
        g.setColor(Color.red);
        g.setFont(new Font("微软雅黑",Font.BOLD,40));
        g.drawString("失败,请重新开始游戏",300,300);
    }

修改开始游戏部分代码

        if (keyCode == KeyEvent.VK_SPACE) {
            if(isFail){
                isFail = false;
                init();
            }else {
                isStart = !isStart;//取反
            }
            repaint();
        }

timeListener类中修改

if(isStart && !isFail)

最后在StartGame类中添加面板

jFrame.add(new GamePanel());

完成。
基于GUI简易贪吃蛇
完整代码如下
StartGame.java

import javax.swing.*;

//游戏主启动
public class StartGame {
    public static void main(String[] args) {
        JFrame jFrame = new JFrame();
        jFrame.add(new GamePanel());

        jFrame.setBounds(300,100,900,800);//宽度和高度要按照一定比例
        jFrame.setResizable(false);//设置窗口大小不可变
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jFrame.setVisible(true);
    }
}

GamePanel.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;

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

    //定义蛇的数据结构
    int length;//蛇的长度
    final int size = 24;//蛇的尺寸
    int[] snakeX = new int[600];
    int[] snakeY = new int[600];
    String direction;//初始方向
    //食物坐标
    int foodX;
    int foodY;
    Random random = new Random();
    boolean isStart = false;//游戏状态默认未开始
    boolean isFail = false;//游戏失败状态
    //定时器,100毫秒刷新一次
    Timer timer = new Timer(50,new timeListener());

    //构造器
    public GamePanel(){
        init();
        //获得焦点和键盘事件
        setFocusable(true);
        addKeyListener(new GameListener());
    }

    //初始化方法
    public void init(){
        length = 3;//初始长度
        snakeX[0] = 100;//头部坐标
        snakeY[0] = 50;
        snakeX[1] = 75;//第一个身体坐标
        snakeY[1] = 50;
        snakeX[2] = 50;//第二个身体坐标
        snakeY[2] = 50;
        //随机生成事物
        foodX = 25+25*random.nextInt(33);
        foodY = 25+25*random.nextInt(23);
        direction = "R";//初始方向向右
        timer.start();//游戏一开始启动定时器
    }



    //绘制面板,游戏中所有东西都使用此画笔
    @Override
    protected void paintComponent(Graphics g) {

        super.paintComponent(g);
        //绘制静态面板
//        setBackground(Color.BLACK);
        g.fillRect(25,25,850,650);
        g.setColor(Color.red);
        g.drawRect(25,25,850,650);
        //画食物
        g.setColor(Color.yellow);
        g.fillOval(foodX,foodY,25,25);
        //画蛇
        g.setColor(Color.red);
        g.fillRect(snakeX[0],snakeY[0],size,size);
        g.setColor(Color.green);
        for (int i = 1;i < length; i++) {
            g.fillRect(snakeX[i],snakeY[i],size,size);
        }
        //画积分
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑",Font.BOLD,15));
        g.drawString("长度:"+length,750,50);
        //游戏状态
        if(!isStart){
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("按空格开始游戏",300,300);
        }
        if(isFail){
            g.setColor(Color.red);
            g.setFont(new Font("微软雅黑",Font.BOLD,40));
            g.drawString("失败,请重新开始游戏",300,300);
        }
    }
    //内部类,键盘监听
    class GameListener extends KeyAdapter{
        @Override
        public void keyPressed(KeyEvent e) {
            int keyCode = e.getKeyCode();//获得键盘按键是哪一个
            //空格开始游戏
            if (keyCode == KeyEvent.VK_SPACE) {
                if(isFail){
                    isFail = false;
                    init();
                }else {
                    isStart = !isStart;//取反
                }
                repaint();
            }
            //移动
            if (keyCode == KeyEvent.VK_UP) {
                direction = "U";
            } else if (keyCode == KeyEvent.VK_DOWN) {
                direction = "D";
            } else if (keyCode == KeyEvent.VK_RIGHT) {
                direction = "R";
            } else if (keyCode == KeyEvent.VK_LEFT) {
                direction = "L";
            }
        }
    }
    //定时刷新
    class timeListener implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent e) {
            if(isStart && !isFail){
                for (int i = length-1;i>0;i--){
                    //将后一节移动到前一节的位置
                    snakeX[i] = snakeX[i-1];
                    snakeY[i] = snakeY[i-1];
                }
                switch (direction) {
                    case "R":
                        snakeX[0] = snakeX[0] + 25;
                        break;
                    case "L":
                        snakeX[0] = snakeX[0] - 25;
                        break;
                    case "U":
                        snakeY[0] = snakeY[0] - 25;
                        break;
                    case "D":
                        snakeY[0] = snakeY[0] + 25;
                        break;
                }
                //吃事物事件

                if (snakeX[0]==foodX && snakeY[0]==foodY){
                    length++;//长度增加
                    //重新生成食物
                    foodX = 25+25*random.nextInt(33);
                    foodY = 25+25*random.nextInt(23);
                }
                //失败判定
                if(snakeX[0] > 850 || snakeX[0] < 25 || snakeY[0] > 650 || snakeY[0] < 25){ //边界判定
                    isFail = true;
                }
                for (int i = 1;i < length;i++) {//重合判定
                    if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
                        isFail = true;
                        break;
                    }
                }
                repaint();//重画页面
            }
            timer.start();//开启定时器
        }
    }

}

基于GUI简易贪吃蛇

上一篇:设计模式


下一篇:1.RPC基本原理