欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實(shí)現(xiàn)貪吃蛇游戲的示例代碼

 更新時間:2022年09月22日 11:01:41   作者:sid10t  
這篇文章主要為大家詳細(xì)介紹了如何利用Java實(shí)現(xiàn)簡單的貪吃蛇游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

項目演示

項目演示地址

項目實(shí)戰(zhàn)

1. 游戲的主啟動類

作為貪吃蛇游戲的主啟動類,構(gòu)建了頂級窗口,可以容納各種面板,

package Snake;

import javax.swing.*;

/**
 * 游戲的主啟動類
 */
public class StartGame {
    public static void main(String[] args) {
        JFrame frame = new JFrame();

        frame.setBounds(10,10,900,720);
        frame.setResizable(false);  //窗口大小不可變
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        //正常游戲界面都應(yīng)該在面板上

        frame.setVisible(true);
    }
}

2. 游戲的面板

若是沒有super.paintComponent(g);,則會出現(xiàn)閃屏,

在主啟動類StartGame中添加frame.add(new GamePanel());,

package Snake;

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

/**
 * 游戲的面板
 */
public class GamePanel extends JPanel {
    //繪制面板,游戲中所有東西都用這個畫筆來畫
    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);    //清屏
        this.setBackground(Color.BLACK);
    }
}

3. 數(shù)據(jù)中心

創(chuàng)建一個Data類作為數(shù)據(jù)中心,用于調(diào)用statics包里的資源,

package Snake;

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

/**
 * 數(shù)據(jù)中心,用于調(diào)用資源
 */
public class Data {
    public static URL headerURL = Data.class.getResource("/statics/header.png");
    public static ImageIcon header = new ImageIcon(headerURL);

    public static URL downURL = Data.class.getResource("/statics/down.png");
    public static URL leftURL = Data.class.getResource("/statics/left.png");
    public static URL rightURL = Data.class.getResource("/statics/right.png");
    public static URL upURL = Data.class.getResource("/statics/up.png");
    public static ImageIcon up = new ImageIcon(upURL);
    public static ImageIcon down = new ImageIcon(downURL);
    public static ImageIcon left = new ImageIcon(leftURL);
    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);
}

4. 繪制靜態(tài)面板

GamePanel類中,構(gòu)建一個初始的靜態(tài)面板,添加如下代碼,

/**
 * 繪制靜態(tài)面板
 */
this.setBackground(Color.WHITE);
Data.header.paintIcon(this,g,25,11);    //頭部廣告欄
g.fillRect(25,75,850,600);    //默認(rèn)游戲界面

5. 繪制靜態(tài)小蛇

依然是在類GamePanel中,先是繪制好小蛇的初始形態(tài),

//定義蛇的數(shù)據(jù)結(jié)構(gòu)
int length;     //蛇的長度
int[] snakeX = new int[600];    //蛇的x坐標(biāo) 25*25
int[] snakeY = new int[500];    //蛇的y坐標(biāo) 25*25

//構(gòu)造器
public GamePanel(){
    init();
}

//初始化方法
public void init(){
    length = 3;
    snakeX[0] = 100; snakeY[0] = 100;    //蛇腦袋的坐標(biāo)
    snakeX[1] = 75; snakeY[1] = 100;    //蛇第一節(jié)身體的坐標(biāo)
    snakeX[2] = 50; snakeY[2] = 100;    //蛇第二節(jié)身體的坐標(biāo)
}

然后再把繪制好的小蛇畫到面板上去,即在paintComponent(Graphics g)方法中添加如下代碼,

/**
 * 繪制靜態(tài)小蛇
 */
Data.right.paintIcon(this,g,snakeX[0],snakeY[0]);    //蛇腦袋的坐標(biāo)
Data.body.paintIcon(this,g,snakeX[1],snakeY[1]);    //蛇第一節(jié)身體的坐標(biāo)
Data.body.paintIcon(this,g,snakeX[2],snakeY[2]);    //蛇第二節(jié)身體的坐標(biāo)

6. 繪制動態(tài)小蛇

小蛇在動起來之后,蛇頭會進(jìn)行上下左右的移動,身體也會變長,因此不能局限于固定的坐標(biāo),需要對靜態(tài)小蛇的代碼做如下改動,

