首頁  >  文章  >  Java  >  如何用Java實現貪吃蛇大作戰小遊戲

如何用Java實現貪吃蛇大作戰小遊戲

WBOY
WBOY轉載
2023-04-26 08:55:061743瀏覽

1.開發環境及遊戲展示

貪吃蛇大作戰在設計與實驗的過程中需要在Window 10系統中進行,並使用開發工具IntelliJ IDEA Community Edition 2020.3.2(jdk- 15)完成程式碼的編寫、編譯、調試、測試等工作。程式所需的組件如貪吃蛇的蛇頭、蛇身及背景圖片等均使用影像軟體Adobe Photoshop 2020製作。

1.1 遊戲主介面

如何用Java實現貪吃蛇大作戰小遊戲

1.2 移動介面

如何用Java實現貪吃蛇大作戰小遊戲

1.3 獎勵介面

1.遊戲達到50分:

如何用Java實現貪吃蛇大作戰小遊戲

#2.遊戲達到100分:

如何用Java實現貪吃蛇大作戰小遊戲

1.4 F加速功能介面

按下F時,速度提高到100。

如何用Java實現貪吃蛇大作戰小遊戲

1.5 死亡介面

如何用Java實現貪吃蛇大作戰小遊戲

#2.需求分析

貪吃蛇遊戲是小型益智遊戲,可用於人們日常的休閒、娛樂等場景。本次遊戲設計涉及一維數組、Swing中的常用元件、GUI中的事件處理(事件監聽器、鍵盤監聽器)、類別的封裝與繼承、static靜態變數、包裝類別、隨機數等方面的知識。

具體需求摘要如下:

1.初始化介面為800×800大小,且遊戲介面應保持在螢幕中央,視窗應有「貪吃蛇」字樣;

2.遊戲介面應有必要的提示文字,提示遊戲的得分和蛇的當前速度。開始介面應有操作提示文字(輕按空格遊戲以開始/暫停遊戲、按住F以加速),文字顏色應美觀;

3.在程式中初始化蛇的位置(靠近面板左側)、蛇的方向(預設向右)、蛇的長度(預設為3),並初始化食物的位置;

4.遊戲的開始與暫停的實現:透過空白鍵控制遊戲的開始與暫停;

5.蛇移動功能的實現:以W、S、A、D或↑、↓、←、→控制蛇的運動方向為上、下、左、右進行遊戲;

6.當蛇頭接觸活動外圍時:蛇頭接觸界面最右(左)端則從對稱的左(右)端出現,以此類推,當蛇頭接觸界面最上(下)端則從對稱的下(上)端出現;

7.蛇吃食物的功能的實現:遊戲過程中,蛇頭觸碰到食物時,即為吃食物。此時蛇的長度應加1,速度應增加10,得分增加10,並刷新食物的位置(隨機位置);

8.蛇加速功能的實現:當按住「F」鍵時,蛇加速運動,速度值達到100;當鬆開「F」鍵時,蛇恢復至預設速度10;

9.蛇的死亡判定:當蛇頭碰到蛇身時,蛇死亡,遊戲結束,介面靠近中央提示:「你的小蛇已經死亡,按下空格重新開始!」;

10.遊戲的獎勵機制的實現:當得分為10時,遊戲提示「Good !」字樣;當得分為50時,遊戲提示「Good!!!」字樣;當得分為100時,遊戲提示「Perfect!!!」字樣;當得分達到200時,則遊戲提示「無人能擋!!!」的字樣;以上提示字樣皆位於蛇頭;

基本操作表如下:

如何用Java實現貪吃蛇大作戰小遊戲

##3.系統設計

3.1 系統整體功能設計

此貪吃蛇程式大方向上包含貪吃蛇的移動功能、貪吃蛇的主動加速功能、遊戲規則判斷功能、主界面控制功能、貪吃蛇吃食物功能。其中貪吃蛇的移動功能中包含移動方向的按鍵控制以及貪吃蛇的自動移動;遊戲規則判斷功能包括蛇的死亡判斷、遊戲開始與暫停判斷以及越界規則;主界面控制功能包含蛇的初始化以及食物的初始化;貪吃蛇吃食物功能包括蛇身增長、蛇速度增加、積分增加和食物刷新位置。具體功能結構圖如下:

如何用Java實現貪吃蛇大作戰小遊戲

3.2 系統整體流程設計

開始進入貪吃蛇程式時先判斷是否按下空白鍵,如果按下空白鍵則遊戲開始。遊戲開始後判斷是否有按鍵輸入,若有按鍵輸入則依按鍵設定改變蛇的移動方向或進行加速操作;若沒有按鍵操作則蛇繼續保持原方向運動。在蛇運動過程中判斷蛇是否吃到食物,若吃到食物則遊戲得分加10,蛇的移動速度也相應增加;不管是否吃到食物都進行蛇是否死亡的判斷,若死亡則遊戲結束;若蛇沒有死亡則繼續判斷是否有空格輸入,若有則遊戲暫停,反之則繼續判斷按鍵,根據按鍵改變蛇的運動狀態,繼續遊戲,直到蛇死亡,遊戲結束。

如何用Java實現貪吃蛇大作戰小遊戲

4.功能設計

4.1 貪吃蛇移動及加速功能設計

貪吃蛇的移動功能主要依賴選擇語句和鍵盤監聽器來實現,用W、S、A、D或↑、↓、←、→控制蛇的運動方向為上、下、左、右進行遊戲。當按下F鍵時,蛇加速運動。

如何用Java實現貪吃蛇大作戰小遊戲

4.2 貪吃蛇吃食物加速及死亡判定功能的設計

在貪吃蛇吃食物以及死亡判定的過程中,使用到了以下參數:

  • Timer類別的一個參數:int 類型的time,程式中呼叫timer.setDelay(time)方法更改定時器的參數(time越小,蛇運動越快) ;

  • 記錄蛇死亡與否的參數:boolean 類型的isDied(true則蛇死,false則蛇活),預設為false;

  • #蛇的長度:int 類型的length(初始為3);

  • 積分參數:int 類型的score(初始為0),程式中透過循環控制每吃一次食物加10分;

  • 蛇頭的座標:int類型的snakeX[0]與snakeY[0],分別儲存蛇頭的橫縱座標;

  • #蛇身的座標:int[] 類型的snakeX[i]和snakeY[i],分別儲存每一節蛇身的橫縱座標(i≠0);

  • 食物的座標:int 類型的foodX,foodY,分別儲存食物的橫縱座標,foodX與foodY均為使用Random類中的nextInt()方法產生的隨機數,故食物的座標是隨機的。

以下使用上述參數時便不再贅述。

4.2.1 貪吃蛇吃食物加速功能的設計

當蛇頭的座標snakeX[0]與snakeY[0]分別與食物的座標foodX,foodY相等時,得分score增加10,蛇身長度length加1,Timer參數time減10,進而完成蛇吃到食物後的加分,蛇身加長及加速功能。此功能的流程設計圖如下:

如何用Java實現貪吃蛇大作戰小遊戲

4.2.2 貪吃蛇死亡判定功能的設計

當貪吃蛇吃到自己的時候蛇死亡,即蛇頭座標snakeX[0]與snakeY[0]分別與蛇身座標snakeX[i]和snakeY[i]相等時,蛇死亡。此時isDied=! isDied。

如何用Java實現貪吃蛇大作戰小遊戲

4.3 貪吃蛇主動加速功能的設計

#貪吃蛇的主動加速功能即在遊戲過程中按住F鍵,蛇的移動速度加快,若按住後放開,則蛇的速度恢復預設值。這主要透過GUI中的鍵盤監聽器來實現,實現了鍵盤監聽器的兩個方法,keyPressed()與keyReleased()分別監聽按下F鍵的操作和鬆開F鍵的操作。其次用到了參數time,程式中改變time的值透過呼叫timer.setDelay(time)方法(timer為Timer類別的一個物件)從而改變定時器的頻率,達到蛇速度加快的效果。

如何用Java實現貪吃蛇大作戰小遊戲

