一天時間用Java寫了個飛機大戰(zhàn)游戲,朋友直呼高手
一、代碼實現(xiàn)
創(chuàng)建窗口
首先創(chuàng)建一個游戲窗體類GameFrame,繼承至JFrame,用來顯示在屏幕上(window的對象),每個游戲都有一個窗口,設置好窗口標題、尺寸、布局等就可以。
/*
* 游戲窗體類
*/
public class GameFrame extends JFrame {
public GameFrame() {
setTitle("飛機大戰(zhàn)");//設置標題
setSize(526, 685);//設定尺寸
setLayout(new BorderLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//點擊關閉按鈕是關閉程序
setLocationRelativeTo(null); //設置居中
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;
//構造里面初始化相關參數(shù)
public GamePanel(JFrame frame){
this.setLayout(null);
mainFrame = frame;
mainFrame.setVisible(true);
}
@Override
public void paint(Graphics g) {
}
}
再創(chuàng)建一個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);//設定顯示
}
}
右鍵執(zhí)行這個Main類,窗口建出來了
??
二、創(chuàng)建菜單及菜單選項
創(chuàng)建菜單
private void initMenu(){
// 創(chuàng)建菜單及菜單選項
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");
}
實現(xiàn)ActionListener并重寫方法actionPerformed

actionPerformed方法的實現(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, "您確認要退出嗎", "",
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, "游戲中,您確認要重新開始嗎", "",
JOptionPane.YES_OPTION, JOptionPane.QUESTION_MESSAGE, null,
options, options[0]);
if (response == 0) {
//需要先結束游戲
realGameEnd(1);
restart();
}
}else{
restart();
}
}else if("help".equals(command)){
JOptionPane.showMessageDialog(null, "游戲開始后,要先動鼠標到飛機處,觸發(fā)移動效果,然后飛機就會跟隨鼠標移動!",
"提示!", 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)生動畫就要靠這個repaint。
//刷新線程,用來重新繪制頁面
private class RefreshThread implements Runnable {
@Override
public void run() {
while (startFlag) {
repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
在GamePanel的構造里面啟動這個主線程

有了這個主線程刷新,待會我們更新飛機的位置,飛機就會移動,不需要另外的代碼去調(diào)用repaint方法了(這是我的做法,僅供參考)。
五、創(chuàng)建我方飛機
創(chuàng)建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);
}
}
創(chuàng)建(這里只是創(chuàng)建好了飛機對象,需要繪制)
//創(chuàng)建自己飛機
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);
}
}

六、鼠標事件監(jiān)聽
加入監(jiān)聽是為了讓飛機跟隨鼠標移動,我這里定的規(guī)則是第一次鼠標必須移動到飛機上,然后飛機才會跟隨。
代碼里面用一個屬性canMove來控制,默認是false,只有鼠標第一次移入到飛機上時,這個屬性設置為true,然后就可以跟隨鼠標移動了。
//鼠標事件的創(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 ;
//飛機第一次是不允許移動的,只有飛機的canMove為true才去跟隨
if(myPlane.isCanMove()){
myPlane.move(x,y);
return;
}
//判斷鼠標的移入,如果移動到飛機上則canMove設置為true
if(myPlane.isPoint(x,y)){
myPlane.setCanMove(true);
}
}
};
addMouseMotionListener(mouseAdapter);
addMouseListener(mouseAdapter);
}
來實現(xiàn)一下MyPlane的move方法,這里處理了邊界,保證飛機不出界,同時保證鼠標在飛機的中間位置
//飛機跟隨鼠標移動
public void move(int x,int y) {
//判斷范圍,當橫向移動在窗口范圍內(nèi)
if(x-width/2>=0 && x<=panel.getWidth()-width/2){
this.x=x-width/2;
}
//判斷范圍,當縱向移動在窗口范圍內(nèi)
if(y-height/2>=0 && y<=panel.getHeight()-height/2){
this.y=y-height/2;
}
}

七、創(chuà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();
}
飛機類加入射擊方法,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)建敵機
創(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)建敵機子類
有個特殊一點的地方: 因為有4種敵機,這里隨機1、2、3、4這4個數(shù)字作為屬性index,然后根據(jù)這個index來展現(xiàn)不同的飛機圖片,當然也可以通過這個index來設置敵機不同的移動速度,但是我為了偷懶,就全部一樣的移動速度,嘿嘿。
移動就是開啟線程讓y坐標增加,沒什么好講的,這里加一個飛機碰撞,就是當敵機跟我方飛機如何判斷碰撞的問題。
撞機分析(敵機與我機的撞機)



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



