GUI-4 实战贪吃蛇

4.贪吃蛇

必备知识:

  • 帧,如果时间片足够小,就是动画,一秒30帧,连起来就是动画,拆开就是静态的图片
  • 键盘监听
  • 定时器Timer

主启动类

package com.zr.snake;

import javax.swing.*;
import java.awt.*;

//游戏的主启动类
public class StartGame {
    public static void main(String[] args) {
        //创建游戏窗口,名字为"贪吃蛇的世界"
        JFrame frame = new JFrame("贪吃蛇的世界");
        //设置游戏窗口大小位置
        frame.setBounds(320,100,875,750);
        //设置游戏窗口大小不可变
        frame.setResizable(false);

        //设置游戏窗口可关闭
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        //frame.setVisible(true);如果放在添加面板之前,就只会显示窗口,添加的游戏面板加载不出来

        //将游戏面板添加到游戏窗口中
        frame.add(new GamePanel());

        //设置游戏窗口可见 必须放在最后!!!!!
        frame.setVisible(true);
    }
}

数据中心

package com.zr.snake;

import javax.swing.*;
import java.net.URL;

//蛇的数据
public class SnakeData {

    //蛇的头,身子都为25*25像素的

    //相对路径(类的包下的文件):"文件名.后缀名" 绝对路径(src目录下的文件):"/**.*.后缀名"
    private static URL bodyURL = SnakeData.class.getResource("/statics/body.png");
    public static ImageIcon body = new ImageIcon(bodyURL);

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

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

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

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

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

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

游戏面板

package com.zr.snake;

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

//游戏的面板 继承面板类,实现键盘监听器接口
public class GamePanel extends JPanel implements KeyListener,ActionListener {

    private int length;//蛇的节数
    private int[] snakeX = new int[980];//蛇的x坐标数组
    private int[] snakeY = new int[980];//蛇的y坐标数组
    private String direction;//蛇头的方向
    private int score;
    private int foodX;//食物的x坐标
    private int foodY;//食物的y坐标
    private Boolean isStart;//游戏状态
    private boolean isFail;//游戏是否失败
    private Random random = new Random();//生成随机数种子
    //定时器 每1000毫秒执行一次ActionListener对象的actionPerformed()方法
    private Timer timer = new Timer(130,this);

    //调用构造器执行init()方法
    public GamePanel() {
        init();//调用初始化方法
        this.setFocusable(true);//绑定焦点事件
        this.addKeyListener(this);//绑定键盘监听事件
        timer.start();//定时器开始
    }

    //初始化方法
    public void init() {
        length = 3;
        snakeX[0] = 150;snakeY[0] = 100;//蛇头的坐标
        snakeX[1] = 125;snakeY[1] = 100;//第一节身子的坐标
        snakeX[2] = 100;snakeY[2] = 100;//第二节身子的坐标
        direction = "right";//默认蛇头向右
        isStart = false;//默认游戏状态为不开始
        isFail = false;//默认游戏不失败
        //初始化随机食物坐标
        //g.fillRect(0, 50, w875, h700);
        foodX = 25*random.nextInt(34);
        foodY = 50+25*random.nextInt(26);
        score = 0;
    }

    //绘制面板,游戏中的所有资源,都用此画笔g来画
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);//清屏 ??闪烁??
        //设置面板颜色为白色
        this.setBackground(new Color(134, 93, 75));
        //画励志语
        SnakeData.header.paintIcon(this, g, 100, 0);
        //画游戏界面(实心矩形)
        g.fillRect(0, 50, 875, 700);
        //画食物
        SnakeData.food.paintIcon(this,g,foodX,foodY);

        //画蛇
        //动态画蛇头
        if (direction.equals("right")) {
            SnakeData.right.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (direction.equals("up")) {
            SnakeData.up.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (direction.equals("down")) {
            SnakeData.down.paintIcon(this, g, snakeX[0], snakeY[0]);
        } else if (direction.equals("left")) {
            SnakeData.left.paintIcon(this, g, snakeX[0], snakeY[0]);
        }
        //动态画蛇身
        for (int i = 1; i < length; i++) {
            SnakeData.body.paintIcon(this, g, snakeX[i], snakeY[i]);
        }

        g.setColor(new Color(41, 45, 41, 182));
        g.setFont(new Font("微软雅黑", Font.BOLD, 15));
        g.drawString("长度:"+length, 800, 20);
        g.drawString("积分:"+score, 800, 40);

        //画状态提示语
        if (isStart == false) {
            g.setColor(new Color(235, 255, 232, 182));
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("按下空格开始游戏", 275, 300);
        }
        //画失败提示语
        if (isFail){
            g.setColor(new Color(109, 1, 8, 182));
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("你失败了", 275, 300);
        }
    }

    @Override//事件监听---需要通过固定时间来刷新
    public void actionPerformed(ActionEvent e) {
        if(snakeX[0] == foodX & snakeY[0] == foodY){
            length++;
            score = score + 10;
            foodX = 25*random.nextInt(35);
            foodY = 50+25*random.nextInt(30);
        }

        //如果游戏开始且不失败
        if (isStart && isFail == false) {
            //蛇身的移动
            for (int i = length - 1; i > 0; i--) {
                snakeX[i] = snakeX[i - 1];//向前移动一节
                snakeY[i] = snakeY[i - 1];
            }
            //蛇头的移动
            if(direction.equals("right")){
                snakeX[0] = snakeX[0] + 25;
                if(snakeX[0] > 875){ snakeX[0] = 0; }//边界判断
            } else if(direction.equals("left")){
                snakeX[0] = snakeX[0] - 25;
                if(snakeX[0] < 0) { snakeX[0] = 875; }//边界判断
            } else if (direction.equals("up")){
                snakeY[0] = snakeY[0] - 25;
                if(snakeY[0] <50) { snakeY[0] = 750; }//边界判断
            } else if(direction.equals("down")){
                snakeY[0] = snakeY[0] + 25;
                if(snakeY[0] > 750) { snakeY[0] = 50;}//边界判断
            }
            //失败判定
            for (int i = 1; i < length; i++) {
                if(snakeX[0] == snakeX[i] & snakeY[0] == snakeY[i]){
                    isFail = true;
                }
            }
            repaint();
        }
    }

    @Override//键盘监听
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();//获得键值
        if (keyCode == KeyEvent.VK_SPACE) {//当键值为空格
            if(isFail){//如果当前为失败
                isFail = false;
                init();
            }else {
                isStart = !isStart;//状态取反
            }
        }else if(keyCode == KeyEvent.VK_UP){//当键值为上
            if(direction.equals("down")){//如果此时方向与键值相反,则返回
                return;
            }else {
                direction = "up";
            }
        }else if(keyCode == KeyEvent.VK_DOWN) {//当键值为下
            if(direction.equals("up")){
                return;
            }else {
                direction = "down";
            }
        }else if(keyCode == KeyEvent.VK_LEFT) {//当键值为左
            if(direction.equals("right")){
                return;
            }else {
                direction = "left";
            }
        }else if(keyCode == KeyEvent.VK_RIGHT) {//当键值为右
            if(direction.equals("left")){
                return;
            }else {
                direction = "right";
            }
        }
        repaint();//重画
    }

    public void keyTyped(KeyEvent e) {}
    public void keyReleased(KeyEvent e) {}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值