最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一天時(shí)間用Java寫了個(gè)飛機(jī)大戰(zhàn)游戲,朋友直呼高手

 更新時(shí)間:2021年05月28日 16:21:37   作者:編程界明世隱  
前兩天我發(fā)現(xiàn)論壇有兩篇飛機(jī)大戰(zhàn)的文章異常火爆,但都是python寫的,竟然不是我大Java,說實(shí)話作為老java選手,我心里是有那么一些失落的,今天特地整理了這篇文章,需要的朋友可以參考下

一、代碼實(shí)現(xiàn)

創(chuàng)建窗口

首先創(chuàng)建一個(gè)游戲窗體類GameFrame,繼承至JFrame,用來顯示在屏幕上(window的對(duì)象),每個(gè)游戲都有一個(gè)窗口,設(shè)置好窗口標(biāo)題、尺寸、布局等就可以。

/*
 * 游戲窗體類
 */
public class GameFrame extends JFrame {
	
	public GameFrame() {
		setTitle("飛機(jī)大戰(zhàn)");//設(shè)置標(biāo)題
		setSize(526, 685);//設(shè)定尺寸
		setLayout(new BorderLayout());
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//點(diǎn)擊關(guān)閉按鈕是關(guān)閉程序
        setLocationRelativeTo(null);   //設(shè)置居中
    	setResizable(false); //不允許修改界面大小
	}
}

創(chuàng)建面板容器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;
	//構(gòu)造里面初始化相關(guān)參數(shù)
	public GamePanel(JFrame frame){
		this.setLayout(null);
		mainFrame = frame;
		
		mainFrame.setVisible(true);
	}
	
	@Override
	public void paint(Graphics g) {
		
	}
}

再創(chuàng)建一個(gè)Main類,來啟動(dòng)這個(gè)窗口,用來啟動(dòng)。

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);//設(shè)定顯示
	}
}

右鍵執(zhí)行這個(gè)Main類,窗口建出來了

??窗口

二、創(chuàng)建菜單及菜單選項(xiàng)

創(chuàng)建菜單

private void  initMenu(){
	// 創(chuàng)建菜單及菜單選項(xiàng)
	jmb = new JMenuBar();
	JMenu jm1 = new JMenu("游戲");
	jm1.setFont(new Font("微軟雅黑", Font.BOLD, 15));// 設(shè)置菜單顯示的字體
	JMenu jm2 = new JMenu("幫助");
	jm2.setFont(new Font("微軟雅黑", Font.BOLD, 15));// 設(shè)置菜單顯示的字體
	
	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");
}

實(shí)現(xiàn)ActionListener并重寫方法actionPerformed

在這里插入圖片描述

actionPerformed方法的實(shí)現(xiàn)

@Override
public void actionPerformed(ActionEvent e) {

	String command = e.getActionCommand();
	UIManager.put("OptionPane.buttonFont", new FontUIResource(new Font("宋體", Font.ITALIC, 18)));
	UIManager.put("OptionPane.messageFont", new FontUIResource(new Font("宋體", Font.ITALIC, 18)));
	if ("Exit".equals(command)) {
		Object[] options = { "確定", "取消" };
		int response = JOptionPane.showOptionDialog(this, "您確認(rèn)要退出嗎", "",
				JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null,
				options, options[0]);
		if (response == 0) {
			System.exit(0);
		} 
	}else if("Restart".equals(command)){
		if(startFlag){
			Object[] options = { "確定", "取消" };
			int response = JOptionPane.showOptionDialog(this, "游戲中,您確認(rèn)要重新開始嗎", "",
					JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null,
					options, options[0]);
			if (response == 0) {
				//需要先結(jié)束游戲
				realGameEnd(1);
				restart();
			} 
		}else{
			restart();
		}
	}else if("help".equals(command)){
		JOptionPane.showMessageDialog(null, "游戲開始后,要先動(dòng)鼠標(biāo)到飛機(jī)處,觸發(fā)移動(dòng)效果,然后飛機(jī)就會(huì)跟隨鼠標(biāo)移動(dòng)!",
				"提示!", JOptionPane.INFORMATION_MESSAGE);
	}else if("win".equals(command)){
		JOptionPane.showMessageDialog(null, "得分1000,獲得勝利!",
				"提示!", JOptionPane.INFORMATION_MESSAGE);
	}
}

在這里插入圖片描述

三、創(chuàng)建背景

在GamePanel類中重寫paint方法,繪制背景圖即可

