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) {}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章