添加一個名為fxString對象,存儲小蛇的方向,使用if語句進(jìn)行判斷,

對于小蛇身體節(jié)數(shù)的增長使用for循環(huán)語句進(jìn)行控制,

String fx;

//初始化方法
public void init(){
    length = 3;
    snakeX[0] = 100; snakeY[0] = 100;    //蛇腦袋的坐標(biāo)
    snakeX[1] = 75; snakeY[1] = 100;    //蛇第一節(jié)身體的坐標(biāo)
    snakeX[2] = 50; snakeY[2] = 100;    //蛇第二節(jié)身體的坐標(biāo)
    fx = "L";
}

/**
 * 繪制小蛇
 */
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]);    //蛇頭初始化向下,需要通過方向來判斷
}

for (int i = 1; i < length; i++) {
    Data.body.paintIcon(this,g,snakeX[i],snakeY[i]);    //蛇第一節(jié)身體的坐標(biāo)
}

7. 設(shè)置游戲狀態(tài)

游戲狀態(tài)主要分為開始停止兩種,我們默認(rèn)游戲狀態(tài)為停止,

依舊是在類GamePanel中進(jìn)行設(shè)置,

添加一個boolean對象,

//游戲狀態(tài):開始,停止
boolean isStart = false;    //默認(rèn)游戲不開始

paintComponent(Graphics g)方法中添加如下代碼,

/**
 * 游戲狀態(tài)
 */
if(isStart == false){
    g.setColor(Color.CYAN);
    g.setFont(new Font("微軟雅黑",Font.BOLD,40));   //設(shè)置字體
    g.drawString("按下空格開始游戲",300,350);
}

8. 讓蛇動起來

讓蛇能夠動起來就是為程序添加監(jiān)聽事件,內(nèi)部類或者外部類都可,  

空格鍵獲得響應(yīng)

設(shè)置鍵盤的監(jiān)聽事件,先設(shè)置空格的監(jiān)聽事件,

接上接口KeyListener,重寫它的三個方法,

//鍵盤監(jiān)聽事件
@Override
public void keyPressed(KeyEvent e){
    int keyCode = e.getKeyCode();   //獲得鍵盤按鍵是哪一個
    if (keyCode == KeyEvent.VK_SPACE){      //如果按下空格鍵
        isStart = !isStart;     //取反
        repaint();
    }
}

@Override
public void keyTyped(KeyEvent e) {

}

@Override
public void keyReleased(KeyEvent e) {

}

在構(gòu)造器中獲取焦點(diǎn)和鍵盤事件,鼠標(biāo)在范圍內(nèi)獲取焦點(diǎn),離開范圍則失去焦點(diǎn),

//構(gòu)造器
public GamePanel(){
    init();
    //獲得焦點(diǎn)和鍵盤事件
    this.setFocusable(true);    //獲得焦點(diǎn)事件
    this.addKeyListener(this);  //獲得鍵盤監(jiān)聽事件
}

初始化狀態(tài)

點(diǎn)擊空格后

設(shè)置定時器

通過對固定事件的高頻率刷新,實(shí)現(xiàn)動畫效果,即創(chuàng)建定時器Timer,

    //定時器,以ms為單位,1s = 1000ms
    Timer timer = new Timer(100, this);     //100毫秒執(zhí)行一次

接下來設(shè)置事件監(jiān)聽,先以右移為例,

//事件監(jiān)聽——需要通過固定事件來刷新,比如10次/s
@Override
public void actionPerformed(ActionEvent e) {
    if(isStart){    //如果游戲是開始狀態(tài),就讓小蛇動起來
        //右移
        for (int i = length-1; i > 0; i--) {    //后一節(jié)移動到前一節(jié)的位置 snakeX[1] = snakeX[0];
            snakeX[i] = snakeX[i-1];
            snakeY[i] = snakeY[i-1];
        }
        snakeX[0] += 25;

        //邊界判斷
        if (snakeX[0] > 850){
            snakeX[0] = 25;
        }

        repaint();  //重畫頁面
    }
    timer.start();  //定時器開啟
}