//繪圖方法
@Override
public void paint(Graphics g) {
	gameHeight = this.getHeight();
	gameWidth = this.getWidth();
	//繪制背景
	g.drawImage((BufferedImage)imageMap.get("bg"), 0, -150, null);
}

在這里插入圖片描述

四、開啟主線程

主線程,用來重繪頁面,重繪全部交給主線程,主線程調(diào)用 repaint方法就行,要產(chǎn)生動(dòng)畫就要靠這個(gè)repaint。

//刷新線程,用來重新繪制頁面
private class RefreshThread implements Runnable {
	@Override
	public void run() {
		while (startFlag) {
			repaint();
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

在GamePanel的構(gòu)造里面啟動(dòng)這個(gè)主線程

在這里插入圖片描述

有了這個(gè)主線程刷新,待會(huì)我們更新飛機(jī)的位置,飛機(jī)就會(huì)移動(dòng),不需要另外的代碼去調(diào)用repaint方法了(這是我的做法,僅供參考)。

五、創(chuàng)建我方飛機(jī)

創(chuàng)建MyPlane類,屬性有坐標(biāo)x、y,寬高、圖片、是否存活、是否可以移動(dòng)等;方法主要有繪制、移動(dòng)、射擊等。

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);
	}
}

創(chuàng)建(這里只是創(chuàng)建好了飛機(jī)對(duì)象,需要繪制)

//創(chuàng)建自己飛機(jī)
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);
	
	//繪制飛機(jī)
	if(myPlane!=null){
		myPlane.draw(g);
	}
}

在這里插入圖片描述

六、鼠標(biāo)事件監(jiān)聽

加入監(jiān)聽是為了讓飛機(jī)跟隨鼠標(biāo)移動(dòng),我這里定的規(guī)則是第一次鼠標(biāo)必須移動(dòng)到飛機(jī)上,然后飛機(jī)才會(huì)跟隨。

代碼里面用一個(gè)屬性canMove來控制,默認(rèn)是false,只有鼠標(biāo)第一次移入到飛機(jī)上時(shí),這個(gè)屬性設(shè)置為true,然后就可以跟隨鼠標(biāo)移動(dòng)了。

//鼠標(biāo)事件的創(chuàng)建
private void createMouseListener() {
	MouseAdapter mouseAdapter = new MouseAdapter() {
		@Override
		public void mouseMoved(MouseEvent e) {
			int x = e.getX();
			int y = e.getY();
			if(myPlane==null) return ;
			//飛機(jī)第一次是不允許移動(dòng)的,只有飛機(jī)的canMove為true才去跟隨
			if(myPlane.isCanMove()){
				myPlane.move(x,y);
				return;
			}
			//判斷鼠標(biāo)的移入,如果移動(dòng)到飛機(jī)上則canMove設(shè)置為true
			if(myPlane.isPoint(x,y)){
				myPlane.setCanMove(true);
			}
		}
	};
	addMouseMotionListener(mouseAdapter);
	addMouseListener(mouseAdapter);
}

來實(shí)現(xiàn)一下MyPlane的move方法,這里處理了邊界,保證飛機(jī)不出界,同時(shí)保證鼠標(biāo)在飛機(jī)的中間位置

//飛機(jī)跟隨鼠標(biāo)移動(dòng)
public void move(int x,int y) {
	//判斷范圍,當(dāng)橫向移動(dòng)在窗口范圍內(nèi)
	if(x-width/2>=0 && x<=panel.getWidth()-width/2){
		this.x=x-width/2;
	}
	//判斷范圍,當(dāng)縱向移動(dòng)在窗口范圍內(nèi)
	if(y-height/2>=0 && y<=panel.getHeight()-height/2){
		this.y=y-height/2;
	}
}

在這里插入圖片描述

七、創(chuàng)建子彈類

屬性也就是坐標(biāo)、寬高這些,給子彈加入移動(dòng)方法

