最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java實(shí)戰(zhàn)之飛翔的小鳥小游戲

 更新時間:2021年04月26日 14:58:58   作者:qq_42236679  
這篇文章主要介紹了Java實(shí)戰(zhàn)之飛翔的小鳥小游戲,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下

前言

一個簡單的單機(jī)小游戲:flypybird ,用來鞏固java基礎(chǔ)。

涉及主要知識點(diǎn):JFrame 、 JPanel 、 繼承、 鍵盤/鼠標(biāo)監(jiān)聽 、 多線程 、 工具類設(shè)計

 提示:這是大致的實(shí)現(xiàn)過程,實(shí)際實(shí)現(xiàn)過程有一定的修改,具體以源碼為準(zhǔn)。

一、大體思路

1、首先要有一個框架,作為主程序入口,這里使用 JFrame  類。

2、然后需要有一個畫布,用來把游戲場景畫上去,然后在上面添加鍵盤/鼠標(biāo)監(jiān)聽來控制,這里使用的是 JPenal 類。

3、需要創(chuàng)建幾個類:小鳥、地面、障礙物柱子、一個獲取圖片的工具類

4、然后逐步添加到畫布中,實(shí)現(xiàn)對應(yīng)的功能

二、具體步驟

2.1 創(chuàng)建窗體類

相當(dāng)于窗戶的框架,有了框架才能裝玻璃。然后也是主程序執(zhí)行的入口

2.1.1 具體代碼

public class MainFrame extends JFrame {
 
    /* 圖標(biāo) */
    BufferedImage Icon;
 
    /*
     * 構(gòu)造器用來初始化框架*/
    public MainFrame() throws IOException {
        /* 設(shè)置圖標(biāo) */
        Icon = ImageUtil.getImage("bird1_1.png");
        setIconImage(Icon);
        /* 設(shè)置關(guān)閉 */
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        /* 設(shè)置標(biāo)題 */
        setTitle("飛翔的小鳥");
        /* 設(shè)置尺寸*/
        setSize(298, 550);
        /* 設(shè)置大小不可變 */
        setResizable(false);
        /* 設(shè)置窗體居中 */
        setLocationRelativeTo(null);
    }
 
 
    /*
     * 主程序
     * */
    public static void main(String[] args) throws IOException {
        
        MainFrame mainFrame = new MainFrame();
        mainFrame.setVisible(true);
 
    }
}

2.1.2 效果展示

2.1.3 小結(jié)

大體框架做好,考慮到后面還需要使用比較多的圖片,因此接下來先建一個工具類,用來獲取圖片資源。

三、創(chuàng)建一個獲取圖片的工具類

3.1 具體代碼

/*
 * 工具類,用來獲取圖片
 * */
public class ImageUtil {
    public static BufferedImage getImage(String name) throws IOException {
       
        return ImageIO.read(new BufferedInputStream(new FileInputStream("birdGame/flyBird/" + name)));
    }
}

3.2 小結(jié)

圖片獲取方式改為用工具類獲取,只需要輸入圖片名+格式。后期方便減少重復(fù)代碼的書寫。

四、創(chuàng)建畫布

使用 Jpanel 類,創(chuàng)建畫布(相當(dāng)于玻璃) ,就能在上面畫游戲的畫面了。后期還需要在上面添加鼠標(biāo)/鍵盤監(jiān)聽。

4.1 具體代碼

public class GameJPenal extends JPanel {
    /*
     * 各種參數(shù)應(yīng)該設(shè)置在這
     * */
    BufferedImage bg; 
    
    /*
     * 構(gòu)造方法用來完成數(shù)據(jù)的初始化
     * */
    public GameJPenal() throws IOException {
        bg = ImageUtil.getImage("bg_day.png"); 
    }
    
