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