同時不要忘記在構(gòu)造器中添加啟動語句timer.start();,啟動程序,

方向鍵獲得響應(yīng)

在鍵盤監(jiān)聽事件keyPressed(KeyEvent e)中,添加上下左右鍵盤監(jiān)聽,類似于空格鍵獲得的響應(yīng),

/**
 * 小蛇移動
 */
if(keyCode == KeyEvent.VK_UP){
    fx = "U";
}else if (keyCode == KeyEvent.VK_DOWN){
    fx = "D";
}else if (keyCode == KeyEvent.VK_LEFT){
    fx = "L";
}else if (keyCode == KeyEvent.VK_RIGHT){
    fx = "R";
}

然后再對定時器進(jìn)行修改,

//事件監(jiān)聽——需要通過固定事件來刷新,比如10次/s
@Override
public void actionPerformed(ActionEvent e) {
    if(isStart){    //如果游戲是開始狀態(tài),就讓小蛇動起來
        //移動
        for (int i = length-1; i > 0; i--) {    //后一節(jié)移動到前一節(jié)的位置 snakeX[1] = snakeX[0];
            snakeX[i] = snakeX[i-1];
            snakeY[i] = snakeY[i-1];
        }

        //走向
        if (fx.equals("R")){
            snakeX[0] = snakeX[0] + 25;
            if(snakeX[0] > 850){    //邊界判斷
                snakeX[0] = 25;
            }
        }else if (fx.equals("L")){
            snakeX[0] = snakeX[0] - 25;
            if(snakeX[0] < 25){    //邊界判斷
                snakeX[0] = 850;
            }
        }else if (fx.equals("U")){
            snakeY[0] = snakeY[0] - 25;
            if(snakeY[0] < 75){    //邊界判斷
                snakeY[0] = 650;
            }
        }else if (fx.equals("D")){
            snakeY[0] = snakeY[0] + 25;
            if(snakeY[0] > 650){    //邊界判斷
                snakeY[0] = 75;
            }
        }

        repaint();  //重畫頁面
    }
    timer.start();  //定時器開啟
}

9. 繪制食物布局

先是創(chuàng)建食物的坐標(biāo),

//食物的坐標(biāo)
int foodX;
int foodY;

在初始化方法中添加如下語句,隨機(jī)產(chǎn)生食物的位置,

//把食物隨機(jī)分布在界面上
foodX = 25 + 25*random.nextInt(34);
foodY = 75 + 25*random.nextInt(24);

在繪制面板方法paintComponent(Graphics g)中,將食物畫上去,

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

再在事件監(jiān)聽actionPerformed(ActionEvent e)中,將小蛇吃了食物會使身體變長的語句寫上去,

//吃食物
if (snakeX[0] == foodX && snakeY[0] == foodY){
    length++;   //小蛇身體長度增加一節(jié)
    //再次隨機(jī)分配食物
    foodX = 25 + 25*random.nextInt(34);
    foodY = 75 + 25*random.nextInt(24);
}

10. 游戲失敗判定

先設(shè)置一個失敗標(biāo)志,

//游戲失敗判定
boolean isFail = false;     //游戲失敗狀態(tài)

然后在繪制畫板paintComponent(Graphics g)中設(shè)置一個失敗回顯,

 if (isFail){
    g.setColor(Color.RED);
    g.setFont(new Font("微軟雅黑",Font.BOLD,40));   //設(shè)置字體
    g.drawString("游戲結(jié)束,按下空格重新開始",300,350);
}

再在鍵盤監(jiān)聽事件keyPressed(KeyEvent e)里重寫空格鍵的監(jiān)聽事件,

 if (keyCode == KeyEvent.VK_SPACE){      //如果按下空格鍵
    if(isFail){
        //重新開始
        isFail = false;
        init();
    }else {
        isStart = !isStart;     //取反
    }
    repaint();
}

然后再在事件監(jiān)聽actionPerformed(ActionEvent e)中再寫對失敗的判斷,

//失敗判定,撞到自己游戲結(jié)束
for (int i = 1; i < length; i++) {
    if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]){
        isFail = true;
    }
}

11. 積分獲取系統(tǒng)

