很快,大二这个学期就要完结了,所学的大部分课程都快要结束了,Java课程也是如此。而Java这门课程也有一个惯例就是要做一个课程设计,老师给了我们三个选择,分别是飞机大战、推箱子和学生成绩管理系统。在经过深思熟虑后,我选择了飞机大战。一方面是觉得他比较有趣和好玩,另一方面,觉得这难度也适中,所以就选择了它。

现在,我对这个飞机大战进行解说。主要分为六个部分,分别是底层窗口和容器类、各种组件类、碰撞类、监听器类、线程类和音效媒体类。

游戏运行图片如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一 底层容器和窗口

在利用Java制作飞机大战这个游戏时,首先就要构造一个窗口。只有创建了窗口之后,你后面的游戏背景图片、飞机、子弹和空投等等,才能放入界面中。

Main主程序:程序的运行由此开始。

public class Main {

	public static void main(String[] args) {
		new BaseFrame();
		String bg="Music/bg.wav";
		Music music = new Music();
		music.playMusic(bg);
	}

}

在底层容器中,我是利用JFrame去构造。创建BaseFrame类去继承JFrame,然后再对鼠标设立监听器去控制英雄机的移动。后面再在创建MyPanel类去继承JPanel去实现窗口。
BaseFrame类:

import java.awt.*;
import javax.swing.*;
public class BaseFrame extends JFrame{

	public static int frameWidth=345;
	public static int frameHeight=575;
	
	public Graphics g;
	public MyPanel myPanel;
	//存放的是鼠标监听器
	public FrameMouseListener frameMouseListener;
	public FrameMouseClick frameMouseClick;
	
	//设置监听器
	public void setTouchListener1() {
		this.frameMouseListener=new FrameMouseListener();
		this.frameMouseListener.baseFrame=this;
		//注册监听器
		this.addMouseMotionListener(this.frameMouseListener);
	}
	
	public void setTouchListener2() {
		this.frameMouseClick=new FrameMouseClick();
		this.frameMouseClick.baseFrame=this;
		//注册监听器
		this.addMouseListener(this.frameMouseClick);
	}
	
	public BaseFrame() {
		super("飞机大战");
		//获得屏幕的分辨率
		Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
		//设置窗口的大小和位置
		this.setBounds(((int)screenSize.getWidth()-frameWidth)/2,50,frameWidth,frameHeight);
		//设置布局方式
		this.setLayout(null);

		    //创建一个MyPanel对象
			this.myPanel=new MyPanel();
			//设置MyPanel对象的大小和位置
			this.myPanel.setBounds(0,0,frameWidth,frameHeight);
			//设置监听器
			setTouchListener2();
			setTouchListener1();
			//将组件添加到窗口
			this.add(this.myPanel);
		 
		 //显示窗口
		this.setVisible(true);
		//设置窗口的关闭行为
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
}

MyPanel类:去存放飞机、子弹等等小组件,里面利用的计时器timer去控制整个游戏的进行,包括背景图的移动,子弹的发射,敌机的前进,空投的下落等等。

import java.awt.*;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.*;
public class MyPanel extends JPanel{
    
	Random ran=new Random();
	//存放的是背景图片
	public Image bgImage;
	public Image image1;
	public Image image2;
	public Image image3;
	public int timer=0;
	public int top=0;
	public long  score=0;
	public int flag=0;
	public DrawableThread drawableThread;
	public Player player;
	public Crash crash;
	public Boss boss;
	public int lives=3;
	public int drop=0;
	public int boss_flag=0;
	public Music music = new Music();
	public String all_bomb="Music/all_bomb.wav";
		
	public ArrayList<Enemy> enemies=new ArrayList<Enemy>();
	public ArrayList<Bullet> bullets=new ArrayList<Bullet>();
	public ArrayList<Airdrop> airdrops=new ArrayList<Airdrop>();
	public ArrayList<BossBullet> bossBullets=new ArrayList<BossBullet>();
	
