老Java程序员花一天时间写了个飞机大战,很舒服!
老Java程序員花1天時間做了個飛機大戰
熱門專欄推薦
【1】Java小游戲(俄羅斯方塊、飛機大戰、植物大戰僵尸等)
【2】JavaWeb項目實戰(圖書管理、在線考試、宿舍管理等)
【3】JavaScript精彩實例(飛機大戰、貪吃蛇、驗證碼等)
【4】Java小白入門200例
【5】從零學Java、趣學Java
【6】Idea從零到精通
系列目錄
1. Java俄羅斯方塊
2. 老Java程序員花2天寫了個連連看
3. 老Java程序員花一天時間寫了個飛機大戰
4. Java五子棋人機版
5. Java植物大戰僵尸
6. Java消消樂(天天愛消除)
7. Java貪吃蛇小游戲
8. Java掃雷小游戲
9. Java坦克大戰
引言:
前兩天我發現CSDN上有兩篇飛機大戰的文章異常火爆,各種指標都很高(閱讀、點贊、評論、收藏等),但都是python寫的,竟然不是我大Java,說實話作為老java選手,我心里是有那么一些失落的,難道我大java打飛機不行?就算大java打飛機不行,那我用單身30年的打飛機手速,我肯定行(反正我的代碼我做主,就是玩!),于是我決定一展伸手,用java寫了一個飛機大戰。我就問你們我打飛機行不行,我媳婦都說行,你們呢?歡迎我親愛的大Java選手們 點贊+評論+收藏!給我沖、沖、沖。。。
代碼實現
創建窗口
首先創建一個游戲窗體類GameFrame,繼承至JFrame,用來顯示在屏幕上(window的對象),每個游戲都有一個窗口,設置好窗口標題、尺寸、布局等就可以。
/** 游戲窗體類*/ public class GameFrame extends JFrame {public GameFrame() {setTitle("飛機大戰");//設置標題setSize(526, 685);//設定尺寸setLayout(new BorderLayout());setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//點擊關閉按鈕是關閉程序setLocationRelativeTo(null); //設置居中setResizable(false); //不允許修改界面大小} }創建面板容器GamePanel繼承至JPanel
package main;import java.awt.Graphics; import javax.swing.JFrame; import javax.swing.JPanel; /** 畫布類*/ public class GamePanel extends JPanel{GamePanel gamePanel=this;private JFrame mainFrame=null;//構造里面初始化相關參數public GamePanel(JFrame frame){this.setLayout(null);mainFrame = frame;mainFrame.setVisible(true);}@Overridepublic void paint(Graphics g) {} }再創建一個Main類,來啟動這個窗口,用來啟動。
package main; public class Main {//主類public static void main(String[] args) {GameFrame frame = new GameFrame();GamePanel panel = new GamePanel(frame);frame.add(panel);frame.setVisible(true);//設定顯示} }右鍵執行這個Main類,窗口建出來了
??
創建菜單及菜單選項
創建菜單
private void initMenu(){// 創建菜單及菜單選項jmb = new JMenuBar();JMenu jm1 = new JMenu("游戲");jm1.setFont(new Font("微軟雅黑", Font.BOLD, 15));// 設置菜單顯示的字體JMenu jm2 = new JMenu("幫助");jm2.setFont(new Font("微軟雅黑", Font.BOLD, 15));// 設置菜單顯示的字體JMenuItem jmi1 = new JMenuItem("開始新游戲");JMenuItem jmi2 = new JMenuItem("退出");jmi1.setFont(new Font("微軟雅黑", Font.BOLD, 15));jmi2.setFont(new Font("微軟雅黑", Font.BOLD, 15));JMenuItem jmi3 = new JMenuItem("操作說明");jmi3.setFont(new Font("微軟雅黑", Font.BOLD, 15));JMenuItem jmi4 = new JMenuItem("勝利條件");jmi4.setFont(new Font("微軟雅黑", Font.BOLD, 15));jm1.add(jmi1);jm1.add(jmi2);jm2.add(jmi3);jm2.add(jmi4);jmb.add(jm1);jmb.add(jm2);mainFrame.setJMenuBar(jmb);// 菜單Bar放到JFrame上jmi1.addActionListener(this);jmi1.setActionCommand("Restart");jmi2.addActionListener(this);jmi2.setActionCommand("Exit");jmi3.addActionListener(this);jmi3.setActionCommand("help");jmi4.addActionListener(this);jmi4.setActionCommand("win"); }實現ActionListener并重寫方法actionPerformed
actionPerformed方法的實現
創建背景
在GamePanel類中重寫paint方法,繪制背景圖即可
//繪圖方法 @Override public void paint(Graphics g) {gameHeight = this.getHeight();gameWidth = this.getWidth();//繪制背景g.drawImage((BufferedImage)imageMap.get("bg"), 0, -150, null); }開啟主線程
主線程,用來重繪頁面,重繪全部交給主線程,主線程調用 repaint方法就行,要產生動畫就要靠這個repaint。
//刷新線程,用來重新繪制頁面 private class RefreshThread implements Runnable {@Overridepublic void run() {while (startFlag) {repaint();try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}} }在GamePanel的構造里面啟動這個主線程
有了這個主線程刷新,待會我們更新飛機的位置,飛機就會移動,不需要另外的代碼去調用repaint方法了(這是我的做法,僅供參考)。
創建我方飛機
創建MyPlane類,屬性有坐標x、y,寬高、圖片、是否存活、是否可以移動等;方法主要有繪制、移動、射擊等。
public class MyPlane {private int x = 0;private int y = 0;private int width = 0;private int height = 0;private BufferedImage image = null;private GamePanel panel=null;private HashMap imageMap=null;private boolean alive=true;private boolean canMove=false;private int key=1;private HashMap boomImageMap=null;private boolean hitFlag=false;//正在碰撞public MyPlane(int x,int y,int width,int height,GamePanel panel) {this.x=x;this.y=y;this.width=width;this.height=height;this.panel=panel;this.imageMap=panel.imageMap;this.image=(BufferedImage)imageMap.get("myplane1");this.boomImageMap=panel.mypalneBoomImageMap;}//繪制public void draw(Graphics g) {g.drawImage(image, x, y, width,height, null);} }創建(這里只是創建好了飛機對象,需要繪制)
//創建自己飛機 private void initMyPlane() {myPlane = new MyPlane(200, 530, 132, 86, this); }在paint方法中繪制
//繪圖方法 @Override public void paint(Graphics g) {gameHeight = this.getHeight();gameWidth = this.getWidth();//繪制背景g.drawImage((BufferedImage)imageMap.get("bg"), 0, -150, null);//繪制飛機if(myPlane!=null){myPlane.draw(g);} }鼠標事件監聽
加入監聽是為了讓飛機跟隨鼠標移動,我這里定的規則是第一次鼠標必須移動到飛機上,然后飛機才會跟隨。
代碼里面用一個屬性canMove來控制,默認是false,只有鼠標第一次移入到飛機上時,這個屬性設置為true,然后就可以跟隨鼠標移動了。
//鼠標事件的創建 private void createMouseListener() {MouseAdapter mouseAdapter = new MouseAdapter() {@Overridepublic void mouseMoved(MouseEvent e) {int x = e.getX();int y = e.getY();if(myPlane==null) return ;//飛機第一次是不允許移動的,只有飛機的canMove為true才去跟隨if(myPlane.isCanMove()){myPlane.move(x,y);return;}//判斷鼠標的移入,如果移動到飛機上則canMove設置為trueif(myPlane.isPoint(x,y)){myPlane.setCanMove(true);}}};addMouseMotionListener(mouseAdapter);addMouseListener(mouseAdapter); }來實現一下MyPlane的move方法,這里處理了邊界,保證飛機不出界,同時保證鼠標在飛機的中間位置
//飛機跟隨鼠標移動 public void move(int x,int y) {//判斷范圍,當橫向移動在窗口范圍內if(x-width/2>=0 && x<=panel.getWidth()-width/2){this.x=x-width/2;}//判斷范圍,當縱向移動在窗口范圍內if(y-height/2>=0 && y<=panel.getHeight()-height/2){this.y=y-height/2;} }創建子彈類
屬性也就是坐標、寬高這些,給子彈加入移動方法
//移動 void move(){new Thread(new Runnable() {@Overridepublic void run() {while(alive){y-=speed;if(y<=0){clear();}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}}).start(); }飛機類加入射擊方法,200毫秒創建一發子彈
//射擊 void shoot() {new Thread(new Runnable() {@Overridepublic void run() {while(alive){//創建子彈createBullet();try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}}}private void createBullet() {Bullet bullet = new Bullet(x+width/2-10, y, 20, 30, panel);panel.bulletList.add(bullet);new MusicPlayer("/music/shoot.wav").play();}}).start(); }別忘記在paint方法里面繪制子彈出來
//繪制子彈 Bullet bullet=null; for (int i = 0; i < bulletList.size(); i++) {bullet = (Bullet)bulletList.get(i);bullet.draw(g); }創建敵機
創建抽象類Plane
package main;import java.awt.Graphics;public abstract class Plane {public abstract void move();public abstract void draw(Graphics g);public abstract void boom();public abstract void clear();abstract int getX();abstract int getY();abstract int getWidth();abstract int getHeight(); }創建敵機子類
有個特殊一點的地方: 因為有4種敵機,這里隨機1、2、3、4這4個數字作為屬性index,然后根據這個index來展現不同的飛機圖片,當然也可以通過這個index來設置敵機不同的移動速度,但是我為了偷懶,就全部一樣的移動速度,嘿嘿。
移動就是開啟線程讓y坐標增加,沒什么好講的,這里加一個飛機碰撞,就是當敵機跟我方飛機如何判斷碰撞的問題。
撞機分析(敵機與我機的撞機)
從上面幾個圖可看出什么?因為圖片是方形的,他們的4個頂點一定至少有一個在對方的范圍內。再看一下從左邊撞擊的圖:
從上圖看到也是這樣,其他兩個方向的也是一樣的道理,為了穩點我還加了一種情況:
1.判斷敵機的4個點是否在飛機范圍內,如果有則表示碰撞了。
2.如果1不成立,則反過來,判斷我機的4個點是否在敵機的范圍內,如果是表示碰撞了。
測試一下效果
忘記說擊中敵機的了(原理跟剛才差不多,代碼直接放了)
//判斷擊中敵機 protected void hitEnemy() {EnemyPlane enemyPlane=null;List enemys = panel.enemyList;for (int i = 0; i < enemys.size(); i++) {try {enemyPlane = (EnemyPlane)enemys.get(i);} catch (Exception e) {}if(enemyPlane==null) continue;if(this.isPoint(enemyPlane)){panel.curCount+=enemyPlane.getCount();//刪除當前子彈clear();//飛機爆炸enemyPlane.boom();if(panel.curCount>=panel.totalCount){panel.myPlane.setCanMove(false);panel.gameWin();}}} }//判斷飛機與子彈是否碰撞 private boolean isPoint(EnemyPlane plane) {//因為子彈比飛機小,所以只需要判斷子彈的4個點是否在飛機范圍內,如果有則表示碰撞了//左上角int x1 = x;int y1 = y;//右上角int x2 = x+width;int y2 = y;//右下角int x3 = x+width;int y3 = y+height;//左下角int x4 = x;int y4 = y+height;//只要有一個點在范圍內,則判斷為碰撞if(comparePoint(x1,y1,plane)|| comparePoint(x2,y2,plane)||comparePoint(x3,y3,plane)||comparePoint(x4,y4,plane) ){return true;}return false; }private boolean comparePoint(int x,int y,EnemyPlane plane){//大于左上角,小于右下角的坐標則肯定在范圍內if(x>plane.getX() && y >plane.getY()&& x<plane.getX()+plane.getWidth() && y <plane.getY()+plane.getHeight() ){return true;}return false; }最后加上計分的、勝利、失敗等提示就完成了!
看到這里的大佬,動動發財的小手 點贊 + 回復 + 收藏,能【 關注 】一波就更好了。
代碼獲取方式:
訂閱我的專欄《Java游戲大全》后,可以查看專欄內所有的文章,并且聯系博主免費獲取其中1-3份你心儀的源代碼,專欄的文章都是上過csdn熱榜的,值得信賴!專欄內目前有[13]篇實例,未來2個月內專欄會更新到15篇以上,一般2周一更,了解一下我的專欄。
熱門專欄推薦
【1】Java小游戲(俄羅斯方塊、飛機大戰、植物大戰僵尸等)
【2】JavaWeb項目實戰(圖書管理、在線考試、宿舍管理等)
【3】JavaScript精彩實例(飛機大戰、貪吃蛇、驗證碼等)
【4】Java小白入門200例
【5】從零學Java、趣學Java
【6】Idea從零到精通
★ 更多精彩
1. Java俄羅斯方塊
2. 老Java程序員花2天寫了個連連看
3. 老Java程序員花一天時間寫了個飛機大戰
4. Java五子棋人機版
5. Java植物大戰僵尸
6. Java消消樂(天天愛消除)
7. Java貪吃蛇小游戲
8. Java掃雷小游戲
9. Java坦克大戰
總結
以上是生活随笔為你收集整理的老Java程序员花一天时间写了个飞机大战,很舒服!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pat(基本编程题集)6-2 多项式求值
- 下一篇: 基于单片机的公交车系统