先定義一個用于存儲積分的對象score,然后在繪制面板paintComponent(Graphics g)中顯示出積分來,

 /**
 * 顯示積分
 */
g.setColor(Color.white);
g.setFont(new Font("微軟雅黑",Font.BOLD,18));   //設(shè)置字體
g.drawString("長度: "+length,750,30);
g.drawString("分?jǐn)?shù): "+score,750,55);

然后重寫事件監(jiān)聽actionPerformed(ActionEvent e)里的吃食物代碼塊,

//吃食物
if (snakeX[0] == foodX && snakeY[0] == foodY){
    //小蛇身體長度增加一節(jié)
    length++;
    //一個食物加十點(diǎn)積分
    score += 10;
    //再次隨機(jī)分配食物
    foodX = 25 + 25*random.nextInt(34);
    foodY = 75 + 25*random.nextInt(24);
}

12. 游戲優(yōu)化

移動優(yōu)化

對蛇頭的移動進(jìn)行了優(yōu)化,避免了蛇頭與第一節(jié)蛇身的碰撞,即如果蛇頭向右前進(jìn),這時候按向左是無效的,

/**
 * 小蛇移動
 */
if(keyCode == KeyEvent.VK_UP && !fx.equals("D")){
    fx = "U";
}else if (keyCode == KeyEvent.VK_DOWN && !fx.equals("U")){
    fx = "D";
}else if (keyCode == KeyEvent.VK_LEFT && !fx.equals("R")){
    fx = "L";
}else if (keyCode == KeyEvent.VK_RIGHT && !fx.equals("L")){
    fx = "R";
}

速度優(yōu)化

隨著蛇身越來越長,小蛇移動速度會越來越快,這里蛇身每增加5節(jié),速度提升一個等級,

//判斷是否吃到食物
boolean foodEat = false;

//蛇身越長,蛇的移動速度越快
if (foodEat == true && length % 5 ==0 && foodColor.equals("Blue")){
    grade++;
}
timer.setDelay(150 -  grade*10);

食物優(yōu)化

避免食物的位置與蛇身的位置重疊,而造成食物被蛇身所覆蓋,

因此修改原先的食物分配布局,加入判定代碼塊,

//判斷食物是否與蛇身重疊
boolean flag = false;       //默認(rèn)為重疊狀態(tài)

//把食物隨機(jī)分布在界面上
while (flag == false){
    flag = true;
    foodX = 25 + 25*random.nextInt(34);
    foodY = 75 + 25*random.nextInt(24);
    for (int i = 1; i < length; i++) {
        if(foodX == snakeX[i] && foodY == snakeY[i]){
            flag = false;
        }
    }
}

對食物的種類進(jìn)行多樣化,每種顏色代表不同的功能,其中,

藍(lán)色:增加一節(jié)蛇的身體,分?jǐn)?shù)+10 綠色:減少一節(jié)蛇的身體,分?jǐn)?shù)+10 紫色:加快蛇的移動速度,分?jǐn)?shù)+10 橘色:減慢蛇的移動速度,分?jǐn)?shù)+10

通過隨機(jī)數(shù)對食物種類進(jìn)行分配,其中,

藍(lán)色:[0.1,0.85) 綠色:[0.85,0.95) 且蛇的長度length>=2 紫色:[0,0.1) 且timerDelay值>=80 橘色:[0.95,1) 且timerDelay值<=100

 //食物的種類
String foodColor;
boolean foodFlag = false;
public static URL foodURL;
public static ImageIcon food;

foodFlag = false;
while (foodFlag == false){
    double num = random.nextDouble();
    if(0.1 <= num && num < 0.85){
        foodURL = GamePanel.class.getResource("statics/foodB.png");
        foodColor = "Blue";
        foodFlag = true;
        break;
    }else if (0.85 <= num && num < 0.95 && length >= 2){
        foodURL = GamePanel.class.getResource("statics/foodG.png");
        foodColor = "Green";
        foodFlag = true;
        break;
    }else if (0.0 <= num && num < 0.1 && timer.getDelay() >= 90){
        foodURL = GamePanel.class.getResource("statics/foodP.png");
        foodColor = "Purple";
        foodFlag = true;
        break;
    }else if (0.95 <= num && num < 1.0 && timer.getDelay() <= 130){
        foodURL = GamePanel.class.getResource("statics/foodO.png");
        foodColor = "Orange";
        foodFlag = true;
        break;
    }
}
food = new ImageIcon(foodURL);

