GUI实现贪吃蛇小游戏

完成了GUI部分学习, 实现一个贪吃蛇小游戏

效果

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

功能

  • 开始随机初始化食物
  • 边界实现循环
  • 蛇每吃一个食物增长一个单位长度
  • 不能反方向移动
  • 食物吃完随机刷新
  • 碰到自己游戏结束
  • 按下空格可以暂停游戏和开始游戏
  • 失败后按下空格可以重新开始
关键代码解释
public class StartGame {
    public static void main(String[] args) {
        JFrame frame = new JFrame();

        // add componets to frame
        frame.add(new GamePanel());

        // set characters of frame
        frame.setResizable(false);
        frame.setBounds(10,10,900,720);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}

开始界面
常规GUI操作, 设置Frame属性打一套, 组件部分添加GamePanel类, 所有功能在GamePanel中完成

    public void init(){
        length = 3;
        snakeX[0] = 100; snakeY[0] = 100;
        snakeX[1] = 75; snakeY[1] = 100;
        snakeX[2] = 50; snakeY[2] = 100;
        fx = "R";
        foodX = 25 + 25 * random.nextInt(34);
        foodY = 25 + 25 * random.nextInt(24);
        score = 0;
    }

初始化组件, 一开始设定蛇的长度, 头部位置, 方向, 食物随机生成