    /*
     * 開始游戲的方法
     * */
    public void start() {
        gameStart = true;
        Thread myThread = new Thread(new MyThread());
        myThread.start();
    }
 
 
    //繪制的方法
    @Override
    public void paint(Graphics g) { 
        g.drawImage(bg, 0, 0, 288, 512, null);     //背景
       
    }
}

4.2 效果展示

先在main方法中創(chuàng)建對象,把畫布添加到框架里面,注意要重新在最后設(shè)置可見,否者看不到背景

/*
     * 主程序
     * */
    public static void main(String[] args) throws IOException {
 
        MainFrame mainFrame = new MainFrame();
 
        GameJPenal gameJPenal = new GameJPenal();
 
        mainFrame.add(gameJPenal);  /* 畫布添加到框架上 */
 
        mainFrame.setVisible(true);
 
        gameJPenal.requestFocus(); /* 請求屏幕焦點(diǎn) ,否則無法實(shí)現(xiàn)鍵盤監(jiān)聽 */
 
    }

接下來就可以運(yùn)行,效果如下

4.3 小結(jié)

這里需要注意一個點(diǎn)就是請求屏幕焦點(diǎn):后期如果要做鍵盤監(jiān)聽的話必須有焦點(diǎn),否則無法實(shí)現(xiàn)鍵盤控制

五、把地面畫上去

5.1 代碼

public class Ground {
    BufferedImage land;
    /*  x,y 是地面在畫布上的坐標(biāo) */ 
    private int x;
    private int y;
    private final int SPEED = 4;  //控制地面移動的速度
 
    public Ground() throws IOException {
        land = ImageUtil.getImage("land.png");
        x = 0;
        y = 512 - land.getHeight();
    }
 
    /*
     * 地面移動的效果
     * */
    public void move() {
        if (x == (288 - land.getWidth())) {
            x = 0;
        }
        x-=SPEED;
    }
 
    /*
    * get方法
    * */
    public int getX() {
        return x;
    }
 
    public int getY() {
        return y;
    }
}

接下來就是把地面的圖片用畫筆畫上去

 
g.drawImage(land.landImg, land.x, land.y, land.w, land.h, null);

六、創(chuàng)建一個新線程讓畫面動起來

先把變量添加到 GamePanel 類

Land land;    //地面
    Thread newThread;  //線程
    boolean gameStart; // 游戲狀態(tài)變量,準(zhǔn)備狀態(tài)為 false ,游戲開始為 true
    boolean gameOver;  //狀態(tài)變量, 游戲開始為false ,游戲結(jié)束為true

在GamePanel 構(gòu)造器里面初始化變量,創(chuàng)建一個新線程,用死循環(huán)不斷調(diào)用地面移動的方法,然后重畫畫面,實(shí)現(xiàn)移動的效果

這里還加了倆個游戲的狀態(tài)變量,主要是為了方便實(shí)現(xiàn)游戲的準(zhǔn)備畫面和游戲結(jié)束后可以重新開始游戲:

boolean gameStart;  //游戲準(zhǔn)備狀態(tài)
boolean gameOver;   //游戲結(jié)束狀態(tài)
/*
     * 新開一個線程
     * */
    class MyThread implements Runnable {
        @Override
        public void run() {
            while (true) {
                ground.move();
                c0.move();
                c1.move();
                bird.fly();
                bird.move();
                isGameOver();
                repaint();
                if (gameOver) {
                    return;
                }
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

小結(jié):

這時候畫面已經(jīng)能動起來了,接下來就是把其它的對象創(chuàng)建出來添加進(jìn)去:鳥 、 障礙物(柱子)

七、創(chuàng)建柱子類

 和創(chuàng)建地面類似,需要有他的坐標(biāo)點(diǎn)和高度,同時為了畫面柱子的連續(xù)性,需要倆組不同的柱子,

/*
 * 柱子類
 * */
public class Column {
 
    private final int SPEED = 2;
    int w1;
    int h1;
    int x1;
    int y1;
    BufferedImage img1;
 
    int w2;
    int h2;
    int x2;
    int y2;
    BufferedImage img2;
 
    /*
     * 構(gòu)造方法
     * 初始化對象*/
    public Column(int i) throws IOException {
 
        img1 = ImageUtil.getImage("pipe_down.png");
        w1 = img1.getWidth() / 2;
        h1 = img1.getHeight();
        x1 = 288 + i * 150;
        y1 = -100 - i * 20;
 
        img2 = ImageUtil.getImage("pipe_up.png");
        w2 = img2.getWidth() / 2;
        h2 = img2.getHeight();
        x2 = 288 + i * 150;
        y2 = h2 - i * 25 -20;
    }
 
    /*柱子移動的方法
     * */
    public void move() {
 
        if (x1 == -w1) {
            x1 = 288;
        }
        if (x2 == -w2) {
            x2 = 288;
        }
        x1 -= SPEED;
        x2 -= SPEED;
    }
}

八、實(shí)現(xiàn)柱子在畫布上的移動

和地面的初始化一樣,在畫布上添加成員變量,進(jìn)行初始化,接下來用畫筆在畫布上畫出來,在線程里面的死循環(huán)調(diào)用它移動的方法,實(shí)現(xiàn)柱子的移動

小結(jié):

接下來就是把小鳥添加到畫布上來

九、創(chuàng)建小鳥類

小鳥的x軸位置其實(shí)是固定的,因此小鳥只需要能在y軸移動就行,這一部分可以通過鼠標(biāo)活著鍵盤監(jiān)聽來控制

小鳥有一個扇翅膀的動作,通過把圖片存在一個集合里面,通過循環(huán),每次畫一個圖片,就能實(shí)現(xiàn)扇翅膀的效果

難點(diǎn):小鳥的上下移動的方法的設(shè)計

這里通過設(shè)計一個類似拋物線的動作,每次按下鍵盤Up,就改變它的上拋的初速度,讓小鳥往上飛,經(jīng)過時間 t 開始做落體運(yùn)動

public class Bird {
    private double v0;  /* 小鳥運(yùn)動的初速度 */
    double t;  /* 往上運(yùn)動的時間 */
    int s;   /* 往上運(yùn)動的路程 */
    int x;
    int y;
    int g;   /* 重力 */
    BufferedImage img;
    ArrayList<BufferedImage> list;  /* 裝三張不同動作的圖片 */
 
    public Bird() throws IOException {
        g = 3;
        v0 = 5;
        t = 0.3;
        img = ImageUtil.getImage("bird1_1.png");
        x = 100;
        y = 200;
        list = new ArrayList<>();
        list.add(ImageUtil.getImage("bird1_0.png"));
        list.add(ImageUtil.getImage("bird1_1.png"));
        list.add(ImageUtil.getImage("bird1_2.png"));
    }
 
    /*
     * 鳥飛的動作,通過改變每次畫不同動作的圖片來實(shí)現(xiàn)
     * */
    int i = 0;
    public void fly() {
        if (i >= 3) {
            i = 0;
        }
        img = list.get(i);
        i++;
    }
    /*
     * 鳥的上拋移動
     * */
    public void moveUP() {
        v0 = 10;
    }
    /*
     * 鳥的落體運(yùn)動*/
    public void move() {
        s= (int) (v0*t);
        y -= s;
        double v2 = v0 - g * t;
        v0 = v2;
    }
}

十、小鳥添加到畫布

和柱子一樣,不做贅述

效果如下:

十一、實(shí)現(xiàn)鍵盤監(jiān)聽

注意:實(shí)現(xiàn)加鍵盤監(jiān)聽需要畫布獲得焦點(diǎn)

方法1:main 方法中設(shè)置

gameJPenal.requestFocus();

方法2:直接在GamePanel 類設(shè)置

setFocusable(true);

主要代碼:

this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (gameOver) {
                    if (e.getKeyCode() == KeyEvent.VK_UP) {
                        gameOver = false;
                        gameStart = false;
                        try {
                            ground = new Ground();
                            c0 = new Column(0);
                            c1 = new Column(1);
                            bird = new Bird();
                          
                        } catch (IOException ioException) {
                            ioException.printStackTrace();
                        }
                    }
      
 
                } else if (gameStart) {
                    if (e.getKeyCode() == KeyEvent.VK_UP) {
                        bird.moveUP();
                    }
                } else {
                    start();
                }
            }
        });