從上圖看到也是這樣,其他兩個方向的也是一樣的道理,為了穩(wěn)點我還加了一種情況:
1.判斷敵機的4個點是否在飛機范圍內(nèi),如果有則表示碰撞了。
2.如果1不成立,則反過來,判斷我機的4個點是否在敵機的范圍內(nèi),如果是表示碰撞了。
//判斷飛機與子彈是否碰撞
private boolean isPoint(MyPlane plane) {
/*
*
* 兩種情況
* 1.需要判斷敵機的4個點是否在飛機范圍內(nèi),如果有則表示碰撞了
* 2.如果步驟1不成立,則反過來,判斷我機的4個點是否在敵機的范圍內(nèi),如果是標志碰撞了
*/
//方式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;
//只要有一個點在范圍內(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;
}
//用敵機的坐標來判斷
private boolean comparePointMyPlane(int x,int y,MyPlane plane){
//大于左上角,小于右下角的坐標則肯定在范圍內(nèi)
if(x>plane.getX() && y >plane.getY()
&& x<plane.getX()+plane.getWidth() && y <plane.getY()+plane.getHeight() ){
return true;
}
return false;
}
//用我機的坐標來判斷
private boolean comparePoint(int x,int y){
//大于左上角,小于右下角的坐標則肯定在范圍內(nèi)
if(x>this.x && y >this.y
&& x<this.x+this.width && y <this.y+this.height){
return true;
}
return false;
}
測試一下效果

忘記說擊中敵機的了(原理跟剛才差不多,代碼直接放了)
//判斷擊中敵機
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個點是否在飛機范圍內(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;
//只要有一個點在范圍內(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){
//大于左上角,小于右下角的坐標則肯定在范圍內(nèi)
if(x>plane.getX() && y >plane.getY()
&& x<plane.getX()+plane.getWidth() && y <plane.getY()+plane.getHeight() ){
return true;
}
return false;
}
最后加上計分的、勝利、失敗等提示就完成了!
到此這篇關于一天時間用Java寫了個飛機大戰(zhàn),朋友直呼高手的文章就介紹到這了,更多相關Java飛機大戰(zhàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- java版飛機大戰(zhàn)實戰(zhàn)項目詳細步驟
- java實現(xiàn)飛機大戰(zhàn)案例詳解
- java實戰(zhàn)之飛機大戰(zhàn)小游戲(源碼加注釋)
- Java實現(xiàn)飛機大戰(zhàn)-連接數(shù)據(jù)庫并把得分寫入數(shù)據(jù)庫
- java實現(xiàn)飛機大戰(zhàn)游戲
- Java實現(xiàn)游戲飛機大戰(zhàn)-III的示例代碼
- Java實現(xiàn)經(jīng)典游戲飛機大戰(zhàn)-I的示例代碼
- 基于Java語言在窗體上實現(xiàn)飛機大戰(zhàn)小游戲的完整步驟
- Java實現(xiàn)飛機大戰(zhàn)-II游戲詳解
- java實現(xiàn)飛機大戰(zhàn)小游戲
相關文章
try-cache-finally讀取文件錯誤try-with-resources使用方法
這篇文章主要為大家介紹了try-cache-finally讀取文件錯誤try-with-resources使用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-02-02
大數(shù)據(jù) java hive udf函數(shù)的示例代碼(手機號碼脫敏)
這篇文章主要介紹了大數(shù)據(jù) java hive udf函數(shù)(手機號碼脫敏),的相關知識,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06
詳解SpringCloud Gateway 2020.0.2最新版
這篇文章主要介紹了SpringCloud Gateway 2020.0.2最新版,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-04-04
Java實現(xiàn)利用圖片或視頻生成GIF并發(fā)送微信
這篇文章主要為大家詳細介紹了Java語言如何利用圖片或視頻實現(xiàn)生成GIF并發(fā)送微信的功能,文中的示例代碼講解詳細,感興趣的小伙伴可以嘗試一下2022-11-11
Spring Cloud Feign內(nèi)部實現(xiàn)代碼細節(jié)
Feign 的英文表意為“假裝,偽裝,變形”, 是一個http請求調(diào)用的輕量級框架,可以以Java接口注解的方式調(diào)用Http請求,而不用像Java中通過封裝HTTP請求報文的方式直接調(diào)用。接下來通過本文給大家分享Spring Cloud Feign內(nèi)部實現(xiàn)代碼細節(jié),感興趣的朋友一起看看吧2021-05-05