if (foodColor.equals("Blue")){
    //小蛇身體長度增加一節(jié)
    length++;
}else if (foodColor.equals("Green")){
    //如果蛇身長度正好是5的倍數(shù)會進(jìn)行降速處理
    if (length % 5 ==0){
        grade--;
    }
    //小蛇身體長度減少一節(jié)
    length--;
}else if (foodColor.equals("Purple")){
    //小蛇移動速度加快
    grade++;
}else if (foodColor.equals("Orange")){
    //小蛇移動速度加快
    grade--;
}

以上就是Java實(shí)現(xiàn)貪吃蛇游戲的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于Java貪吃蛇的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • K均值聚類算法的Java版實(shí)現(xiàn)代碼示例

    K均值聚類算法的Java版實(shí)現(xiàn)代碼示例

    這篇文章主要介紹了K均值聚類算法的Java版實(shí)現(xiàn)代碼示例,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • 關(guān)于@EnableGlobalMethodSecurity注解的用法解讀

    關(guān)于@EnableGlobalMethodSecurity注解的用法解讀

    這篇文章主要介紹了關(guān)于@EnableGlobalMethodSecurity注解的用法解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java線程阻塞工具LockSupport用法詳解

    Java線程阻塞工具LockSupport用法詳解

    Java中的LockSupport是一個用于線程同步的工具類,它提供了一種基于線程的阻塞和喚醒機(jī)制,LockSupport可以讓線程在特定條件下阻塞掛起,等待其他線程發(fā)送信號來喚醒它,本文將通過一個小案例給大家介紹一下LockSupport怎么用,讓你永遠(yuǎn)記住它
    2023-08-08
  • Java?String類和StringBuffer類的區(qū)別介紹

    Java?String類和StringBuffer類的區(qū)別介紹

    這篇文章主要介紹了Java?String類和StringBuffer類的區(qū)別,?關(guān)于java的字符串處理我們一般使用String類和StringBuffer類有什么不同呢,下面我們一起來看看詳細(xì)介紹吧
    2022-03-03
  • java如何將int數(shù)組轉(zhuǎn)化為Integer數(shù)組

    java如何將int數(shù)組轉(zhuǎn)化為Integer數(shù)組

    這篇文章主要介紹了java如何將int數(shù)組轉(zhuǎn)化為Integer數(shù)組,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Java RabbitMQ的TTL和DLX全面精解

    Java RabbitMQ的TTL和DLX全面精解

    過期時間TTL表示可以對消息設(shè)置預(yù)期的時間,在這個時間內(nèi)都可以被消費(fèi)者接收獲?。贿^了之后消息將自動被刪除。DLX, 可以稱之為死信交換機(jī),當(dāng)消息在一個隊列中變成死信之后,它能被重新發(fā)送到另一個交換機(jī)中,這個交換機(jī)就是DLX ,綁定DLX的隊列就稱之為死信隊列
    2021-09-09
  • IDEA mybatis-generator逆向工程生成代碼

    IDEA mybatis-generator逆向工程生成代碼

    這篇文章主要介紹了IDEA mybatis-generator逆向工程生成代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • Spring Boot 初始化運(yùn)行特定方法解析

    Spring Boot 初始化運(yùn)行特定方法解析

    這篇文章主要介紹了Spring Boot 初始化運(yùn)行特定方法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • 詳解Java目錄操作與文件操作教程

    詳解Java目錄操作與文件操作教程

    本章具體介紹了目錄操作、文件操作的基本使用方法和常用函數(shù),圖解穿插代碼實(shí)現(xiàn),感興趣的朋友來看看吧
    2022-03-03
  • SprinBoot整合Quart實(shí)現(xiàn)定時調(diào)度的示例代碼

    SprinBoot整合Quart實(shí)現(xiàn)定時調(diào)度的示例代碼

    這篇文章主要介紹了SprinBoot整合Quart實(shí)現(xiàn)定時調(diào)度的示例代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-10-10

最新評論