十二、判斷游戲結(jié)束的方法

判斷游戲結(jié)束其實(shí)比較簡單,通過檢測小鳥的x, y 坐標(biāo)以及小鳥圖片的寬度與柱子的x , y 坐標(biāo)加上柱子的寬度做一個碰撞檢測

/*
     * 判定游戲是否結(jié)束的方法
     * */
    public void isGameOver() {
        //先判斷是否落地
        if (bird.y <= 0 || bird.y >= 512 - ground.land.getHeight() - bird.img.getHeight()) {
            gameOver = true;
        }
        //判斷是否撞柱子
        int bh = bird.img.getHeight();
        int bw = bird.img.getWidth();
        //c0.img1, c0.x1, c0.y1, c0.w1, c0.h1, null
        if (c0.x1 <= bird.x + bw && c0.x1 + c0.w1 >= bird.x && c0.y1 + c0.h1 >= bird.y) {
            gameOver = true;
        }
        if (c1.x1 <= bird.x + bw && c1.x1 + c1.w1 >= bird.x && c1.y1 + c1.h1 >= bird.y) {
            gameOver = true;
        }
        if (c0.x2 <= bird.x + bw && c0.x2 + c0.w2 >= bird.x && c0.y2 <= bird.y + bh) {
            gameOver = true;
        }
        if (c1.x2 <= bird.x + bw && c1.x2 + c1.w2 >= bird.x && c1.y2 <= bird.y + bh) {
            gameOver = true;
        }
    }
if (gameStart == false) {
            g.drawImage(imageStart, 50, 200, null);
        }
        if (gameOver == true) {
            g.drawImage(imageGameOver, 50, 200, null);

十三、游戲結(jié)束后回到準(zhǔn)備狀態(tài)

這里其實(shí)就是狀態(tài)重置,寫在在鍵盤監(jiān)聽事件里面,邏輯就是游戲結(jié)束,只要按了Up鍵,游戲就重置為準(zhǔn)備狀態(tài)。同時,在游戲 paint 方法中加一個判斷,不同的狀態(tài)對應(yīng)不同的圖片

if (gameOver) {
                    if (e.getKeyCode() == KeyEvent.VK_UP) {
                        gameOver = false;
                        gameStart = false;
                        try {
                            ground = new Ground();
                            c0 = new Column(0);
                            c1 = new Column(1);
                            bird = new Bird();
                            score = 0;
                        } catch (IOException ioException) {
                            ioException.printStackTrace();
                        }
                    }
                    repaint();

十四、統(tǒng)計分?jǐn)?shù)

分?jǐn)?shù)統(tǒng)計原理:小鳥的x坐標(biāo)和柱子的( x+w)相等,分?jǐn)?shù)就+1

if (bird.x == c0.x1 + c0.w1 || bird.x == c1.x1 + c1.w1) {
                    score++;
                }

總結(jié)

游戲結(jié)構(gòu)并不復(fù)雜,只需要逐步實(shí)現(xiàn)每個功能即可。然后用到的主要是一些比較基礎(chǔ)的知識,對于鞏固基礎(chǔ)知識還是有一定幫助的。

第一次寫博客,可能不夠精簡,可讀性不強(qiáng)。下次加油  。