	public MyPanel() {
		this.image1=Toolkit.getDefaultToolkit().getImage("Picture/start.png");
		this.image2=Toolkit.getDefaultToolkit().getImage("Picture/gameover.png");
		this.image3=Toolkit.getDefaultToolkit().getImage("Picture/Victory.png");
		this.bgImage=Toolkit.getDefaultToolkit().getImage("Picture/background.png");
		this.player=new Player(this);
		this.boss=new Boss(this);
		this.crash=new Crash(this);
		//创建线程 重绘Panel
		this.drawableThread=new DrawableThread(this);
		//启动线程
		this.drawableThread.start();
	}

	
	//绘制组件
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if(this.flag==0) {
			g.drawImage(image1, 0, 0, this.image1.getWidth(this), this.image1.getHeight(this),null);
		}
		if(this.flag==1) {
		//绘制背景图
		g.drawImage(this.bgImage,0,top-this.bgImage.getHeight(this),this.bgImage.getWidth(this),this.bgImage.getHeight(this),null);
		g.drawImage(this.bgImage,0,top,this.bgImage.getWidth(this),this.bgImage.getHeight(this),null);
		
		timer++;
		if(timer==10000)
			timer=0;
		//实现图片下移
		if(timer%5==0) {
			top++;
			if(top>=this.bgImage.getHeight(this))
			      top=0;
		}
		//绘制玩家
	    this.player.drawSelf(g);
	    if(this.score>450&&this.score<500)
	    {
	    	g.setFont(new Font("黑体",Font.PLAIN,40));
	    	g.setColor(Color.RED);
	    	g.drawString("BOSS即将来临!", 30, 120);
	    }
	    //绘制Boss
	    if(this.score>500) {
	       this.boss.drawSelf(g);
	       this.boss_flag=1;
	    }
	    if(this.boss.lives<0&&(this.boss.y+this.boss.height)<0) {
	    	this.flag=3;
	    	this.music.playMusic(all_bomb);
	    }
	    g.setFont(new Font("宋体",Font.PLAIN,20));
	    g.setColor(Color.WHITE);
	    g.drawString("分数:"+score, BaseFrame.frameWidth/15, BaseFrame.frameHeight/10);
	    g.drawString("生命:"+lives,BaseFrame.frameWidth/15, BaseFrame.frameHeight/10+20);
	    
	    if(timer%20==0) {
	    	if(this.player.attackMode==1) {
	    		//创建子弹
	    		Bullet bullet=new Bullet(this);
	    		//设置坐标
	    		bullet.x=this.player.x+this.player.width/2-bullet.width/2;
	    		bullet.y=this.player.y;
	    		//存入arraylist中
	    		this.bullets.add(bullet);
	    	}
	    	if(this.player.attackMode==2) {
	    		//创建子弹
	    		Bullet bullet1=new Bullet(this);
	    		//设置坐标
	    		bullet1.x=this.player.x+this.player.width/2-bullet1.width/2;
	    		bullet1.y=this.player.y;
	    		//存入arraylist中
	    		this.bullets.add(bullet1);
	    		//创建子弹
	    		Bullet bullet2=new Bullet(this);
	    		//设置坐标
	    		bullet2.x=this.player.x+this.player.width/2-bullet2.width/2-20;
	    		bullet2.y=this.player.y;
	    		//存入arraylist中
	    		this.bullets.add(bullet2);
	    		//创建子弹
	    		Bullet bullet3=new Bullet(this);
	    		//设置坐标
	    		bullet3.x=this.player.x+this.player.width/2-bullet3.width/2+20;
	    		bullet3.y=this.player.y;
	    		//存入arraylist中
	    		this.bullets.add(bullet3);
	    	}
	    	//创建Boss子弹
	    	if(timer%200==0&&this.score>500&&this.boss.lives>0) {
	    	    BossBullet bossBullet=new BossBullet(this);
	    	    bossBullet.x=this.boss.x+this.boss.width/2-bossBullet.width/2;
	    	    bossBullet.y=this.boss.y+this.boss.height;
	    	    this.bossBullets.add(bossBullet);
	    	}
	    	//创建敌机
	    	if(timer%50==0) {
	    	  Enemy enemy=new Enemy(this);
	    	  enemy.x=ran.nextInt(306);//随机生成x坐标
	    	  enemy.y=-30;
	    	  this.enemies.add(enemy);
	    	}
	    	//创建空投
	    	if(timer%1000==0) {
	    		Airdrop airdrop=new Airdrop(this);
	    		airdrop.x=ran.nextInt(346);//随机生成x坐标
	    		airdrop.y=-40;
	    		this.airdrops.add(airdrop);
	    	}
	    }
	   //画出所有子弹
	    for(int i=0;i<bullets.size();i++)
	    	this.bullets.get(i).drawSelf(g);
	   //画出Boss子弹
	    for(int i=0;i<bossBullets.size();i++)
	    	this.bossBullets.get(i).drawSelf(g);
	   //画出敌机
	    for(int i=0;i<enemies.size();i++) {
	    	this.enemies.get(i).drawSelf(g);
	    }
	   //画出空投
	    for(int i=0;i<airdrops.size();i++) {
	    	this.airdrops.get(i).drawSelf(g);
	    	if(this.crash.Boom3(this.airdrops.get(i), this.player.x, this.player.y)) {
	    		this.airdrops.remove(i);
	    		this.drop++;
	    	}
	    }
	    if(this.drop>=3)
	    	this.player.attackMode=2;
	   //子弹与敌机碰撞
	   for(int i=0;i<bullets.size();i++) {
		   Bullet bullet=this.bullets.get(i);
		   
		   for(int j=0;j<enemies.size();j++) {
			   Enemy enemy=this.enemies.get(j);
			   if(this.crash.Boom1(bullet, enemy)) {
				   this.enemies.remove(j);
				   this.bullets.remove(i);
				   this.score+=10;
				   break;
			   }
		   }
	   }
	   //boss被子弹击中
	   for(int i=0;i<bullets.size();i++) {
		   Bullet bullet=this.bullets.get(i);
		   if(this.crash.Boom5(bullet, this.boss)) {
				  this.boss.lives--;
				  this.score+=2;
				  this.bullets.remove(i);
			}
	   }
	   //英雄机与敌机相撞
	   for(int i=0;i<enemies.size();i++) {
		   if(this.crash.Boom2(this.enemies.get(i),this.player.x, this.player.y))
			   {
			       this.enemies.remove(i);
			       this.lives--;
			       if(this.lives==0)
			    	   this.flag=2;
			       break;
			   }
	   }
	  //英雄机被boss子弹击中
	   for(int i=0;i<bossBullets.size();i++) {
		   if(this.crash.Boom4(this.bossBullets.get(i), this.player.x, this.player.y)) {
			   this.bossBullets.remove(i);
			   this.lives--;
			   if(this.lives==0)
				   this.flag=2;
			   break;
		   }
	   }
	  
	   
	}
	//游戏失败界面
	if(this.flag==2) {
		g.drawImage(image2, 0, 0, this.image2.getWidth(this), this.image2.getHeight(this),null);
		g.setFont(new Font("黑体",Font.PLAIN,20));
    	g.setColor(Color.BLACK);
    	g.drawString("分 数:"+this.score, 120, 300);
	}
	//游戏胜利界面
	if(this.flag==3) {
		g.drawImage(image3, 0, 0, this.image3.getWidth(this), this.image3.getHeight(this),null);
		g.setFont(new Font("黑体",Font.PLAIN,20));
    	g.setColor(Color.BLACK);
    	g.drawString("分 数:"+this.score, 120, 300);
    	g.drawString("恭喜你击败了BOSS,获得了胜利", 20, 350);
	}
	
  }
}