4.4 貪吃蛇獎勵機制功能的設計

#貪吃蛇獎勵機制功能主要使用了選擇結構以及透過paintComponent(Graphics g)方法中的畫筆工具來實現。當遊戲達到一定的得分時,程式會呼叫畫筆工具中的g.drawString(“XXX”,snakeX[0],snakeY[0])方法,在蛇頭位置繪製出提示文字。

如何用Java實現貪吃蛇大作戰小遊戲

5.專案結構與專案實作

5.1 專案結構與類別間關係

如何用Java實現貪吃蛇大作戰小遊戲

如何用Java實現貪吃蛇大作戰小遊戲

5.2 專案完整原始碼

5.2.1 Images類別

此類為靜態類,主要儲存貪吃蛇組件的圖片物件。

package snakegame;

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

//Images类用于封装图片路径以及获取图片(使用静态对象便于用类名直接访问)
public class Images {
    //将图片的路径封装成一个对象
    public static URL bodyURL=Images.class.getResource("/snake_images/body.jpg");
    public static URL backURL=Images.class.getResource("/snake_images/back.jpg");
    public static URL snakeDownURL=Images.class.getResource("/snake_images/snakeDown.jpg");
    public static URL snakeLeftURL=Images.class.getResource("/snake_images/snakeLeft.jpg");
    public static URL snakeRightURL=Images.class.getResource("/snake_images/snakeRight.jpg");
    public static URL snakeUpURL=Images.class.getResource("/snake_images/snakeUp.png");
    public static URL foodURL=Images.class.getResource("/snake_images/food.jpg");
    //将图片封装为程序中的对象
    public static ImageIcon bodyImg=new ImageIcon(bodyURL);
    public static ImageIcon backImg=new ImageIcon(backURL);
    public static ImageIcon snakeDownImg=new ImageIcon(snakeDownURL);
    public static ImageIcon snakeUpImg=new ImageIcon(snakeUpURL);
    public static ImageIcon snakeRightImg=new ImageIcon(snakeRightURL);
    public static ImageIcon snakeLeftImg=new ImageIcon(snakeLeftURL);
    public static ImageIcon foodImg=new ImageIcon(foodURL);
}

5.2.2 HighestScore

此類別實現歷史最高分功能。

package snakegame;

import org.w3c.dom.Text;

import java.io.*;

//该类用于给游戏添加历史最高分功能
public class HighestScore {
    static int score = 0;//最高分的存储

    public void highest() throws IOException {
        //得分为最高分时存储
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(String.valueOf(Text.class.getResourceAsStream("贪吃蛇大作战/score.txt"))));
        if (GamePanel.score > score) {
            score = GamePanel.score;
            String s1 = String.valueOf(score);
            bos.write(s1.getBytes());
        }
        bos.close();
    }

    //用于游戏开始时从文件读取最高分的值
    public void readHighest() throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(String.valueOf(Text.class.getResourceAsStream("贪吃蛇大作战/score.txt"))));
        byte[] bys = new byte[1024];
        int len;
        while ((len = bis.read(bys)) != -1) {
            System.out.print(new String(bys, 0, len));//测试用
            String s2 = new String(bys, 0, len);
            score = Integer.valueOf(s2);
        }
        bis.close();
    }
}

5.2.3 GamePanel類別

此類別用於繪製貪吃蛇遊戲面板,以及實現遊戲特定邏輯功能。

package snakegame;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.Random;

//贪吃蛇游戏面板的绘制
public class GamePanel extends JPanel {
    Timer timer;
    int time=100;
    static int score;//记录游戏分数
    //蛇属性部分
    boolean isDied;
    int length;//设置蛇长
    String direction;//蛇头朝向
    //分别储存蛇身的X,Y坐标
    int[] snakeX=new int[300];
    int[] snakeY=new int[300];
    //判断游戏是否开始
    boolean isStart=false;
    int foodX,foodY;//食物的X,Y坐标
    //贪吃蛇初始化方法
    public void init(){
        length=3;
        snakeX[0]=175;
        snakeY[0]=275;
        snakeX[1]=150;
        snakeY[1]=275;
        snakeX[2]=125;
        snakeY[2]=275;
        foodX=300;
        foodY=400;
        score=0;
        isDied=false;//蛇默认状态为活着
        direction="R";//U,D,L,R分别表示蛇头朝向上,下,左,右
    }

