圖片素材
實現代碼
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.io.IOException;public class BackGroundView extends JPanel {BufferedImage bgImage; //背景圖片BufferedImage groundImg;//地面圖片BufferedImage imgStart;//開始游戲圖片BufferedImage imgEnd;//GameOVer圖片public int bg_width;//背景圖片寬度public int bg_height;//背景圖片高度public int ground_width;//地面圖片寬度public int ground_height;//地面圖片高度public int ground_x,ground_y;//地面繪制起始坐標public int speed = 0;//管道和地面移動的速度public int state = 0;//游戲狀態,0表示未開始,1表示正在玩,2表示GameOverpublic static final int MOVE_SPEED1 = 50;// 地面及柱子移動初始速度,當積分累加,速度會遞增public static final int jframeWidth = 432;//窗口寬度(bg.png寬度)public static final int jframeHeight = 644;//窗口高度(bg.png高度)public static final String PATH_PIC = "\\pictures\\";public static final String PATH_BG = PATH_PIC + "bg.png";//背景圖片路徑public static final String PATH_GROUND = PATH_PIC + "ground.png";public static final String PATH_IMGSTART = PATH_PIC + "start.png";public static final String PATH_IMGEND = PATH_PIC + "gameover.png";public static final int FONT_SIZE = 30;//得分字體大小public static final int SCORE_X = 20;public static final int SCORE_Y = 40;public int score;public JFrame jframeMain;public GameBoard gameBoard;public Bird bird;public Pipe pipe1,pipe2;public BackGroundView(){initFrame();//初始化窗口}public void initFrame(){jframeMain = new JFrame("Flappy Bird");jframeMain.setSize(jframeWidth, jframeHeight);jframeMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jframeMain.setLocationRelativeTo(null);//居中顯示jframeMain.setResizable(false);//窗口Size固定gameBoard = new GameBoard();//初始化內部類GameBoardjframeMain.add(gameBoard);Thread moveAll = new Thread(gameBoard);moveAll.start();}//游戲面板class GameBoard extends JPanel implements Runnable{public GameBoard(){initGame();//初始化游戲}public void initGame(){//原則:先加載后繪制try{//1、加載背景圖片bgImage = ImageIO.read(this.getClass().getResource(PATH_BG));//根據當前路徑加載圖片進內存//獲取圖片寬度與高度bg_width = bgImage.getWidth();bg_height = bgImage.getHeight();System.out.println("bg_width:" + bg_width + ",bg_height:" + bg_height);//2、加載地面圖片,注意大的圖片要先加載,否則會遮住之前加載的groundImg = ImageIO.read(this.getClass().getResource(PATH_GROUND));ground_width = groundImg.getWidth();ground_height = groundImg.getHeight();ground_x = 0;ground_y = bg_height - ground_height;System.out.println("ground_width:" + ground_width + ",ground_height:" + ground_height);System.out.println("ground_x:" + ground_x + ",ground_y:" + ground_y);//3、加載開始和結束圖片imgStart = ImageIO.read(this.getClass().getResource(PATH_IMGSTART));imgEnd = ImageIO.read(this.getClass().getResource(PATH_IMGEND));//4、加載小鳥圖片,并在繪制中繪制小鳥,在run中讓小鳥飛動bird = new Bird();//5、加載管道圖片,一個窗口中最多顯示兩個管道pipe1 = new Pipe(bg_width, bg_height, ground_height);pipe1.x = bg_width;//第一根管道位置pipe2 = new Pipe(bg_width, bg_height, ground_height);pipe2.x = bg_width + Pipe.PIPE_DISTANCE;//第二跟管道位置}catch (IOException e){ }//3、讓地面移動speed = MOVE_SPEED1;//速度初始化}@Overridepublic void run() {action();//處理鍵盤事件//移動while(true){try{if (state == 0) {groundMove();//地面移動,初始化窗口未開始游戲地面和小鳥就要動bird.fly();//小鳥飛動}else if (state == 1){groundMove();//地面移動,初始化窗口未開始游戲地面和小鳥就要動bird.fly();//小鳥飛動bird.down();//僅游戲開始時下降pipe1.move();//讓兩根管子動起來pipe2.move();//小鳥撞到地面,天空,柱子都GameOverif (bird.hitPipe(pipe1) || bird.hitPipe(pipe2) || bird.hitGround(bg_height, ground_height) || bird.hitSky()){state = 2;}else {if (bird.addScore(pipe1) || bird.addScore(pipe2)){//每次通過一個得分加10分,速度也增加score += 10;speed += 2;}}}else if (state == 2){}Thread.sleep(1000 / speed);//speed越大線程休眠時間越少,執行次數越多,速度就越快this.repaint();//刷新,會自動重新調用paint()方法}catch (InterruptedException e){ }}}public void groundMove(){ground_x--;//地面左移,可以實現小鳥右移if (ground_x == bg_width - ground_width + 9){//9為修正值,自己調的,保證移動更流暢ground_x = 0;}}public void action(){//設置監聽事件this.addMouseListener(new MouseAdapter() {@Overridepublic void mouseClicked(MouseEvent e) {super.mouseClicked(e);switch(state){case 0://游戲未開始點擊,就切換為開始游戲state = 1;bird.x = Bird.BIRD_FLY_X;bird.y = Bird.BIRD_FLY_Y;break;case 1://游戲開始bird.up();//游戲中點擊就是上升break;case 2://切換到未開始狀態,得分清零,小鳥與管道位置重置state = 0;score = 0;bird.x = Bird.BIRD_X;bird.y = Bird.BIRD_Y;pipe1.x = bg_width;pipe2.x = bg_width + Pipe.PIPE_DISTANCE;break;default:break;}}});}@Overridepublic void paint(Graphics g) {super.paint(g);//System.out.println("paint方法被調用時間:" + getCurrentTime());g.drawImage(bgImage,0,0,null);//繪制背景if (state == 0){//游戲未開始g.drawImage(imgStart,0,0,null);g.drawImage(bird.img, bird.x, bird.y, null);}else if (state == 1){//游戲開始g.drawImage(bird.img, bird.x, bird.y, null);//點擊開始后,初始坐標也同時變g.drawImage(pipe1.img, pipe1.x, pipe1.y, null);g.drawImage(pipe2.img, pipe2.x, pipe2.y, null);}else if (state == 2){//游戲結束g.drawImage(imgEnd,0,0,null);}g.drawImage(groundImg , ground_x, ground_y, null);//繪制地面//繪制分數Graphics2D gg = (Graphics2D) g;Font scoreFont = new Font("微軟雅黑", Font.BOLD, FONT_SIZE);//得分字體//下面兩句是抗鋸齒模式,消除文字鋸齒,字體更清晰順滑gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);gg.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);gg.setFont(scoreFont);gg.setColor(Color.WHITE);gg.drawString("" + score, SCORE_X, SCORE_Y);}//當前時間public String getCurrentTime() {Date day = new Date();SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");return df.format(day);}}public void showView(){jframeMain.setVisible(true);}
}
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;//小鳥類
public class Bird {public static final int BIRD_PIC_COUNT = 8;//小鳥圖片個數,8張圖片輪播形成飛行時的樣子public static final int BIRD_X = 190;//初始化小鳥坐標(游戲未開始小鳥位置)public static final int BIRD_Y = 220;public static final int BIRD_FLY_X = 120;//開始游戲后小鳥初始坐標public static final int BIRD_FLY_Y = 240;public static final int BIRD_UP_SPEED = 6;public static int index = 0;//當前小鳥圖片序號public int x,y;//小鳥坐標public int width;//小鳥寬度public int height;//小鳥高度public double g = 9.8;//重力加速度public double t = 0.05;//自然下降時間public double v,h;//下降速度與下降距離BufferedImage img;BufferedImage[] imgs = new BufferedImage[BIRD_PIC_COUNT];public Bird(){try{for (int i = 0; i < 8; i++) {imgs[i] = ImageIO.read(this.getClass().getResource(BackGroundView.PATH_PIC + i + ".png"));}img = imgs[0];//獲取小鳥寬高width = img.getWidth();height = img.getHeight();//初始化小鳥位置x = BIRD_X;y = BIRD_Y;}catch (IOException e){ }}// 小鳥飛翔的圖片切換public void fly() {index++;// 小鳥圖形切換的頻率,index/x,x越大,翅膀切換頻率越慢,index到48完成一次輪播img = imgs[index / 6 % BIRD_PIC_COUNT];//除以6是調整速度if (index == 6 * BIRD_PIC_COUNT) {index = 0;}}//上升public void up(){v = BIRD_UP_SPEED;//上升,鼠標點擊小鳥上升20}//下降public void down() {v = v - g*t;// Vt=Vo-gth = v - g*t*t/2;// h=Vot-gt2/2y = y - (int)h;}// 碰撞檢測// 是否碰撞地面public boolean hitGround(int bg_height, int ground_height) {if (y + height >= (bg_height - ground_height)) {return true;}return false;}// 碰撞到舞臺頂部public boolean hitSky() {if (y <= 0) {return true;}return false;}// 碰到柱子時的檢測public boolean hitPipe(Pipe p) {// x方向小鳥和柱子碰撞的條件if ((x + width) >= p.x && x <= p.x + p.width) {if (y <= p.y + (p.height - Pipe.PIPE_GAP) / 2|| y >= p.y + (p.height + Pipe.PIPE_GAP) / 2 - height) {return true;}}return false;}// 增加積分,通過管道后調用該方法public boolean addScore(Pipe p) {if (x == p.x + p.width) {return true;}return false;}
}
public class Main {public static void main(String[] args) {new BackGroundView().showView();}
}
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;public class Pipe {public static int PIPE_GAP = 144;//中間可通過的缺口大小public static int PIPE_DISTANCE = 244;//管道之間的間距BufferedImage img;//管道圖片public int x,y;//坐標public int width,height;//柱子寬高private int max, min;//保證管道完全能顯示在屏幕上,所以要設置max與minRandom random = new Random();//管道隨機出現public int bg_width;public Pipe(int bg_width, int bg_height, int ground_height){this.bg_width = bg_width;try{img = ImageIO.read(this.getClass().getResource(BackGroundView.PATH_PIC + "pipe.png"));width = img.getWidth();height = img.getHeight();System.out.println("Pipe_width = " + width + ",Pipe_height = " + height);//width=74,height=1200x = bg_width;//管道在不在初始背景出現,在背景"右邊"max = (height - PIPE_GAP) / 2;//圖片有上下兩管道,這個max表示一個管道的高度min = (height - PIPE_GAP) / 2 - (bg_height - PIPE_GAP - ground_height);//管道出現的最小長度y = -(min + random.nextInt(max - min));//管道隨機出現的坐標}catch (IOException e){ }}//游戲開始,柱子就要向左移動public void move(){x--;//若柱子走出最左邊窗口,管道就重新初始化if (x == -width){x = bg_width;y = -(min + random.nextInt(max - min));//管道隨機出現的坐標}}}
?游戲界面與實現效果
?