20.贪吃蛇,GUI最后的项目

zhanjianhai / 2023-08-23 / 原文

总结:

  1. 1.定义数据
    2.画上去
    3.监听事件
    键盘事件
    (动作)事件
  2. 把一个大项目分成很多个小项目,依次完成小项目即可,掳清思虑路!
package snake;

import javax.swing.*;

// 主界面,         正常的游戏界面都应该在面板上
public class StartGame {
    public static void main(String[] args) {
        JFrame frame = new JFrame();


        frame.add(new GamePanel());  // 添加面板,//正常的游戏界面都应该在面板上

        frame.setVisible(true);
        frame.setBounds(10,10,900,720);
        frame.setResizable(false);  // 窗口大小不可以改变
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

    }
}
package snake;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
/*1.定义数据
2.画上去
3.监听事件
   键盘事件
   (动作)事件

 */

//游戏的面板  正常的游戏界面都应该在面板上
public class GamePanel extends JPanel implements KeyListener, ActionListener {

    //定义蛇的数据结构
    int length;//蛇的长度(包括蛇头)
    int[] snakeX = new int[600];//蛇的X坐标,包括蛇头和每一截身体
    int[] snakeY = new int[500];//蛇的Y坐标
    String direction;   // 蛇头的方向(上下左右)
    boolean isStart;  // 游戏状态默认为false未启动
    boolean isFail;   // 开启游戏后默认为游戏尚未失败
    Timer timer=new Timer(100,this); //每100ms执行一次,监听对象为自己this,需要用到ActionListener

    // 食物坐标
    int foodx,foody;
    Random random=new Random();

    // 分数
    int scroe;

    // 构造器,初始化
    public GamePanel() {
        init();
        setFocusable(true);  // 获得焦点事件,,, 不理解为什么要聚焦才行
        addKeyListener(this);  // 添加键盘监听器,为本身
        timer.start(); //计时器启动

    }

    // 初始化
    public void init() {
        isStart = false;  // 游戏状态默认为false
        isFail = false;
        scroe=0;
        direction = "R";   // 小蛇初始方向朝右
        length = 3;       // 小蛇的长度
        snakeX[0] = 100;snakeY[0] = 100; // 蛇头的初始坐标
        snakeX[1] = 75; snakeY[1] = 100;  // 第一段蛇身的坐标,25一小格
        snakeX[2] = 50; snakeY[2] = 100;  // 第二段蛇身的坐标
        // 随机生成食物
        foodx=25+25* random.nextInt(34); //横坐标有34个格子,800/25=34
        foody=75+25* random.nextInt(24); // 600/25=24
    }

    //绘制面板,我们游戏中的所有东西,都是用这个画笔来画的
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);//清屏
        //绘制静态的面板
        setBackground(Color.white);
        Data.header.paintIcon(this, g, 25, 11);//头部广告栏放上去
        g.fillRect(25, 75, 850, 600);//默认的游戏界面 默认为黑色,为一个黑色的矩形
        // 长度和积分
        g.setColor(Color.blue);
        g.setFont(new Font("微软雅黑", Font.BOLD, 20));
        g.drawString("长度: "+length,750,30);
        g.drawString("积分: "+scroe,750,50);


        // 画出snake

        // 画出蛇头的方向
        switch (direction) {
            case "U": Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);break;  // 蛇头向上,记得break;
            case "D": Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);break;  // 蛇头向下
            case "L": Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);break; // 蛇头向左
            case "R": Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);break; // 蛇头向右
        }
        // 画出食物
        Data.food.paintIcon(this,g,foodx,foody);

        //画出蛇身
        for (int i = 1; i < length; i++) {
            Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);  // 动态地画出蛇身
        }

        //游戏状态
        if (isStart == false) {  // 是否启动
            g.setColor(Color.white);
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("按下空格开始游戏", 300, 350);
        }
        if (isFail == true) {  // 是否失败
            g.setColor(Color.red);
            g.setFont(new Font("微软雅黑", Font.BOLD, 40));
            g.drawString("游戏失败,按下空格重新开始游戏", 200, 350);
        }

    }

//键盘监听事件
    @Override
    public void keyPressed(KeyEvent e) {


        int keyCode = e.getKeyCode();//获得键盘事件是哪一个
        if(keyCode == KeyEvent.VK_SPACE  ){//如果按下的是空格键
            if (isFail==true){
                // 重新开始
                init();
            }else {
                isStart = !isStart;//取反 否则isStart就失效了}
            }
            repaint();
        }
        //键盘移动
        if(keyCode == KeyEvent.VK_UP){
            direction = "U";
        }else if(keyCode == KeyEvent.VK_DOWN){
            direction = "D";
        }else if(keyCode == KeyEvent.VK_LEFT){
            direction = "L";
        }else if(keyCode == KeyEvent.VK_RIGHT){
            direction = "R";
        }
    }


    public void actionPerformed(ActionEvent e) {
        if(isStart && isFail==false){


            // 小蛇吃到食物
            if (snakeX[0]==foodx && snakeY[0]==foody){
                length++; // 长度加一
                scroe+=10; // 分数加10
                // 重新随机生成食物
                foodx=25+25* random.nextInt(34); //横坐标有34个格子,800/25=34
                foody=75+25* random.nextInt(24); // 600/25=24

            }

            // 蛇身移动
            for (int i = length - 1; i > 0 ; i--) {//后一节移到前一节的位置 snakeX[1] = snake[0];
                snakeX[i] = snakeX[i-1];
                snakeY[i] = snakeY[i-1];
            }

            //控制小蛇上下左右移动
            if(direction.equals("R")){
                snakeX[0] = snakeX[0] + 25;
                if(snakeX[0] > 850){ snakeX[0] = 25; }//边界判断
            }else if(direction.equals("L")){
                snakeX[0] = snakeX[0] - 25;
                if(snakeX[0] < 25){ snakeX[0] = 850; }//边界判断
            }else if(direction.equals("U")){
                snakeY[0] = snakeY[0] - 25;
                if(snakeY[0] < 75){ snakeY[0] = 650; }//边界判断
            }else if(direction.equals("D")){
                snakeY[0] = snakeY[0] + 25;
                if(snakeY[0] > 650){ snakeY[0] = 75; }//边界判断
            }

            // 判断是否失败,且要放在最后(美观直观),why?
            for (int i = 1; i <length ; i++) {
                if (snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i]){
                    isFail=true;
                }
            }

            repaint();//重画页面
        }
        timer.start();//定时器开启

    }

    @Override
    public void keyTyped (KeyEvent e){}   // 直接实现接口,最为暴力
    @Override
    public void keyReleased (KeyEvent e){}

}

package snake;

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

public class Data {
    // 相对路径  picture.png
    // 绝对路径: / 相当于当前的项目
    // 获得头部的素材
    public static URL headerURL = Data.class.getResource("statics/header.png");
    public static ImageIcon header = new ImageIcon(headerURL);
    //上下左右
    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);
    //身体还有食物
    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);
}