        // paint head of snake
        if (fx.equals("R")) {
            Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("L")) {
            Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("U")) {
            Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("D")) {
            Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else {
            System.out.println("error dirction!");
        }

        // paint body of snake
        for (int i = 1; i < length; i++) {
            Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
        }

画出蛇的头部和身体
此处运用了一个技巧, 蛇身从尾往前赋值前一个单位的位置, 这样不用考虑方向就能实现蛇身移动, 蛇头的方向分4个方向考虑

    @Override
    public void actionPerformed(ActionEvent e) {
        if (isrunning && isFail == false) {
            // eat food
            if (snakeX[0] == foodX && snakeY[0] == foodY) {
                length++;
                score += 10;
                foodX = 25 + 25 * random.nextInt(34);
                foodY = 75 + 25 * random.nextInt(24);
            }

            // move body
            for (int i = length - 1; i > 0 ; i--) {
                snakeX[i] = snakeX[i - 1];
                snakeY[i] = snakeY[i - 1];
            }
            // move head
            if (fx.equals("R")) { // right move
                snakeX[0] += 25;
                if (snakeX[0] > 850) {
                    snakeX[0] = 25;
                }
            } else if (fx.equals("L")) { // left move
                snakeX[0] -= 25;
                if (snakeX[0] < 25) {
                    snakeX[0] = 850;
                }
            } else if (fx.equals("U")) { // up move
                snakeY[0] -= 25;
                if (snakeY[0] < 75) {
                    snakeY[0] = 650;
                }
            } else if (fx.equals("D")) { // down move
                snakeY[0] += 25;
                if (snakeY[0] > 650) {
                    snakeY[0] = 75;
                }
            }

            for (int i = 1; i < length; i++) {
                if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
                    isFail = true;
                    break;
                }
            }

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

按键监听, 监听方向键和空格, 控制游戏状态(开始/暂停), 和蛇的移动方向, 边界循环用边界判断条件实现, 用isFail参数判断游戏失败状态



完整代码

GameStart部分

public class StartGame {
    public static void main(String[] args) {
        JFrame frame = new JFrame();

        // add componets to frame
        frame.add(new GamePanel());

        // set characters of frame
        frame.setResizable(false);
        frame.setBounds(10,10,900,720);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}

GamePanel部分

public class GamePanel extends JPanel implements KeyListener, ActionListener {
    // define snake struction
    int length;
    int[] snakeX = new int[600];
    int[] snakeY = new int[600];
    String fx;
    boolean isrunning = false;
    Timer timer = new Timer(50, this);

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

    boolean isFail = false;
    int score;

    public GamePanel() {
        init();
        this.setFocusable(true);
        this.addKeyListener(this);
    }

    public void init(){
        length = 3;
        snakeX[0] = 100; snakeY[0] = 100;
        snakeX[1] = 75; snakeY[1] = 100;
        snakeX[2] = 50; snakeY[2] = 100;
        fx = "R";
        foodX = 25 + 25 * random.nextInt(34);
        foodY = 25 + 25 * random.nextInt(24);
        score = 0;
    }


    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); // clear screen
        this.setBackground(Color.WHITE);

        Data.header.paintIcon(this, g,25, 11);
        g.fillRect(25, 75, 850, 600);

        // paint score and length of snake
        g.setColor(Color.white);
        g.setFont(new Font("微软雅黑", Font.BOLD, 18));
        g.drawString("length "+ length, 760, 35);
        g.drawString("score " + score, 760, 55);

        // paint food
        Data.food.paintIcon(this, g, foodX, foodY);

        // paint head of snake
        if (fx.equals("R")) {
            Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("L")) {
            Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("U")) {
            Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (fx.equals("D")) {
            Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else {
            System.out.println("error dirction!");
        }

        // paint body of snake
        for (int i = 1; i < length; i++) {
            Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
        }

        if (isrunning == false) {
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("press space to start", 240, 360);
        }

        if (isFail) {
            g.setColor(Color.RED);
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("FAIL, press space to restart", 180, 360);
        }

    }



    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        if (keyCode == KeyEvent.VK_SPACE) {
            if (isFail) { // restart
                isFail = false;
                init();
            } else {
                isrunning = !isrunning;
                if (isrunning) {
                    timer.start();
                } else {
                    timer.stop();
                }
                repaint();
            }
        }

        if (isrunning && isFail == false) {
            if (keyCode == KeyEvent.VK_RIGHT) {
                if (!fx.equals("L")) {
                    fx = "R";
                }
            } else if (keyCode == KeyEvent.VK_LEFT) {
                if (!fx.equals("R")) {
                    fx = "L";
                }
            } else if (keyCode == KeyEvent.VK_UP) {
                if (!fx.equals("D")) {
                    fx = "U";
                }
            } else if (keyCode == KeyEvent.VK_DOWN) {
                if (!fx.equals("U")) {
                    fx = "D";
                }
            }
        }

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (isrunning && isFail == false) {
            // eat food
            if (snakeX[0] == foodX && snakeY[0] == foodY) {
                length++;
                score += 10;
                foodX = 25 + 25 * random.nextInt(34);
                foodY = 75 + 25 * random.nextInt(24);
            }

            // move body
            for (int i = length - 1; i > 0 ; i--) {
                snakeX[i] = snakeX[i - 1];
                snakeY[i] = snakeY[i - 1];
            }
            // move head
            if (fx.equals("R")) { // right move
                snakeX[0] += 25;
                if (snakeX[0] > 850) {
                    snakeX[0] = 25;
                }
            } else if (fx.equals("L")) { // left move
                snakeX[0] -= 25;
                if (snakeX[0] < 25) {
                    snakeX[0] = 850;
                }
            } else if (fx.equals("U")) { // up move
                snakeY[0] -= 25;
                if (snakeY[0] < 75) {
                    snakeY[0] = 650;
                }
            } else if (fx.equals("D")) { // down move
                snakeY[0] += 25;
                if (snakeY[0] > 650) {
                    snakeY[0] = 75;
                }
            }

            for (int i = 1; i < length; i++) {
                if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
                    isFail = true;
                    break;
                }
            }

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

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

}

data部分

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

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

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

    public static URL upURL = Data.class.getResource("statics/up.png");
    public static ImageIcon up = new ImageIcon(upURL);

    public static URL downURL = Data.class.getResource("statics/down.png");
    public static ImageIcon down = new ImageIcon(downURL);

    public static URL leftURL = Data.class.getResource("statics/left.png");
    public static ImageIcon left = new ImageIcon(leftURL);

    public static URL rightURL = Data.class.getResource("statics/right.png");
    public static ImageIcon right = new ImageIcon(rightURL);
}

注: 素材放到同目录下的statics文件夹中, 用URL相对路径索引


实现详解可见B站狂神说Java
https://www.bilibili.com/video/BV1DJ411B75F?p=27

总结

  • 以上完成了GUI部分的学习, 以后可以做一个完整的GUI知识点整理(立了个flag)
  • 接下来是多线程部分学习, 加油啊!!!
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值