//移動(dòng)
void move(){
	new Thread(new Runnable() {
		@Override
		public void run() {
			while(alive){
				y-=speed;
				if(y<=0){
					clear();
				}
				
				try {
					Thread.sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}).start();
}

飛機(jī)類加入射擊方法,200毫秒創(chuàng)建一發(fā)子彈

//射擊
void shoot() {
	new Thread(new Runnable() {
		@Override
		public void run() {
			while(alive){
				//創(chuàng)建子彈
				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);
}

在這里插入圖片描述

八、創(chuàng)建敵機(jī)

創(chuàng)建抽象類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();
}

創(chuàng)建敵機(jī)子類

有個(gè)特殊一點(diǎn)的地方: 因?yàn)橛?種敵機(jī),這里隨機(jī)1、2、3、4這4個(gè)數(shù)字作為屬性index,然后根據(jù)這個(gè)index來展現(xiàn)不同的飛機(jī)圖片,當(dāng)然也可以通過這個(gè)index來設(shè)置敵機(jī)不同的移動(dòng)速度,但是我為了偷懶,就全部一樣的移動(dòng)速度,嘿嘿。
移動(dòng)就是開啟線程讓y坐標(biāo)增加,沒什么好講的,這里加一個(gè)飛機(jī)碰撞,就是當(dāng)敵機(jī)跟我方飛機(jī)如何判斷碰撞的問題。

撞機(jī)分析(敵機(jī)與我機(jī)的撞機(jī))

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

從上面幾個(gè)圖可看出什么?因?yàn)閳D片是方形的,他們的4個(gè)頂點(diǎn)一定至少有一個(gè)在對(duì)方的范圍內(nèi)。再看一下從左邊撞擊的圖:

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

從上圖看到也是這樣,其他兩個(gè)方向的也是一樣的道理,為了穩(wěn)點(diǎn)我還加了一種情況:

1.判斷敵機(jī)的4個(gè)點(diǎn)是否在飛機(jī)范圍內(nèi),如果有則表示碰撞了。
2.如果1不成立,則反過來,判斷我機(jī)的4個(gè)點(diǎn)是否在敵機(jī)的范圍內(nèi),如果是表示碰撞了。

//判斷飛機(jī)與子彈是否碰撞
private boolean isPoint(MyPlane plane) {
	/*
	 * 
	 * 兩種情況
	 * 1.需要判斷敵機(jī)的4個(gè)點(diǎn)是否在飛機(jī)范圍內(nèi),如果有則表示碰撞了
	 * 2.如果步驟1不成立,則反過來,判斷我機(jī)的4個(gè)點(diǎn)是否在敵機(jī)的范圍內(nèi),如果是標(biāo)志碰撞了
	*/
	
	//方式1
	
	//左上角
	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;
	//只要有一個(gè)點(diǎn)在范圍內(nèi),則判斷為碰撞
	if(comparePointMyPlane(x1,y1,plane)|| comparePointMyPlane(x2,y2,plane)||comparePointMyPlane(x3,y3,plane)||comparePointMyPlane(x4,y4,plane) ){
		return true;
	}
	
	//方式1沒成立則用方式2判斷
	
	//方式2
	x1 = plane.getX();
	y1 = plane.getY();
	//右上角
	x2 = plane.getX()+plane.getWidth();
	y2 = plane.getY();
	//右下角
	x3 = plane.getX()+plane.getWidth();
	y3 =plane.getY()+plane.getHeight();
	//左下角
	x4 = plane.getX();
	y4 = plane.getY()+plane.getHeight();
	if(comparePoint(x1,y1)|| comparePoint(x2,y2)||comparePoint(x3,y3)||comparePoint(x4,y4) ){
		return true;
	}
	return false;
}
//用敵機(jī)的坐標(biāo)來判斷
private boolean comparePointMyPlane(int x,int y,MyPlane plane){
	//大于左上角,小于右下角的坐標(biāo)則肯定在范圍內(nèi)
	if(x>plane.getX() && y >plane.getY()
		&& x<plane.getX()+plane.getWidth() && y <plane.getY()+plane.getHeight()	){
		return  true;
	}
	return false;
}
//用我機(jī)的坐標(biāo)來判斷
private boolean comparePoint(int x,int y){
	//大于左上角,小于右下角的坐標(biāo)則肯定在范圍內(nèi)
	if(x>this.x && y >this.y
		&& x<this.x+this.width && y <this.y+this.height){
		return  true;
	}
	return false;
}

測(cè)試一下效果

在這里插入圖片描述

忘記說擊中敵機(jī)的了(原理跟剛才差不多,代碼直接放了)

//判斷擊中敵機(jī)
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();
			//刪除當(dāng)前子彈
			clear();
			
			//飛機(jī)爆炸
			enemyPlane.boom();
			
			if(panel.curCount>=panel.totalCount){
				panel.myPlane.setCanMove(false);
				panel.gameWin();
			}
		}
	}
}