    //构造方法
    public GamePanel() throws IOException {
        init();

        if(GamePanel.score>HighestScore.score){
            new HighestScore().highest();
        }
        //焦点定位到当前面板
        this.setFocusable(true);
        //监听器的实现部分
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                super.keyPressed(e);
                int keyCode = e.getKeyCode();
                //按下空格以开始游戏,以及方向键的控制
                if (keyCode == KeyEvent.VK_SPACE) {
                    if(isDied){
                        init();
                    }else {
                        isStart = !isStart;
                        repaint();//重绘
                    }
                } else if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_W) {
                    direction = "U";
                } else if (keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_S) {
                    direction = "D";
                } else if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_A) {
                    direction = "L";
                } else if (keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_D) {
                    direction = "R";
                }
            }
        });
        //贪吃蛇加速功能的实现
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int keyCode=e.getKeyCode();
                if(keyCode==KeyEvent.VK_F){
                    time=10;
                    timer.setDelay(time);//按下F时加速
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
                int keyCode=e.getKeyCode();
                if(keyCode==KeyEvent.VK_F){
                    time=100;
                    timer.setDelay(time);//松开F键减速恢复默认速度
                }
            }
        });
        //对定时器进行初始化,并实现监听器
            timer = new Timer(time, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    //当游戏处于开始状态且蛇活着时蛇活动,且后一节身子到前一节身子的位置上(每一节身子为25乘25像素)
                    if (isStart && isDied == false) {
                        //蛇身运动部分
                        for (int i = length - 1; i > 0; i--) {
                            snakeX[i] = snakeX[i - 1];
                            snakeY[i] = snakeY[i - 1];
                        }
                        //蛇头运动部分
                        if ("D".equals(direction)) {
                            snakeY[0] += 25;
                        }
                        if ("U".equals(direction)) {
                            snakeY[0] -= 25;
                        }
                        if ("L".equals(direction)) {
                            snakeX[0] -= 25;
                        }
                        if ("R".equals(direction)) {
                            snakeX[0] += 25;
                        }
                        //防止超出边界
                        if (snakeX[0] > 750) {
                            snakeX[0] = 25;
                        }
                        if (snakeX[0] < 25) {
                            snakeX[0] = 750;
                        }
                        if (snakeY[0] < 100) {
                            snakeY[0] = 725;
                        }
                        if (snakeY[0] > 725) {
                            snakeY[0] = 100;
                        }
                        //吃食物的动作,吃食物加10分且蛇身变长,蛇的速度提升10
                        if ((snakeX[0] == foodX && snakeY[0] == foodY)) {
                            length++;//蛇身长度加1
                            foodX = (new Random().nextInt(30) + 1) * 25;//随机生成X坐标[25,750]
                            foodY = (new Random().nextInt(26) + 4) * 25;//随机生成Y坐标[100,725]
                            score += 10;//吃一次食物积分加10
                            try {
                                new HighestScore().highest();
                            } catch (IOException ioException) {
                                ioException.printStackTrace();
                            }
                            if(time>10)
                                timer.setDelay(time-=10);//吃一次食物速度增加10
                        }
                        //蛇的死亡机制判定
                        for (int i = 1; i < length; i++) {
                            if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
                                isDied = !isDied;
                            }
                        }
                        repaint();
                    }
                }
            });
            timer.start();//定时器启动
    }

    //绘制面板部分
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        //填充背景颜色
        this.setBackground(new Color(164, 219, 246));
        //绘制初始蛇头的图片(默认右方朝向)
        Images.backImg.paintIcon(this,g,10,10);
        //调整画笔的颜色并绘制一个矩形面板
        g.setColor(new Color(219,226,219));
        g.fillRect(10,70,770,685);
        //蛇头的绘制;上下左右不同情况
        if("L".equals(direction)){
            Images.snakeLeftImg.paintIcon(this,g,snakeX[0],snakeY[0]);
        }
        if("R".equals(direction)){
            Images.snakeRightImg.paintIcon(this,g,snakeX[0],snakeY[0]);
        }
        if("U".equals(direction)){
            Images.snakeUpImg.paintIcon(this,g,snakeX[0],snakeY[0]);
        }
        if("D".equals(direction)){
            Images.snakeDownImg.paintIcon(this,g,snakeX[0],snakeY[0]);
        }
        //蛇身的绘制
        for(int i=1;i<length;i++) {
            Images.bodyImg.paintIcon(this, g, snakeX[i], snakeY[i]);
        }
        //食物绘制
       Images.foodImg.paintIcon(this,g,foodX,foodY);
        //游戏的文字提示语
        if(!isStart&&!isDied){
            g.setColor(new Color(12, 191, 222));
            g.setFont(new Font("楷体",Font.BOLD,40));
            g.drawString("轻按空格以开始/暂停游戏!",150,330);
            g.setColor(new Color(246, 2, 31));
            g.setFont(new Font("宋体",Font.CENTER_BASELINE,30));
            g.drawString("按住F以加速",300,380);
        }
        //游戏的得分显示
        g.setColor(new Color(248, 4, 74));
        g.setFont(new Font("楷体",Font.BOLD,30));
        g.drawString("得分:"+score,420,90);
        //游戏的最高分展示模块
        try {
            new HighestScore().readHighest();
        } catch (IOException e) {
            e.printStackTrace();
        }
        g.setColor(new Color(183, 25, 238));
        g.setFont(new Font("楷体",Font.BOLD,30));
        g.drawString("历史最高分:"+HighestScore.score,10,90);
        //蛇的速度提示
        g.setColor(new Color(248, 136, 36));
        g.setFont(new Font("楷体",Font.BOLD,30));
        g.drawString("当前速度:"+String.valueOf(110-time),550,90);
        //游戏的奖励鼓励机制
        if(score==10){
            g.setColor(new Color(127, 232, 20));
            g.setFont(new Font("微软雅黑",Font.BOLD,50));
            g.drawString("Good!",snakeX[0],snakeY[0]);
        }
        else if(score==50){
            g.setColor(new Color(17, 231, 250));
            g.setFont(new Font("微软雅黑",Font.BOLD,50));
            g.drawString("Good!!!",snakeX[0],snakeY[0]);
        }else if(score==100){
            g.setColor(new Color(248, 196, 6));
            g.setFont(new Font("微软雅黑",Font.BOLD,50));
            g.drawString("Perfect!!!",snakeX[0],snakeY[0]);
        }else if(score==200){
            g.setColor(new Color(248, 245, 26));
            g.setFont(new Font("微软雅黑",Font.BOLD,50));
            g.drawString("无人能挡!!!",snakeX[0],snakeY[0]);
        }
        //小蛇死亡时面板的绘制
        if(isDied){
            g.setColor(new Color(6, 115, 248));
            g.setFont(new Font("微软雅黑",Font.BOLD,30));
            g.drawString("你的小蛇已经死亡,按下空格重新开始!",170,330);
        }
    }
}

5.2.4 Start類別

頁面的整體佈局與程式的入口。

package snakegame;

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

//贪吃蛇总体界面布局以及程序的主方法
public class Start {
    public static void main(String[] args) throws IOException {
        JFrame jf=new JFrame("贪吃蛇");
        //获取屏幕的大小,并使用数据使窗口位置居中
        int width= Toolkit.getDefaultToolkit().getScreenSize().width;
        int height= Toolkit.getDefaultToolkit().getScreenSize().height;
        jf.setBounds((width-800)/2,(height-800)/2,800,800);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setResizable(false);//设置窗口大小不能更改
        //添加GamePanel面板
        GamePanel panel=new GamePanel();
        jf.add(panel);
        jf.setVisible(true);
    }
}

以上是如何用Java實現貪吃蛇大作戰小遊戲的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除