二 各种组件类

各种组件类中就比较多了,包括英雄机类,子弹类,空投类,boss类等等,以下一一通过代码展示。
英雄机类:

import java.awt.*;
import javax.swing.*;

public class Player {

	public MyPanel myPanel;
	public int width=60;
	public int height=61;
	public int x;
	public int y;
	public int attackMode=1;//火力等级
	public int imageindex=0;//存放当前图片下标
	public Image[] images=new Image[] {
			Toolkit.getDefaultToolkit().getImage("Picture/player1.png"),
			Toolkit.getDefaultToolkit().getImage("picture/player2.png"),
			Toolkit.getDefaultToolkit().getImage("Picture/playerX.png")
	};
	
	public Player(MyPanel myPanel) {
		this.myPanel=myPanel;
		this.x=(BaseFrame.frameWidth-this.width)/2;
		this.y=(BaseFrame.frameHeight-this.height+260)/2;
	}
	
	public void drawSelf(Graphics g) {
		g.drawImage(this.images[imageindex], x, y, width, height, null);
		if(this.myPanel.timer%50==0) {
			if(this.myPanel.score<=300) {
			imageindex++;
			if(this.imageindex==2)
				this.imageindex=0;
			}
			else {
				imageindex=2;
			}
		}
	}
}

敌机类:

import java.awt.*;
import java.util.Random;

import javax.swing.*;
public class Enemy {
     public MyPanel myPanel;
     public int width=40;
     public int height=25;
     public int x;
     public int y;
     public Image image;
     
     public Enemy(MyPanel myPanel) {
    	 this.myPanel=myPanel;
    	 this.image=Toolkit.getDefaultToolkit().getImage("Picture/enemy.png");
    	
     }
     public void drawSelf(Graphics g) {
    	 g.drawImage(this.image, x, y, width, height, null);
    	 if(this.myPanel.timer%1==0)
    		 y++;
    	 if(y+height>BaseFrame.frameHeight)
    		 this.myPanel.enemies.remove(this);
     }
}

boss类:

import java.awt.*;
public class Boss {

	public MyPanel myPanel;
	public int width=100;
	public int height=73;
	public int x;
	public int y;
	public Image image;
	public int flag=1;
	public int lives=500;
	
	public Boss(MyPanel myPanel) {
		this.myPanel=myPanel;
		this.image=Toolkit.getDefaultToolkit().getImage("Picture/Boss.png");
		this.x=(BaseFrame.frameWidth-this.width)/2;
		this.y=0;
	}
	public void drawSelf(Graphics g) {
		g.drawImage(this.image, x, y, width, height, null);
		if(this.myPanel.timer%3==0&&this.y<=100&&lives>0)
			this.y++;
		if(lives<0)
			this.y--;
		if(this.myPanel.timer%3==0&&this.y>100) {
			if(this.x+this.width>BaseFrame.frameWidth)
				flag=0;
			if(this.x==0)
				flag=1;
			if(flag==1)
				this.x++;
			if(flag==0)
				this.x--;
		}
	}
}

空投类:

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.util.Random;

public class Airdrop {

	public MyPanel myPanel;
	public int width=40;
	public int height=40;
	public int x;
	public int y;
	public int flag=0;
	Random ran;
	public Image image;
	
	public Airdrop(MyPanel myPanel) {
		this.myPanel=myPanel;
		this.image=Toolkit.getDefaultToolkit().getImage("Picture/airdrop.png");
	}
	
	public void drawSelf(Graphics g) {
		g.drawImage(this.image, x, y, width, height, null);
		if(this.myPanel.timer%3==0) {
			y++;
			if(flag==0) {
				x++;
			}
			if(flag==1) {
				x--;
			}
			if(this.x+40>BaseFrame.frameWidth)
				flag=1;
			if(this.x<0)
				flag=0;
		}
		
		if(y+height>BaseFrame.frameHeight)
			this.myPanel.airdrops.remove(this);
	
	}
	
}