//判斷飛機(jī)與子彈是否碰撞
private boolean isPoint(EnemyPlane plane) {
	//因?yàn)樽訌棻蕊w機(jī)小,所以只需要判斷子彈的4個(gè)點(diǎn)是否在飛機(jī)范圍內(nèi),如果有則表示碰撞了
	//左上角
	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;
	//只要有一個(gè)點(diǎn)在范圍內(nèi),則判斷為碰撞
	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){
	//大于左上角,小于右下角的坐標(biāo)則肯定在范圍內(nèi)
	if(x>plane.getX() && y >plane.getY()
		&& x<plane.getX()+plane.getWidth() && y <plane.getY()+plane.getHeight()	){
		return  true;
	}
	return false;
}

最后加上計(jì)分的、勝利、失敗等提示就完成了!

到此這篇關(guān)于一天時(shí)間用Java寫了個(gè)飛機(jī)大戰(zhàn),朋友直呼高手的文章就介紹到這了,更多相關(guān)Java飛機(jī)大戰(zhàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中Map.getOrDefault()方法舉例詳解

    Java中Map.getOrDefault()方法舉例詳解

    這篇文章主要介紹了Java?8中Map接口的getOrDefault()方法,該方法在獲取鍵值對(duì)時(shí),如果鍵不存在則返回默認(rèn)值,文中通過一個(gè)統(tǒng)計(jì)網(wǎng)站用戶點(diǎn)擊次數(shù)的應(yīng)用場(chǎng)景,詳細(xì)展示了getOrDefault()的用法,需要的朋友可以參考下
    2025-02-02
  • Slf4j+logback實(shí)現(xiàn)JSON格式日志輸出方式

    Slf4j+logback實(shí)現(xiàn)JSON格式日志輸出方式

    這篇文章主要介紹了Slf4j+logback實(shí)現(xiàn)JSON格式日志輸出方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java中Spring的Security使用詳解

    Java中Spring的Security使用詳解

    這篇文章主要介紹了Java中Spring的Security使用詳解,在web應(yīng)用開發(fā)中,安全無疑是十分重要的,選擇Spring Security來保護(hù)web應(yīng)用是一個(gè)非常好的選擇,需要的朋友可以參考下
    2023-07-07
  • springboot Jpa多數(shù)據(jù)源(不同庫)配置過程

    springboot Jpa多數(shù)據(jù)源(不同庫)配置過程

    這篇文章主要介紹了springboot Jpa多數(shù)據(jù)源(不同庫)配置過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 實(shí)例講解MyBatis如何防止SQL注入

    實(shí)例講解MyBatis如何防止SQL注入

    這篇文章通過實(shí)例代碼介紹MyBatis如何防止SQL注入,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • Guava反射工具使用示例詳解

    Guava反射工具使用示例詳解

    這篇文章主要為大家介紹了Guava反射工具使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • maven工程中jar包瘦身的五種方法

    maven工程中jar包瘦身的五種方法

    這篇文章主要介紹了maven工程中jar包瘦身的五種方法,幫助大家更好的理解和使用maven,感興趣的朋友可以了解下
    2021-02-02
  • Spring Cloud原理詳解

    Spring Cloud原理詳解

    今天小編就為大家分享一篇關(guān)于Spring Cloud原理詳解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • Java的優(yōu)先隊(duì)列PriorityQueue原理及實(shí)例分析

    Java的優(yōu)先隊(duì)列PriorityQueue原理及實(shí)例分析

    這篇文章主要介紹了Java的優(yōu)先隊(duì)列PriorityQueue原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • java中進(jìn)制的轉(zhuǎn)換,Byte與16進(jìn)制的轉(zhuǎn)換方法

    java中進(jìn)制的轉(zhuǎn)換,Byte與16進(jìn)制的轉(zhuǎn)換方法

    下面小編就為大家?guī)硪黄猨ava中進(jìn)制的轉(zhuǎn)換,Byte與16進(jìn)制的轉(zhuǎn)換方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-11-11

最新評(píng)論

武鸣县| 无棣县| 湘潭市| 天津市| 文登市| 绥宁县| 秦安县| 海原县| 涡阳县| 安新县| 阜宁县| 邹平县| 芜湖县| 平舆县| 淮阳县| 莱阳市| 玛曲县| 曲阳县| 曲麻莱县| 吉首市| 镇坪县| 海伦市| 灌南县| 红安县| 宝应县| 抚顺市| 丘北县| 雷山县| 福建省| 陆川县| 胶南市| 工布江达县| 故城县| 卫辉市| 沙河市| 临颍县| 华蓥市| 香港| 永德县| 新田县| 井研县|