亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

項(xiàng)目演示

項(xiàng)目演示地址

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

1. 游戲的主啟動(dòng)類

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

package Snake;

import javax.swing.*;

/**
 * 游戲的主啟動(dòng)類
 */
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. 游戲的面板

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

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

package Snake;

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

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

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

創(chuàng)建一個(gè)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)建一個(gè)初始的靜態(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;     //蛇的長(zhǎng)度
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. 繪制動(dòng)態(tài)小蛇

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

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

對(duì)于小蛇身體節(jié)數(shù)的增長(zhǎng)使用for循環(huán)語(yǔ)句進(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]);    //蛇頭初始化向右,需要通過(guò)方向來(lái)判斷
}else if(fx.equals("L")){
    Data.left.paintIcon(this,g,snakeX[0],snakeY[0]);    //蛇頭初始化向左,需要通過(guò)方向來(lái)判斷
}else if(fx.equals("U")){
    Data.up.paintIcon(this,g,snakeX[0],snakeY[0]);    //蛇頭初始化向上,需要通過(guò)方向來(lái)判斷
}else if(fx.equals("D")){
    Data.down.paintIcon(this,g,snakeX[0],snakeY[0]);    //蛇頭初始化向下,需要通過(guò)方向來(lái)判斷
}

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è)置,

添加一個(gè)boolean對(duì)象,

//游戲狀態(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. 讓蛇動(dòng)起來(lái)

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

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

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

接上接口KeyListener,重寫它的三個(gè)方法,

//鍵盤監(jiān)聽事件
@Override
public void keyPressed(KeyEvent e){
    int keyCode = e.getKeyCode();   //獲得鍵盤按鍵是哪一個(gè)
    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í)器

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

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

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

//事件監(jiān)聽——需要通過(guò)固定事件來(lái)刷新,比如10次/s
@Override
public void actionPerformed(ActionEvent e) {
    if(isStart){    //如果游戲是開始狀態(tài),就讓小蛇動(dòng)起來(lái)
        //右移
        for (int i = length-1; i > 0; i--) {    //后一節(jié)移動(dòng)到前一節(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();  //重畫頁(yè)面
    }
    timer.start();  //定時(shí)器開啟
}

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

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

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

/**
 * 小蛇移動(dò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";
}

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

//事件監(jiān)聽——需要通過(guò)固定事件來(lái)刷新,比如10次/s
@Override
public void actionPerformed(ActionEvent e) {
    if(isStart){    //如果游戲是開始狀態(tài),就讓小蛇動(dòng)起來(lái)
        //移動(dòng)
        for (int i = length-1; i > 0; i--) {    //后一節(jié)移動(dòng)到前一節(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();  //重畫頁(yè)面
    }
    timer.start();  //定時(shí)器開啟
}

9. 繪制食物布局

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

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

在初始化方法中添加如下語(yǔ)句,隨機(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)中,將小蛇吃了食物會(huì)使身體變長(zhǎng)的語(yǔ)句寫上去,

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

10. 游戲失敗判定

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

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

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

 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)中再寫對(duì)失敗的判斷,

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

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

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

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

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

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

12. 游戲優(yōu)化

移動(dòng)優(yōu)化

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

/**
 * 小蛇移動(dòng)
 */
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)化

隨著蛇身越來(lái)越長(zhǎng),小蛇移動(dòng)速度會(huì)越來(lái)越快,這里蛇身每增加5節(jié),速度提升一個(gè)等級(jí),

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

//蛇身越長(zhǎng),蛇的移動(dòng)速度越快
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;
        }
    }
}

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

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

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

藍(lán)色:[0.1,0.85) 綠色:[0.85,0.95) 且蛇的長(zhǎng)度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")){
    //小蛇身體長(zhǎng)度增加一節(jié)
    length++;
}else if (foodColor.equals("Green")){
    //如果蛇身長(zhǎng)度正好是5的倍數(shù)會(huì)進(jìn)行降速處理
    if (length % 5 ==0){
        grade--;
    }
    //小蛇身體長(zhǎng)度減少一節(jié)
    length--;
}else if (foodColor.equals("Purple")){
    //小蛇移動(dòng)速度加快
    grade++;
}else if (foodColor.equals("Orange")){
    //小蛇移動(dòng)速度加快
    grade--;
}

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

相關(guān)文章

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

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

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

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

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

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

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

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

    這篇文章主要介紹了Java?String類和StringBuffer類的區(qū)別,?關(guān)于java的字符串處理我們一般使用String類和StringBuffer類有什么不同呢,下面我們一起來(lái)看看詳細(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ù)組,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Java RabbitMQ的TTL和DLX全面精解

    Java RabbitMQ的TTL和DLX全面精解

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

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

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

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

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

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

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

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

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

最新評(píng)論