到此這篇關(guān)于Java實(shí)戰(zhàn)之飛翔的小鳥小游戲的文章就介紹到這了,更多相關(guān)java飛翔的小鳥內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 如何從官網(wǎng)下載Hibernate jar包的方法示例

    如何從官網(wǎng)下載Hibernate jar包的方法示例

    這篇文章主要介紹了如何從官網(wǎng)下載Hibernate jar包的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-04-04
  • Java輸入輸出流復(fù)制文件所用時間對比

    Java輸入輸出流復(fù)制文件所用時間對比

    這篇文章主要介紹了Java輸入輸出流復(fù)制文件所用時間對比的相關(guān)資料,非常不錯,具有參考解決價值,需要的朋友可以參考下
    2016-08-08
  • spring中@ComponentScan自動掃描并指定掃描規(guī)則

    spring中@ComponentScan自動掃描并指定掃描規(guī)則

    本文主要介紹了spring中@ComponentScan自動掃描并指定掃描規(guī)則,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Java連接SAP RFC實(shí)現(xiàn)數(shù)據(jù)抽取的示例詳解

    Java連接SAP RFC實(shí)現(xiàn)數(shù)據(jù)抽取的示例詳解

    這篇文章主要為大家學(xué)習(xí)介紹了Java如何連接SAP RFC實(shí)現(xiàn)數(shù)據(jù)抽取的功能,文中的示例代碼講解詳細(xì),具有一定的參考價值,需要的可以了解下
    2023-08-08
  • 關(guān)于Mybatis-Plus字段策略與數(shù)據(jù)庫自動更新時間的一些問題

    關(guān)于Mybatis-Plus字段策略與數(shù)據(jù)庫自動更新時間的一些問題

    這篇文章主要介紹了關(guān)于Mybatis-Plus字段策略與數(shù)據(jù)庫自動更新時間的一些問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Spring事件發(fā)布監(jiān)聽,順序監(jiān)聽,異步監(jiān)聽方式

    Spring事件發(fā)布監(jiān)聽,順序監(jiān)聽,異步監(jiān)聽方式

    這篇文章主要介紹了Spring事件發(fā)布監(jiān)聽,順序監(jiān)聽,異步監(jiān)聽方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • 詳解Spring Boot Mysql 版本驅(qū)動連接池方案選擇

    詳解Spring Boot Mysql 版本驅(qū)動連接池方案選擇

    這篇文章主要介紹了詳解Spring Boot Mysql 版本驅(qū)動連接池方案選擇,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • SpringBoot部署與服務(wù)配置方式

    SpringBoot部署與服務(wù)配置方式

    這篇文章主要介紹了SpringBoot部署與服務(wù)配置方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • Java使用反射獲取字段屬性

    Java使用反射獲取字段屬性

    這篇文章主要為大家詳細(xì)介紹了Java如何利用反射實(shí)現(xiàn)獲取字段屬性值,文中的示例代碼講解詳細(xì),具有很好的參考價值,希望對大家有所幫助
    2023-06-06
  • Java使用正則表達(dá)式判斷獨(dú)立字符的存在(代碼示例)

    Java使用正則表達(dá)式判斷獨(dú)立字符的存在(代碼示例)

    通過使用正則表達(dá)式,我們可以更加靈活地判斷字符串中是否包含特定的字符,并且可以控制匹配的條件,如獨(dú)立的字符,這為我們處理字符串提供了更多的選擇和功能,這篇文章主要介紹了Java使用正則表達(dá)式判斷獨(dú)立字符的存在,需要的朋友可以參考下
    2023-10-10

最新評論

永靖县| 台东县| 从江县| 西华县| 同德县| 久治县| 台南市| 肇庆市| 辰溪县| 新乐市| 汝阳县| 佛教| 许昌县| 黑河市| 申扎县| 吉林省| 禹州市| 孟津县| 通榆县| 汕尾市| 广平县| 大化| 永吉县| 乌海市| 泊头市| 南皮县| 凤翔县| 林芝县| 新郑市| 虞城县| 遂溪县| 古交市| 新津县| 永顺县| 建水县| 象山县| 元谋县| 宣化县| 三河市| 扎兰屯市| 井陉县|