一.準備工作
首先創建一個新的Java項目命名為“飛翔的鳥”,并在src中創建一個包命名為“com.qiku.bird",在這個包內分別創建4個類命名為“Bird”、“BirdGame”、“Column”、“Ground”,并向需要的圖片素材導入到包內。
二.代碼呈現
package com.qiku.bird;
?
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
?
/*
?* 小鳥類
?* */
public class Bird {
? ? int x;// 坐標
? ? int y;
? ? int width; // 寬高
? ? int height;
? ? BufferedImage image; // 圖片
? ? BufferedImage[] images; // 小鳥所有圖片
?
? ? public Bird() {
? ? ? ? // 初始化數組 保存八張圖片
? ? ? ? images = new BufferedImage[8];
? ? ? ? // 使用循環結構 將小鳥所有圖片 存入數組
? ? ? ? for (int i = 0; i < images.length; i++) {
? ? ? ? ? ? try {
? ? ? ? ? ? ? ? images[i] = ImageIO.read(Bird.class.getResourceAsStream(i + ".png"));
? ? ? ? ? ? } catch (IOException e) {
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? image = BirdGame.bird_image;
? ? ? ? width = image.getWidth();
? ? ? ? height = image.getHeight();
? ? ? ? x = 120;
? ? ? ? y = 240;
? ? }
?
? ? // 小鳥飛翔的方法
? ? int index = 0;
?
? ? public void fly() {
? ? ? ? image = images[index % images.length];
? ? ? ? index++;
? ? }
?
? ? // h = v * t + g * t * t / 2
? ? int g = 6; //重力加速度
? ? double t = 0.15; // 下落時間
? ? double v = 0; // 初速度
? ? double h = 0; // 下落距離
?
? ? //小鳥下落一次
? ? public void down() {
? ? ? ? h = v * t + g * t * t / 2; // 具體下落的距離
? ? ? ? v = v + g * t; // 末速度 = 當前速度 + 重力加速度 * 時間
? ? ? ? y += (int) h;
? ? }
?
? ? // 小鳥向上飛
? ? public void up() {
? ? ? ? // 給一個 負方向的初速度
? ? ? ? v = -30;
? ? }
? ? /*
? ? ?* 小鳥撞地面
? ? ?* */
? ? public boolean hitGround(Ground ground) {
? ? ? ? boolean isHit = this.y + this.height >= ground.y;
? ? ? ? return isHit;
? ? }
?
? ? // 小鳥撞天花板
? ? public boolean hitCeiling() {
? ? ? ? boolean isHit = this.y <= 0;
? ? ? ? return isHit;
? ? }
?
? ? // 小鳥撞柱子
? ? public boolean hitColumn(Column c) {
? ? ? ? boolean b1 = this.x + this.width >= c.x;
? ? ? ? boolean b2 = this.x <= c.x + c.width;
? ? ? ? boolean b3 = this.y <= c.y + c.height / 2 - c.gap / 2;
? ? ? ? boolean b4 = this.y + this.height >= c.y + c.height / 2 + c.gap / 2;
? ? ? ? // 滿足b1 b2表示水平方向 相撞 b1 b2 b3 同時滿足 撞上柱子 b1 b2 b4 同時滿足撞下柱子
? ? ? ? return b1 && b2 && (b3 || b4);
?
? ? }
?
}
package com.qiku.bird;
import javax.imageio.ImageIO;
import javax.swing.*;
?
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
?
/**
?* 游戲啟動類
?* 使用extends 關鍵字 繼承JPanel 畫板類 ==> 于是BirdGame 就具備了畫板類的功能
?*/
public class BirdGame extends JPanel {
? ? // ? ?定義游戲狀態
? ? public static final int START = 0; ?// 開始
? ? public static final int RUNNING = 1; ?// 運行
? ? public static final int GAME_OVER = 2; ?// 結束
? ? // 游戲當前狀態 默認0 開始狀態
? ? int state = START;
? ? int score = 0; //玩家得分
?
? ? static BufferedImage bg = null; // 背景圖片
? ? static BufferedImage start = null; //開始圖片
? ? static BufferedImage ground_image = null; // 地面
? ? static BufferedImage bird_image = null; // 小鳥
? ? static BufferedImage column_image = null; // 柱子
? ? static BufferedImage gameOver_image = null; // game游戲
?
? ? // 靜態代碼塊 一般用于加載靜態資源(視頻,音頻,圖片等)
? ? static {
? ? ? ? // 將本地的圖片bg.png讀取到程序中的bg
? ? ? ? try {
? ? ? ? ? ? bg = ImageIO.read(BirdGame.class.getResourceAsStream("bg.png"));
? ? ? ? ? ? start = ImageIO.read(BirdGame.class.getResourceAsStream("start.png"));
? ? ? ? ? ? ground_image = ImageIO.read(BirdGame.class.getResourceAsStream("ground.png"));
? ? ? ? ? ? column_image = ImageIO.read(BirdGame.class.getResourceAsStream("column.png"));
? ? ? ? ? ? bird_image = ImageIO.read(BirdGame.class.getResourceAsStream("0.png"));
? ? ? ? ? ? gameOver_image = ImageIO.read(BirdGame.class.getResourceAsStream("gameover.png"));
? ? ? ? } catch (IOException e) {
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
?
? ? Ground ground;//聲明地面
? ? Bird bird;
? ? Column column1;
? ? Column column2;
?
? ? // BirdGame 的構造方法
? ? public BirdGame() {
? ? ? ? bird = new Bird();
? ? ? ? ground = new Ground();
? ? ? ? column1 = new Column();
? ? ? ? column2 = new Column();
? ? ? ? // 柱子2的x坐標 = 柱子1的坐標基礎上+244保持水平間距
? ? ? ? column2.x = column1.x + column1.distance;
?
? ? }
?
? ? /*
? ? ?* 用于在畫板上繪制內容的方法
? ? ?* 想在畫板上顯示什么 在這個方法寫就行了
? ? ?* @param g 畫筆
? ? ?* ?*/
? ? @Override
?
? ? public void paint(Graphics g) {
? ? ? ? // g.fillRect(0,0,100,200); // 設置顏色落筆點 寬高
? ? ? ? g.drawImage(bg, 0, 0, null); // 畫背景
? ? ? ? if (state == START) {
? ? ? ? ? ? g.drawImage(start, 0, 0, null); ?// 開始圖片
? ? ? ? }
? ? ? ? g.drawImage(column1.image, column1.x, column1.y, null); // 畫柱子
? ? ? ? g.drawImage(column2.image, column2.x, column2.y, null); // 畫柱子2
? ? ? ? g.drawImage(bird.image, bird.x, bird.y, null); //小鳥圖片
? ? ? ? g.drawImage(ground.image, ground.x, ground.y, null); ?// 地面圖片
? ? ? ? if (state == GAME_OVER) {
? ? ? ? ? ? g.drawImage(gameOver_image, 0, 0, null); // 結束圖片
?
? ? ? ? }
? ? ? ? // 畫分數
? ? ? ? Font font = new Font("微軟雅黑", Font.BOLD, 25); // 創建字體
? ? ? ? g.setFont(font); ?// 給畫筆設置字體
? ? ? ? g.setColor(Color.BLACK); ?// 設置字體黑色顏色
? ? ? ? g.drawString("分數: ?" + score, 30, 50);
? ? ? ? g.setColor(Color.WHITE); ?// 設置字體白色顏色
? ? ? ? g.drawString("分數: ?" + score, 28, 48);
? ? }
?
? ? // 判斷小鳥與柱子是否相撞 游戲結束
? ? public boolean isGameOver() {
? ? ? ? boolean isHit = bird.hitGround(ground) || bird.hitCeiling() || bird.hitColumn(column1) || bird.hitColumn(column2);
? ? ? ? return isHit;
? ? }
?
?
? ? // 游戲流程控制的方法
? ? public void action() throws Exception {
? ? ? ? frame.addKeyListener(new KeyAdapter() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void keyPressed(KeyEvent e) {
? ? ? ? ? ? ? ? System.out.println(e.getKeyCode());
? ? ? ? ? ? ? ? if(e.getKeyCode() == 32){
? ? ? ? ? ? ? ? ? ? if (state == START) { ?// 如果是開始狀態 單擊轉換運行
? ? ? ? ? ? ? ? ? ? ? ? state = RUNNING;
? ? ? ? ? ? ? ? ? ? }
?
? ? ? ? ? ? ? ? ? ? if (state == RUNNING) {
? ? ? ? ? ? ? ? ? ? ? ? bird.up(); //小鳥上升
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? if (state == GAME_OVER) {
? ? ? ? ? ? ? ? ? ? ? ? bird = new Bird();
? ? ? ? ? ? ? ? ? ? ? ? column1 = new Column();
? ? ? ? ? ? ? ? ? ? ? ? column2 = new Column();
? ? ? ? ? ? ? ? ? ? ? ? column2.x = column1.x + column1.distance;
? ? ? ? ? ? ? ? ? ? ? ? score = 0;
? ? ? ? ? ? ? ? ? ? ? ? state = START;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? });
?
?
? ? ? ? // 給當前對象()添加鼠標單擊事件
? ? ? ? this.addMouseListener(new MouseAdapter() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void mouseClicked(MouseEvent e) { // 鼠標單擊執行代碼
? ? ? ? ? ? ? ? if (state == START) { ?// 如果是開始狀態 單擊轉換運行
? ? ? ? ? ? ? ? ? ? state = RUNNING;
? ? ? ? ? ? ? ? }
?
? ? ? ? ? ? ? ? if (state == RUNNING) {
? ? ? ? ? ? ? ? ? ? bird.up(); //小鳥上升
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if (state == GAME_OVER) {
? ? ? ? ? ? ? ? ? ? bird = new Bird();
? ? ? ? ? ? ? ? ? ? column1 = new Column();
? ? ? ? ? ? ? ? ? ? column2 = new Column();
? ? ? ? ? ? ? ? ? ? column2.x = column1.x + column1.distance;
? ? ? ? ? ? ? ? ? ? score = 0;
? ? ? ? ? ? ? ? ? ? state = START;
? ? ? ? ? ? ? ? }
?
? ? ? ? ? ? }
? ? ? ? });
?
? ? ? ? // 死循環 {}的代碼會一直反復執行
? ? ? ? while (true) {
? ? ? ? ? ? if (state == START) {
? ? ? ? ? ? ? ? ground.step(); // 地面移動
? ? ? ? ? ? ? ? bird.fly(); // 小鳥飛翔
? ? ? ? ? ? } else if (state == RUNNING) {
? ? ? ? ? ? ? ? ground.step(); // 地面移動
? ? ? ? ? ? ? ? column1.step(); // 柱子1移動
? ? ? ? ? ? ? ? column2.step(); // 柱子2移動
? ? ? ? ? ? ? ? bird.fly(); // 小鳥飛翔
? ? ? ? ? ? ? ? bird.down(); // 小鳥下落
? ? ? ? ? ? ? ? if (isGameOver() == true) {
? ? ? ? ? ? ? ? ? ? state = GAME_OVER;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? // 設置增加分數
? ? ? ? ? ? ? ? if (bird.x == column1.x + column1.width + 1 || bird.x == column2.x + column2.width + 1) {
? ? ? ? ? ? ? ? ? ? score +=5;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
?
? ? ? ? ? ? repaint(); //重畫 即重新執行paint 方法
? ? ? ? ? ? Thread.sleep(10); //每隔10毫秒,讓程序休眠一次
? ? ? ? }
? ? }
? ? static ?JFrame frame = new JFrame();
? ? // main方法 - 程序的入口(即:有main方法 程序才能運行)
? ? public static void main(String[] args) throws Exception {
? ? ? ? BirdGame game = new BirdGame(); // 創建畫板對象
? ? ? ? frame.setSize(432, 644);//設置寬高
? ? ? ? frame.setLocationRelativeTo(null); // 居中顯示
? ? ? ? frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 設置關閉窗口,同時使程序結束
? ? ? ? frame.setVisible(true); //設置可見性
? ? ? ? frame.add(game); // 將畫板放到畫框上
? ? ? ? frame.setTitle("飛翔的小鳥");// 設置標題
? ? ? ? frame.setResizable(false);// 設置不允許玩家拖動界面
?
? ? ? ? // 調用action
? ? ? ? game.action();
? ? }
?
}
package com.qiku.bird;
?
import java.awt.image.BufferedImage;
?
/*
?* 柱子類
?* */
public class Column {
? ? int x;// 坐標
? ? int y;
? ? int width; // 寬高
? ? int height;
? ? BufferedImage image; // 圖片
? ? int gap; //上下柱子之間的間隙
? ? int distance; //水平方向柱子之間的距離
? ? int min = -(1200 / 2 - 144 / 2);
? ? int max = 644 - 146 - 144 / 2 - 1200 / 2;
?
? ? public Column() {
? ? ? ? gap = 144;
? ? ? ? distance = 244;
? ? ? ? image = BirdGame.column_image;
? ? ? ? width = image.getWidth();
? ? ? ? height = image.getHeight();
? ? ? ? x = BirdGame.bg.getWidth();
? ? ? ? y = (int) (Math.random() * (max - min) + min);
?
? ? }
?
? ? public void step() {
? ? ? ? x--;
? ? ? ? if (x <= -width) {
? ? ? ? ? ? x = BirdGame.bg.getWidth();
? ? ? ? ? ? y = (int) (Math.random() * (max - min) + min);
? ? ? ? }
? ? }
}
?
package com.qiku.bird;
?
import java.awt.image.BufferedImage;
?
/*
* 地面類
* */
public class Ground {
? ? int x ;// 地面坐標
? ? int y ;
? ? int width ; // 地面的寬高
? ? int height;
? ? BufferedImage image; // 地面圖片
?
? ? public Ground(){
? ? ? ? image = BirdGame.ground_image;
? ? ? ? x = 0;
? ? ? ? y = BirdGame.bg.getHeight() - image.getHeight();
?
? ? ? ? width = image.getWidth();
? ? ? ? height = image.getHeight();
? ? }
? ? /*
? ? * 地面走一步的方法
? ? * */
? ? public void step(){
? ? ? ? x--;
? ? ? ? if(x <= 432 - width){
? ? ? ? ? ? x=0;
? ? ? ? }
? ? }
}
三.結果呈現