JAVA 飞机大战
? ? ? ? 小的時候我們玩過很多小游戲,比如:坦克大戰、貪吃蛇、超級瑪麗、推箱子、飛機大戰等等。今天就用java寫一個小游戲,飛機大戰。飛機大戰的主要知識點就是線程,只要對線程有基本的了解就能完成飛機大戰的編程。
? ? ? ? 關于飛機大戰的編寫,接下來分幾個步驟來完成。
一、實現敵方飛機的移動
? ? ? ?(用一張球的圖片來替代敵方飛機,之后更換圖片就好)
? ? ? ?1.首先要有一個圖形界面(定義為BallFream類)
? ? ? ? ? 繼承JPanel是為了獲取它的畫筆,這不是最簡便的方法。接下來要使用畫筆,你用其他的方法獲取也可以.
? ? ? ?2.定義一個(Ball類)類來存儲對象(現在用的圖片是球,定義一個球類存儲相應的參數)
? ? ? ? ? 同時將球的圖片引入進來,之后會使用。引入球的圖片用ImageIcon,將圖片直接復制到當前包下。通過新建一個對象new ImageIcon(this.getClass().getResource("圖片名.類型名")).getImage();
public class Ball {private int x,y,width,height;private Image image;public Ball(int x, int y, int width, int height) {super();this.x = x;this.y = y;this.width = width;this.height = height;this.image = new ImageIcon(this.getClass().getResource("ball.png")).getImage();}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public int getWidth() {return width;}public void setWidth(int width) {this.width = width;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}}? ? ? ?3.將圖片畫出來和實現球的移動
? ? ? ? ? 在定義的對象類(Ball類)里寫畫球方法和移動方法。球并不是真的移動,而是我們改變了球的坐標。畫完一個球后,畫一個窗體大小的顏色與窗體背景色一樣的矩形,會把之前畫的球覆蓋掉,接下來按照新的坐標再畫一次。因為電腦畫的非???#xff0c;在我們看來就達到了移動的效果。
//畫球的方法,把圖畫出來,給定了位置、大小 public void draw(Graphics2D g) {g.drawImage(image, x - 80/2, y - 80/2, 80, 80,null);}//移動的方法,改變坐標y的值,讓球看起來在下落 public void move() {y+=5; }? ? ? ?4.添加監聽和繼承線程接口(Runnable)
? ? ? ? ?我們希望在窗體某個位置點擊鼠標的時候就生成一個球,并開始運動。這就要添加鼠標監聽機制,還要有事件處理類(BallListener類)。
? ? ? ? ?繼承Runnable是為了讓移動方法不斷執行,這樣球的縱坐標就會不斷改變,達到移動的效果。
? ? ? ? ?添加監聽方法并啟動線程
? ? ? ? ?在圖形界面類(BallFrame類)中添加和啟動,啟動線程要先與Runnable建立聯系,也就是實例化Thread類。同時在實例化事件處理類BallListener是將需要使用的參數傳遞過去,這里把窗體傳遞過去,可以通過窗體獲取參數。
BallListener bl = new BallListener(this); this.addMouseListener(bl); Thread td = new Thread(bl); td.start();? ? ? 5.事件處理類BallListener
? ? ? 繼承MouseAdapter類只需重寫用到的抽象方法;
? ? ? 繼承Runnable接口,重寫run()方法。
? ? ? 實現球的移動,需要將以前畫的球去掉,留下最新畫的球。畫一個界面大小的矩形,將以前的球覆蓋掉再畫新的球。
? ? ? 在界面上可能不止一個球在移動,而是多個球在移動,就需要把所有的球存儲起來。建立一個數組隊列用來存儲生成的球,?鼠標點擊一次就生成一個球,在鼠標點擊后就將球存儲起來。當線程運行的時候,遍歷數組隊列,將所有的球都畫一遍。
? ? ?將球和矩形畫出來就需要畫筆,而我們已經將窗體傳過來了,如果畫筆為空,就獲取畫筆。
import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList;public class BallListener extends MouseAdapter implements Runnable{private BallFrame bf;private int x,y;private Ball ball;//創建數組隊列,直接通過Ball類來存儲private ArrayList<Ball> list = new ArrayList<Ball>();//你也可以用Graphics,不用Graphics2Dprivate Graphics2D g;//構造函數public BallListener(BallFrame bf) {this.bf = bf;}//重寫鼠標點擊方法,獲取鼠標點擊的坐標,把球的坐標、寬度、高度存儲起來public void mouseClicked(MouseEvent e) {x = e.getX();y = e.getY();ball = new Ball(x,y,80,80);list.add(ball);}//重寫線程的抽象方法public void run() {//while循環,讓代碼不斷執行while(true) {//判斷畫筆是否為空,如果是則獲取畫筆if(g == null) {g = (Graphics2D) bf.getGraphics();//畫筆抗鋸齒(讓圖形邊緣變得光滑)g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);}//獲取窗體的背景顏色g.setColor(bf.getBackground());//畫一個窗體大小矩形,去掉移動痕跡g.fillRect(0, 0, 500, 600);//遍歷數組隊列,將隊列里的球都畫出來for(int i = 0; i < list.size(); i++) {//判斷語句,當球移動出窗體可見范圍后就將它從數組隊列移除,減少內存消耗if(y < bf.getHeight()) {ball = list.get(i);//調用畫球的方法ball.draw(g);//調用移動方法ball.move();}else {//移除不可見的球list.remove(ball);}}//線程休眠try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}}? ? ? 6.補充
? ? ? ? ?關于調用Ball類的移動方法后數組隊列里存儲的值也會改變問題。
? ? ? ? ?ball = list.get(i);只是把地址賦給了ball,并不是直接把存儲的值給了ball。當ball調用移動方法后改變了y的值,改變的值是數組隊列中的值。
? ? ? 7.總結
? ? ? ? 以上實現的功能為:鼠標點擊窗體的某一個位置時,生成一個球,點擊多次,生成多個球。之后球會向下移動。
? ? ? ? 但存在屏閃問題。有可能在畫一個球的同時,一個清除移動痕跡的矩形也在繪制,會造成相互沖突。我們希望球在同一時間畫出來,接下來就解決這個問題。
二、雙緩沖解決屏閃問題
? ? ? ? ?
? ? ? ??
? ? ? ? 注意,顯示緩沖區是和顯示器一起的,顯示器只負責從顯示緩沖區取數據顯示。我們通常所說的在顯示器上畫一條直線,其實就是往該顯示緩沖區中寫入數據。顯示器通過不斷的刷新(從顯示緩沖區取數據),從而使顯示緩沖區中數據的改變及時的反映到顯示器上。
? ? ?這也是顯示復雜圖形時造成閃爍的原因,比如你現在要顯示從屏幕中心向外發射的一簇射線,你開始編寫代碼用一個循環從0度開始到360度,每隔一定角度畫一條從圓心開始向外的直線。你每次畫線其實是往顯示緩沖區寫入數據,如果你還沒有畫完,顯示器就從顯示緩沖區取數據顯示圖形,此時你看到的是一個不完整的圖形,然后你繼續畫線,等到顯示器再次取顯示緩沖區數據顯示時,圖形比上次完整了一些,依次下去直到顯示完整的圖形。你看到圖形不是一次性完整地顯示出來,而是每次顯示一部分,從而造成閃爍。
--------------------- 本文來自 Smith先生 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/acs713/article/details/16359551?utm_source=copy
?
? ? ? ? 所以,我們引入次畫布。將數組隊列里存儲的信息遍歷完后將圖形在次畫布上畫出來,再把次畫布和次畫布上的圖形畫到窗體上。
? ? ? ? 在BallListener類進行操作,對run()方法進行修改。
private BufferedImage bi;//可用來構建次畫布public void run() {while(true) {//引入次畫布,先在次畫布上消除移動的痕跡,然后把圖形按照數組隊列逐一畫出來BufferedImage bi = new BufferedImage(bf.getWidth(), bf.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);//獲取次畫布上的畫筆ig =(Graphics2D) bi.getGraphics();ig.setColor(bf.getBackground());//用次畫布上的畫筆在次畫布上消除移動痕跡ig.fillRect(0, 0, bf.getWidth(), bf.getHeight());for(int i = 0; i < list.size(); i++) {//圖形移動出窗體可見后就移除,減少占用if(x > 0 && x < bf.getWidth() && y > 0 && y < bf.getHeight()) {ball = list.get(i);//用次畫布上的畫筆畫球ball.draw(ig);ball.move();}else {list.remove(ball);}}//如果畫筆為空,則獲取窗體上的畫筆if(g == null) {g = (Graphics2D) bf.getGraphics();g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);}//將次畫布上的圖形畫到窗體上g.drawImage(bi, null, bf);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}三、敵方飛機自動生成和發射子彈
現在我們在前面的基礎上開發飛機大戰,為了代碼的易讀,修改了類名,現在再貼一遍代碼吧
界面類PlaneFrame
import javax.swing.JFrame; import javax.swing.JPanel;public class PlaneFrame extends JPanel{public static void main(String[] args) {PlaneFrame pf = new PlaneFrame();pf.showFrame();}public void showFrame() {JFrame frame = new JFrame();frame.setTitle("球");frame.setSize(700,600);frame.setLocationRelativeTo(null);frame.setDefaultCloseOperation(3);frame.setResizable(false);//將JPanel添加到JFrame,this就是JPanelframe.add(this);frame.setVisible(true);PlaneListener bl = new PlaneListener(this);//添加鼠標監聽方法this.addMouseListener(bl);//與線程建立聯系Thread td = new Thread(bl);//調用啟動線程的方法td.start();}}事件處理類PlaneListener
import java.awt.Graphics; import java.awt.Image; import java.awt.event.MouseAdapter; import java.awt.image.BufferedImage; import java.util.ArrayList;import javax.swing.ImageIcon;public class PlaneListener extends MouseAdapter implements Runnable{private PlaneFrame pf;private int x,y,width,height;private Plane plane;private ArrayList<Plane> list = new ArrayList<Plane>();//創建球類數組隊列,存儲數據private Graphics g;private BufferedImage bi;//可用來構建次畫布private Graphics ig;private Image background;//構造函數,把窗體傳遞過來public PlaneListener(PlaneFrame pf) {this.pf = pf;}public void run() {while(true) {//引入次畫布,先在次畫布上消除移動的痕跡,然后把圖形按照數組隊列逐一畫出來BufferedImage bi = new BufferedImage(pf.getWidth(), pf.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);//獲取次畫布上的畫筆ig = bi.getGraphics();// ig.setColor(bf.getBackground());//用次畫布上的畫筆在次畫布上消除移動痕跡// ig.fillRect(0, 0, bf.getWidth(), bf.getHeight());//引入背景圖片,用背景圖片替代矩形達到察除移動痕跡的目的background = new ImageIcon(this.getClass().getResource("background.jpg")).getImage();;ig.drawImage(background, 0, 0, pf.getWidth(), pf.getHeight(),null);for(int i = 0; i < list.size(); i++) {if(x < pf.getWidth() && y < pf.getHeight()) {plane = list.get(i);//用次畫布上的畫筆畫球plane.draw(ig);plane.move();}else {list.remove(plane);}}//如果畫筆為空,則獲取窗體上的畫筆if(g == null) {g = pf.getGraphics();}//將次畫布上的圖形畫到窗體上g.drawImage(bi,0,0, null);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}}定義存儲類Plane
import java.awt.Graphics; import java.awt.Image; import java.util.ArrayList; import java.util.Random;import javax.swing.ImageIcon;public class Plane {private int x,y,width,height;private Image image,img;private int size;private PlaneFrame pf;private int addx;private int speed;//構造方法//獲取圖片小球的數據public Plane(int x, int y, int width, int height,int speed,,PlaneFrame pf,Image image) {super();this.x = x;this.y = y;this.width = width;this.height = height;this.speed = speed;this.pf = pf;this.image = image;this.img = new ImageIcon(this.getClass().getResource("bullet.png")).getImage(); }//畫圖public void draw(Graphics g) {g.drawImage(image, x-width/2, y-height/2, width, height,null); //畫圖}//移動public void move() {y+=speed; }public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public int getWidth() {return width;}public void setWidth(int width) {this.width = width;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}}? ? ? ?1.之前我們是點擊鼠標才會生成圖片,現在我們要讓圖片自動生成。這就需要新建一個線程,在程序開始執行的時候通過start()方法來啟動線程的run()方法來達到我們目的 。
? ? ? ?在PlaneListener類的構造方法里啟動新的線程PlaneThread類(未定義),并傳遞參數。
public PlaneListener(PlaneFrame pf) {this.pf = pf;//這里的10為產生敵機的數量,可修改PlaneThread pt = new PlaneThread(pf,list,10,width,height);//啟動新線程pt.start(); }? ? ? ?在run()方法里寫一個循環,給定size的大小,也就是產生敵方飛機的數量。再利用休眠,每隔一段時間就產生一架敵機,并且利用數組隊列存儲起來。
接下來是PlaneThread類
import java.awt.Image; import java.util.ArrayList; import java.util.Random;import javax.swing.ImageIcon;public class PlaneThread extends Thread{private int size;private PlaneFrame pf;private ArrayList<Plane> list;private int x,y,width,height;private Image image;//構造方法public PlaneThread(PlaneFrame pf,ArrayList<Plane> list,int size,int width, int height) {this.pf = pf;this.list = list;this.size = size;this.width = width;this.height = height;//敵機的圖片this.image = new ImageIcon(this.getClass().getResource("fighter.png")).getImage();}public void run() {//循環,利用隨機數讓敵機生成的橫坐標無規律for(int i = 0; i < size; i++) {Random rand = new Random();x = 40 + rand.nextInt(pf.getWidth() - 200) + 1;y = 20;//利用數組隊列將敵機存儲起來//x-80/2,y-80/2為坐標,80,80為圖片的寬度和高度,2為移動速度,image為圖片Plane ball = new Plane(x-80/2,y-80/2,80,80,2,list,pf,image);list.add(ball);try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}}}? ? ? ?2.敵機自動發射子彈,我這里是讓敵機每向下移動50單位距離就產生一枚子彈。在Plane類的移動方法里進行操作。當敵機的y坐標除以50沒有余數的時候就生成一枚子彈。同時需要將數組隊列傳過來,把生成的子彈存儲起來。傳遞數組對列這里就不再重復了,通過構造函數,還要將子彈的圖片引入,下面是Plane類里移動方法的修改。
public void move(ArrayList<Plane> list) {//用speed來指代每次移動距離y+=speed;//判斷是否應該生成子彈if(y%50 ==0) {//將子彈存儲起來//x,y為子彈生成的坐標;20,20為子彈圖片的大小;6為子彈的移動速度;img為子彈的圖片Plane bullet = new Plane(x,y,20,20,6,list,pf,img);list.add(bullet); }? ? ? ?注意:到達這一步運行程序后會發現,敵機每隔50個單位距離會產生一顆子彈,而之前產生的子彈也會每隔50個單位生產一顆子彈。這是因為判斷生成子彈的時候只根據距離來判斷,沒有區分敵機還是子彈,這個問題后面會解決。
? ? ? ?
四、己方飛機和子彈
? ? ? 1.通過鼠標控制己方飛機,當鼠標在窗體上移動時己方飛機跟著移動,同時還需給定己方飛機的初始位置。創建一個myplane對象來對應己方飛機,實時更新己方飛機的坐標值。在PlaneListener類進行操作
//給定己方飛機的初始坐標值 private int x = 330,y = 520,width,height; //引入己方飛機的圖片 private Image imagemyplane = new ImageIcon(this.getClass().getResource("myplane.png")).getImage();private Plane myplane;//構造函數,把窗體傳遞過來 public PlaneListener(PlaneFrame pf) {this.pf = pf;//存儲己方飛機的數據 myplane = new Plane(x,y,80,80,0,list,pf,imagemyplane); list.add(myplane);//啟動生成敵機的線程 PlaneThread pt = new PlaneThread(pf,list,50,width,height);pt.start();}public void mouseMoved(MouseEvent e){//獲取鼠標移動時的坐標值x = e.getX();y = e.getY();//將坐標賦給myplane對象myplane.setX(x);myplane.setY(y); }? ? ? 2.己方飛機發射不斷發射子彈,創建一個己方飛機的子彈線程MyBullet。己方飛機的子彈通過獲取己方飛機的坐標來生成子彈。
import java.awt.Image; import java.util.ArrayList;import javax.swing.ImageIcon;public class MyBullet extends Thread{private PlaneFrame pf;private ArrayList<Plane> list;private int x,y,width,height;private Image imagemybullet;private Plane myplane;//構造函數public MyBullet(PlaneFrame pf,ArrayList<Plane> list,int x,int y,int width, int height,Plane myplane) {this.pf = pf;this.list = list;this.x = x;this.y = y;this.width = width;this.height = height;this.myplane = myplane;//引入己方飛機的子彈圖片this.imagemybullet = new ImageIcon(this.getClass().getResource("mybullet.png")).getImage();}public void run() {while(true) {//獲取己方飛機的坐標x = myplane.getX();y = myplane.getY();//存儲己方飛機的子彈//x,y為坐標,20,20為圖片的寬度和高度,-6為移動速度(負號是移動方向)Plane mybullet = new Plane(x,y,20,20,-6,list,pf,imagemybullet);list.add(mybullet);//每隔500毫秒生成一顆子彈try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}}?
五、判斷飛機大戰輸贏
? ? ? ?1.為解決子彈每隔50個單位距離生成一顆子彈,用字符對存儲的信息進行標識,確認是敵機才會生成子彈。
在Plane類里操作
public void move(ArrayList<Plane> list) {y+=speed;for(int i = 0;i < list.size();i++) {//如果是敵機且移動50個單位距離if(type.equals("e_p") && y%50 == 0) {Plane bullet = new Plane(x,y,20,20,6,list,pf,imagebullet,"e_b");list.add(bullet); }break;}}? ? ? ?2.在Plane類里寫一個碰撞crash方法,敵機和敵機子彈碰到己方飛機子彈時會消失(從數組隊列里一起移除);敵機和敵機子彈碰到己方飛機時,游戲結束,線程停止。static關鍵字的運用可定義靜態變量,在不同的類可通過類名.對象名調用,根據這個來控制PlaneListener類里的run()方法的
Plane類里的crash()方法
public void crash() {for(int j = 0;j < list.size();j++){Plane lt = list.get(j);if(lt.getType().equals("m_p")) {for(int i = 0;i < list.size();i++) {Plane temp = list.get(i);if(temp.getType().equals("e_p") || temp.getType().equals("e_b")) {double xx = lt.getX() - temp.getX();double yy = lt.getY() - temp.getY();double ww = lt.getWidth() + temp.getWidth();if(Math.sqrt(xx*xx + yy*yy) <= ww/2) {list.remove(lt);list.remove(temp);//給靜態屬性賦值PlaneListener.flag=false;}}}}if(lt.getType().equals("m_b")) {for(int i = 0;i < list.size();i++) {Plane temp = list.get(i);if(temp.getType().equals("e_p") || temp.getType().equals("e_b")) {double xx = lt.getX() - temp.getX();double yy = lt.getY() - temp.getY();double ww = lt.getWidth() + temp.getWidth();if(Math.sqrt(xx*xx + yy*yy) <= ww/2) {list.remove(temp);list.remove(lt);}}}}}}下面貼上完整代碼(此版本的飛機大戰很簡單,可以在此基礎上進行開發,你可以發揮自己的想象,增設關卡、血條、獎勵、Boss等等)(可能存在少許未使用代碼和注釋掉的代碼沒有刪除)
import java.awt.Color;import javax.swing.JFrame; import javax.swing.JPanel;public class PlaneFrame extends JPanel{public static void main(String[] args) {PlaneFrame pf = new PlaneFrame();pf.showFrame();}public void showFrame() {JFrame frame = new JFrame();frame.setTitle("飛機大戰");frame.setSize(700,600);frame.setLocationRelativeTo(null);frame.setDefaultCloseOperation(3);frame.setResizable(false);//將JPanel添加到JFrame,this就是JPanelframe.add(this);frame.setVisible(true);PlaneListener bl = new PlaneListener(this);//添加鼠標監聽方法// this.addMouseListener(bl);this.addMouseMotionListener(bl);//與線程建立聯系Thread td = new Thread(bl);//調用啟動線程的方法td.start();//讓線程里的代碼執行bl.setFlag(true);}} import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.util.ArrayList;import javax.swing.ImageIcon;public class PlaneListener extends MouseAdapter implements Runnable{private PlaneFrame pf;private int x = 330,y = 520,width,height;private Plane plane;private ArrayList<Plane> list = new ArrayList<Plane>();//創建飛機類數組隊列,存儲數據private Graphics2D g;private BufferedImage bi;//可用來構建次畫布private Graphics ig;private Image background;private Image imagemyplane = new ImageIcon(this.getClass().getResource("myplane.png")).getImage();;private Plane myplane;private String type;//設置為靜態屬性,可在別的類直接調用public static boolean flag = true;//構造函數,把窗體傳遞過來public PlaneListener(PlaneFrame pf) {this.pf = pf;//創建我的飛機對象,并存儲起來myplane = new Plane(x,y,80,80,0,list,pf,imagemyplane,"m_p"); list.add(myplane);//創建敵機線程,讓敵機自動出現,把用到的參數傳遞過去PlaneThread pt = new PlaneThread(pf,list,50,width,height);pt.start();//創建我的飛機的子彈線程,讓子彈自動發射并傳遞參數MyBullet mb = new MyBullet(pf,list,x,y,width,height,type,myplane);mb.start();}public PlaneListener() {}public void mouseMoved(MouseEvent e){//獲取坐標x = e.getX();y = e.getY();//將坐標賦給我的飛機對象myplane.setX(x);myplane.setY(y); }public void run() {while(true) {if(flag) {//引入次畫布,先在次畫布上消除移動的痕跡,然后把圖形按照數組隊列逐一畫出來BufferedImage bi = new BufferedImage(pf.getWidth(), pf.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);//獲取次畫布上的畫筆ig = bi.getGraphics();background = new ImageIcon(this.getClass().getResource("background.jpg")).getImage();;ig.drawImage(background, 0, 0, pf.getWidth(), pf.getHeight(),null);for(int i = 0; i < list.size(); i++) {if(x < pf.getWidth() && y < pf.getHeight()) {plane = list.get(i);//用次畫布上的畫筆來畫plane.draw(ig); plane.move(list);plane.judge(pf);plane.crash();}else {list.remove(plane);}}//如果畫筆為空,則獲取窗體上的畫筆if(g == null) {g = (Graphics2D) pf.getGraphics();g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);}//將次畫布上的圖形畫到窗體上g.drawImage(bi,0,0, null);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}}public boolean isFlag() {return flag;}public void setFlag(boolean flag) {this.flag = flag;}} import java.awt.Image; import java.util.ArrayList; import java.util.Random;import javax.swing.ImageIcon;public class PlaneThread extends Thread{private int size;private PlaneFrame pf;private ArrayList<Plane> list;private int x,y,width,height;private Image imageplane;private String type;public PlaneThread(PlaneFrame pf,ArrayList<Plane> list,int size,int width, int height) {this.pf = pf;this.list = list;this.size = size;this.width = width;this.height = height;this.imageplane = new ImageIcon(this.getClass().getResource("plane.png")).getImage();}public void run() {//自動產生敵機for(int i = 0; i < size; i++) {Random rand = new Random();x = 80 + rand.nextInt(pf.getWidth() - 100);y = 20;Plane plane = new Plane(x-80/2,y-80/2,80,80,2,list,pf,imageplane,"e_p");list.add(plane);try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}} import java.awt.Image; import java.util.ArrayList;import javax.swing.ImageIcon;public class MyBullet extends Thread{private PlaneFrame pf;private ArrayList<Plane> list;private int x,y,width,height;private Image imagemybullet;private String type;private Plane myplane;public MyBullet(PlaneFrame pf,ArrayList<Plane> list,int x,int y,int width, int height,String type,Plane myplane) {this.pf = pf;this.list = list;this.x = x;this.y = y;this.width = width;this.height = height;this.type = type;this.myplane = myplane;this.imagemybullet = new ImageIcon(this.getClass().getResource("mybullet.png")).getImage();}public void run() {//自動產生子彈while(true) {//通過我的飛機對象來獲取子彈發射的坐標x = myplane.getX();y = myplane.getY();Plane mybullet = new Plane(x,y,20,20,-6,list,pf,imagemybullet,"m_b");list.add(mybullet);try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}} import java.awt.Graphics; import java.awt.Image; import java.util.ArrayList; import java.util.Random;import javax.swing.ImageIcon;public class Plane {private int x,y,width,height;private Image imageplane,imagebullet;private int size;private ArrayList<Plane> list;private PlaneFrame pf;private int addx;private int speed;private String type;private PlaneListener pr;//構造方法//獲取圖片小球的數據public Plane(int x, int y, int width, int height,int speed,ArrayList<Plane> list,PlaneFrame pf,Image imageplane,String type) {super();this.x = x;this.y = y;this.width = width;this.height = height;this.speed = speed;this.list = list;this.pf = pf;this.imageplane = imageplane;this.type = type;this.imagebullet = new ImageIcon(this.getClass().getResource("bullet.png")).getImage();//隨機數的運用Random rand = new Random();addx = -10 + rand.nextInt(20);}//畫圖public void draw(Graphics g) {g.drawImage(imageplane, x-width/2, y-height/2, width, height,null); //畫圖// g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,// RenderingHints.VALUE_ANTIALIAS_ON);}//移動public void move(ArrayList<Plane> list) {//x+=addx;敵機的運動可以左右隨機 // x+=addx;y+=speed;for(int i = 0;i < list.size();i++) {if(type.equals("e_p") && y%50 == 0) {Plane bullet = new Plane(x,y,20,20,6,list,pf,imagebullet,"e_b");list.add(bullet); }break;}}//判斷是否到達邊界//敵機左右運動到達邊界后反彈public void judge(PlaneFrame pf) {if(x-40 <= 0) {addx = -addx;}else if(x+40 >= pf.getWidth()) {addx = -addx;}}//碰撞public void crash() {for(int j = 0;j < list.size();j++){Plane lt = list.get(j);if(lt.getType().equals("m_p")) {for(int i = 0;i < list.size();i++) {Plane temp = list.get(i);if(temp.getType().equals("e_p") || temp.getType().equals("e_b")) {double xx = lt.getX() - temp.getX();double yy = lt.getY() - temp.getY();double ww = lt.getWidth() + temp.getWidth();if(Math.sqrt(xx*xx + yy*yy) <= ww/2) {list.remove(lt);list.remove(temp);//給靜態屬性賦值PlaneListener.flag=false;}}}}if(lt.getType().equals("m_b")) {for(int i = 0;i < list.size();i++) {Plane temp = list.get(i);if(temp.getType().equals("e_p") || temp.getType().equals("e_b")) {double xx = lt.getX() - temp.getX();double yy = lt.getY() - temp.getY();double ww = lt.getWidth() + temp.getWidth();if(Math.sqrt(xx*xx + yy*yy) <= ww/2) {list.remove(temp);list.remove(lt);}}}}}}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}public int getWidth() {return width;}public void setWidth(int width) {this.width = width;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}public String getType() {return type;}public void setType(String type) {this.type = type;}}?
總結
- 上一篇: python装饰器调用顺序_聊一聊Pyt
- 下一篇: java内存溢出让tomcat停止_ja