英雄机子弹类:

import javax.swing.*;
import java.awt.*;
public class Bullet {

	public MyPanel myPanel;
	public int width=6;
	public int height=14;
	public int x;
	public int y;
	public int index=0;
	public Image[] bulletImage=new Image[] {
			Toolkit.getDefaultToolkit().getImage("Picture/ammo.png"),
			Toolkit.getDefaultToolkit().getImage("Picture/bullet1.png")
	};
	
	public Bullet(MyPanel myPanel) {
		this.myPanel=myPanel;
	}
	//画子弹
	public void drawSelf(Graphics g) {
		g.drawImage(this.bulletImage[index], x, y, width, height, null);
		if(this.myPanel.timer%1==0)
			y--;
		if(y<0)
			this.myPanel.bullets.remove(this);
		if(this.myPanel.score>100)
			index=1;
	}
}

boss子弹类:

import java.awt.*;
public class BossBullet {

	public MyPanel myPanel;
	public int width=20;
	public int height=20;
	public int x;
	public int y;
	public int index=0;
	public Image[] images=new Image[] {
			Toolkit.getDefaultToolkit().getImage("Picture/BossBullet.png"),
			Toolkit.getDefaultToolkit().getImage("Picture/BossBullet1.png"),
			Toolkit.getDefaultToolkit().getImage("Picture/BossBullet2.png")
	};
	
	public BossBullet(MyPanel myPanel) {
		this.myPanel=myPanel;
	}
	
	public void drawSelf(Graphics g) {
		g.drawImage(this.images[index], x, y, width, height, null);
		if(this.myPanel.timer%1==0)
			y++;
		if(y>580)
			this.myPanel.bossBullets.remove(this);
		if(this.myPanel.timer%2==0) {
			index++;
			if(index==images.length)
				index=0;
		}
		if(y>BaseFrame.frameHeight)
			this.myPanel.bossBullets.remove(this);
	}
	
}

三 组件碰撞类

因为飞机大战中,重要利用的就是各种组件相碰撞而制作成的游戏,所以这部分肯定少不了。这里需要对各种组件进行判断,看他们是否相碰撞,判断的依据就是他们之间的距离是否小于最小距离。
碰撞类:

public class Crash {
	public MyPanel myPanel;
	Music music = new Music();
	public String enemy_bomb="Music/enemy_bomb.wav";
	public String hero_bomb="Music/hero_bomb.wav";
	public String boss_boom="Music/10804.wav";
	public Crash(MyPanel myPanel) {
		this.myPanel=myPanel;
	}
    //判断子弹和敌机碰撞
	public boolean Boom1(Bullet bullet,Enemy enemy) {
		int bulletx,bullety;
		int enemyx,enemyy;
		boolean crash=false;
		//子弹坐标
		bulletx=bullet.x+3;
		bullety=bullet.y+7;
		//敌机坐标
		enemyx=enemy.x+20;
		enemyy=enemy.y+12;
		
		if(Math.abs(enemyx-bulletx)<20&&Math.abs(bullety-enemyy)<12) {
			crash=true;//如果相撞返回真
			music.playMusic(enemy_bomb);
			
		}
		return crash;
	}
	//判断子弹击中boss机
		public boolean Boom5(Bullet bullet,Boss boss) {
			int bulletx,bullety;
			int bossx,bossy;
			boolean crash=false;
			//子弹坐标
			bulletx=bullet.x+4;
			bullety=bullet.y+9;
			//敌机坐标
			bossx=boss.x+50;
			bossy=boss.y+36;
			
			if(Math.abs(bulletx-bossx)<50&&Math.abs(bullety-bossy)<36&&this.myPanel.boss_flag==1) {
				crash=true;//如果相撞返回真
				music.playMusic(enemy_bomb);
			}
			return crash;
		}
	//飞机碰撞敌机
	public boolean Boom2(Enemy enemy,int x,int y) {
		int enemyx,enemyy;
		boolean crash=false;
		//敌机坐标
		enemyx=enemy.x+20;
	    enemyy=enemy.y+12;
	    //英雄机坐标
	    x=x+40;
	    y=y+36;
	    //相撞条件
	    if(Math.abs(x-enemyx)<50&&Math.abs(y-enemyy)<50) {
	    	crash=true;
	    	music.playMusic(hero_bomb);
	    }
	    return crash;
	}
	//英雄机被Boss的子弹击中
		public boolean Boom4(BossBullet bossBullet,int x,int y) {
			int bossbx,bossby;
			boolean crash=false;
			//敌机坐标
			bossbx=bossBullet.x+10;
		    bossby=bossBullet.y+10;
		    //英雄机坐标
		    x=x+45;
		    y=y+36;
		    //相撞条件
		    if(Math.abs(x-bossbx)<50&&Math.abs(y-bossby)<50) {
		    	crash=true;
		    	music.playMusic(hero_bomb);
		    }
		    return crash;
		}
	//飞机获取空投
	public boolean Boom3(Airdrop airdrop,int x,int y) {
		int airdropx,airdropy;
		boolean crash=false;
		//空投坐标
		airdropx=airdrop.x;
	    airdropy=airdrop.y;
	    //英雄机坐标
	    x=x-30;
	    y=y-30;
	    //相撞条件
	    if(airdropx>x+20&&y-airdropy<20&&airdropx<x+60) 
	    	crash=true;
	    return crash;
	}
	
}

四 线程类

这里主要控制游戏的进行,飞机大战中利用了线程去实现,从而使游戏的表现更好,能一致进行。
线程类:

import java.awt.*;
import javax.swing.*;
public class DrawableThread extends Thread{
       
	public MyPanel myPanel;
	
	public DrawableThread(MyPanel myPanel) {
		this.myPanel=myPanel;
	}
	
	public void run() {
		while(true) {
			this.myPanel.repaint();//重绘调用paintComponent
			try {
				Thread.currentThread().sleep(1);
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

五 监听器类

这里主要使用监听器去实现用鼠标控制英雄机的移动,和用鼠标控制游戏的开始和结束。
控制英雄机的移动:

import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
public class FrameMouseListener extends MouseMotionAdapter{

	public BaseFrame baseFrame;

	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub
		this.baseFrame.myPanel.player.x=e.getX()-this.baseFrame.myPanel.player.width/2;
		this.baseFrame.myPanel.player.y=e.getY()-this.baseFrame.myPanel.player.height/2;
	}
	
}

控制游戏的开始和结束:

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
public class FrameMouseClick extends MouseAdapter{

	public BaseFrame baseFrame;
	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		if(this.baseFrame.myPanel.flag==2||this.baseFrame.myPanel.flag==3)
			{
			    this.baseFrame.dispose();//直接退出
			    
			    new BaseFrame();
			}
		this.baseFrame.myPanel.flag=1;
	}
	
}

六 音效媒体类

为了增加游戏的体验感和沉浸感,我给游戏添加了游戏背景音乐和子弹击中音效和英雄机死亡音效,效果不错。

import java.io.File;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;

public class Music {
	
	
	void playMusic(String musicLocation)
	{
		try
		{
			File musicPath = new File(musicLocation);
			
			if(musicPath.exists())
			{
				AudioInputStream audioInput = AudioSystem.getAudioInputStream(musicPath);
				Clip clip = AudioSystem.getClip();
				clip.open(audioInput);
				clip.start();
				clip.loop(0);
				
			}
					}
		catch(Exception ex)
		{
			ex.printStackTrace();
		}
	}

}

以上所有的代码展示完毕,感谢你的浏览。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