简单制作飞机大战游戏。

飞机大战(初级)(一)

      因为最近有做这个的实训,每天一点点的学习。因为自己也是个初学者,希望自己所做的这些也能帮助简单学习java的朋友,这是第一次在这上面去分享这些,一方面希望自己能进步,能交更多的朋友,有更好的空间,也能和大家一起进步。

一· 流程图

 

这个是最简单的框架。三个界面:开始界面,游戏界面,结束界面。

 

这个是三个类,战机,敌机,子弹三个类的关系。

二· 整体概括

        通过平时玩的飞机大战,我们可以想象得到我们通常玩的飞机大战游戏的流程。我们应先总结一下此次可能会用到的一些知识。

    (一)三大界面

      1.开始界面

          界面主要显示开始游戏,结束游戏(退出游戏中,设置一个是否确认退出的消息框),两个按钮。主要为GUI设计,

总共有三个界面;

     2.游戏界面

  • 设置游戏背景    
  • 实现游戏的运行,鼠标事件战机的移动,敌机自由下落,敌机与子弹的碰撞,子弹的上升,敌机与战机的碰撞。    

     3. 结束界面

         界面显示游戏完成及最终得分。并显示是否退出还是重新游戏

(二)三大类

    1. 战机:

              属性:背景,速度,总血量,实时血量,坐标x,y,半径r。分数。

    2. 敌机:

              属性:背景,随机出现,坐标x,y,半径r,速度,敌机数量。

    3. 子弹:发射速度

 (三)核心功能

     最后,在所有这些完成后,最核心代码实现整个游戏的运行,子弹和战机的碰撞,子弹和敌机的碰撞

(四)详细实现过程

开始界面

  1. 创建Start()类,继承JFrame,实现ActionListener接口。
  2. 初始化成员,并将其设置为私有变量。
  3. 通过JBtton设立两个按钮button_startbutton_end
  4. 通过Dimension获取屏幕,目的为实现开始界面窗口位于屏幕中央。
  5. 创建面板JPanel,在面板上实现两个按钮的创建
  6. 建立主函数,为整个游戏的唯一实现入口
  7. 使用鼠标或者行动事件对两个按钮进行监听。

游戏窗口

  1. 创建Started(),继承JFrame。
  2. 建立无参构造函数,在其中对窗口的各种属性进行实现。
  3. 通过Thread创建线程,th.start()启动线程。

是否退出窗口

  1. 创建Exit()类,以行动事件作接口。
  2. 建立无参构造函数,在其中对窗口的各种属性进行实现。
  3. 确定事件源,进行监听,设置判断语句,来完成是否退出的实现。

战机类

  1. 创建Hero()类。
  2. 初始化战机的坐标x,y,半径r,总血量AllBlood,实时血量Blood,分数,score,以及战机的展示形式,及调用图片,设置其访问器和设置器。
  3. 建立paint()将关于飞机的所有都画出来,通过,g.drawImage来进行绘画。
  4. 绘制总血量和实时时,应将实时血量颜色填充稍微深,使得更清楚明白。

敌机类

  1. 创建EenemyPlane()类。
  2. 初始化敌机的坐标x,y以及半径r,速度speed,敌机数量epNum,并设置他们的访问器和设置器。
  3. 建立函数EnemyPlane()对epNum数量实现随机性,通过Math.random()实现,并建立String epString = null;将敌机图片随机展示,则使得敌机随机出现,数量位置不定。
  4. 建立函数changeEnemyPlane(),此函数与EnemyPlane()无不同,但此函数在随后的MyPlane中,当敌机坠毁时会被调用。

子弹类

  1. 创建Bullet()类。
  2. 初始化子弹的位置x,y,半径r,子弹的展现形式,及他的访问器和修改器。
  3. 最后画子弹。设置子弹位置。

实现类

  1. 创建MyJPlane()类,继承JPanel,实现Runnable,MouseMotionListener的接口
  2. 初始化战机,建立战机,同时创建子弹和敌机的集合类,初始化背景。
  3. 建立有参构造函数,初始化屏幕的宽和高,定义背景图片,实现随机出现。初始化战机,初始化敌机,初始化子弹。
  4. 建立paint()将这些全部画出来。
  5. 建立文件保存最高分。
  6. 在try()模块中,建立if-else语句,如果文件不存在,则创建新文件,写入分数,刷新,关闭。否则,将字节流转换为字符流,建立当前分数,并进行判断。
  7. 在mouseMoved中实现当鼠标移动,则战机挪动。
  8. 生成的run函数中,
  9. 通过while(true)建立一个死循环,初始化子弹,让子弹每十个单位发射一个。
  10. 通过for()让每个敌机下落,并在循环中判断敌机是否已经下落出去,在if-else语句判断中,如果敌机下落出去,则将当前敌机移除,即epList.remove(i);并调用changeEnemyPlane()实现再产生一个新的敌机,如果没有落出屏幕,则继续下落,并设置以不同速度。
  11. 建立函数isHeart()函数,判断敌机与子弹是否相撞,通过两边平方和大于第三边进行判断,设置成boolean类型。返回true代表相撞,false代表未相撞。
  12. 判断敌机与战机是否相撞,则判断是true还是false,如果是true,则移除此敌机,随机产生别的敌机。并且实现实时血量的减少。
  13. 判断敌机与子弹是否相撞,如果是true,则移除当前敌机,并随机产生新的,同时,分数增加。
  14. 最后进行随时的重写repaint();

结束界面

  1. 判断当分数小于零时,跳转到结束界面。
  2. 在结束界面显示是否要退出还是继续游戏。

(五)日志

 第一天

今天为编译代码第一天,主要实现开始界面的两个按钮,及游戏界面的一个窗口,及开始界面到游戏界面的一个跳转三个任务。主要代码与注释如下,所有解释均在注释中体现。

1.开始界面

package cn.rjxy.planegame;


import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;


/**
 * 功能描述:飞机大战开始界面
 *创建窗体,标题,位置,关闭方式,禁止用户调整,可见性
 */


public class Start extends JFrame implements ActionListener{
private static final long serialVersionUID = 1L;
//为了系统安全性,我们会考虑把成员属性私有
private JButton button_start = new JButton("开始游戏");
private JButton button_end = new JButton("结束游戏");
public Start() {
JFrame frame = new JFrame("开始界面");//或者通过setTitle也可以实现窗口命名 :frame.setTitle("飞机大战");
//获取屏幕尺寸,主要为实现窗口能位于中央。
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();

frame.setBounds((dim.width-300)/2, (dim.height-400)/2, 300, 400);//此的距离都是距离左上角,宽高单位是像素,                                                                                                                                          根据屏幕尺寸使放中央
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭方式
frame.setResizable(false);//窗口大小不可修改

frame.setVisible(true);//可见性,一个图形默认是不可见的,此将改为可见



                 //frame.add(button_start);这样做会覆盖掉。
                 //frame.add(button_end);
                //所以应该在面板上添加按钮
JPanel panel = new JPanel();//创建面板
panel.add(button_start);
button_start.addActionListener(this);//1.确定事件源2.注册监听器,当前对象为this
panel.add(button_end);
button_end.addActionListener(this);
frame.add(panel);
}
public static void main(String[] args)
{
new Start();


}

//这里主要为实现开始界面到游戏界面的跳转

public void actionPerformed(ActionEvent e){//可以使用行动或鼠标事件
//监听开始按钮
if(e.getSource()==button_start){
new Started();//打开游戏的主界面
}
//监听结束按钮
if(e.getSource()==button_end){//两者为并列关系,所以if  if
//System.exit(0);这种做法为直接退出
new Exit();//这样为调用Exit()函数,而此函数实现另一个消息窗口,使得弹出是否确定退出窗口。
}




}

}

 

2.Exit()函数

此与上一个函数雷同,所以不再多做解释

package cn.rjxy.planegame;


import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class Exit implements ActionListener{
//为了系统安全性,我们会考虑把成员属性私有
private JButton button_yes = new JButton("确定");
private JButton button_no = new JButton("取消");
public Exit() {
JFrame frame = new JFrame("退出游戏");//建立窗口,窗口名称
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭方式
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();//获取屏幕大小
frame.setBounds((dim.width-200)/2, (dim.height-100)/2, 200,100);//使得窗口位于屏幕中央
frame.setResizable(false);//不可修改
frame.setVisible(true);//可见性
//在面板上创建按钮
JPanel panel = new JPanel();
panel.add(button_yes);
button_yes.addActionListener(this);//1.确定事件源2.注册监听器,当前对象,this
panel.add(button_no);
button_no.addActionListener(this);
frame.add(panel);




}


@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource()==button_yes)
{
System.exit(0);
}
if(e.getSource()==button_no)
{
new Start();
}

}

}

3.游戏界面的窗口

package cn.rjxy.plaingame;
/**
 * 功能描述:游戏主界面
 */


import java.awt.Dimension;
import java.awt.Toolkit;


import javax.swing.JFrame;


public class Started extends JFrame {
private static final long serialVersionUID = 1L;


public Started() {
JFrame frame = new JFrame("飞机大战");
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
frame.setSize(dim);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);


}

/*public static void main(String[] args) {
new Started();
}
*/



}

今天的运行结果 

第二天

   第一天是很简单的将两个界面做了出来,大家都是小白嘛,第二天循序渐进,我们可以继续去完成三个类,也就是战机,敌机,子弹类,将其中的属性初始化完整,这相对是比较简单的。在这里面,有一个需要插入的是,需要将java中加入图片,import->General->Fiel System->选择图片缩存储的地方。这样,就将你战机,敌机子弹的模样存储在了代码文件里,更方便调用。其他类的详细叙述会在代码中说。

1.战机类

package cn.rjxy.planegame;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;

/**
 * 战机类:属性;坐标:x,y,r,allBlood,blood,score,heroIng
                        方法:属性的访问器和设置器。paint()
 *
 */

public class Hero {
	private int x;//坐标
	private int y;
	private int r;//半径
	private int allBlood;//总血量
	private int blood;//实时血量
	private int score;//分数
	private Image heroImg = new ImageIcon("image/img/hero.png").getImage();//展示战机
	public int getX() {
		return x;
	}
	public int setX(int x) {
		return this.x=x;
	}
	public int getY() {
		return y;
	}
	public int setY(int y) {
		return this.y=y;
	}
	public int getR() {
		return r;
	}
	public int setR(int r) {
		return this.r=r;
	}
	public int getAllBlood() {
		return allBlood;
	}
	public int setAllBlood(int allblood) {
		return this.allBlood=allblood;
	}
	public int getBlood() {
		return blood;
	}
	public int setBlood(int blood) {
		return this.blood=blood;
	}
	public int getScore() {
		return score;
	}
	public int setScore(int score1) {
		return 	this.score =score1 ;
	}
	
	public void paint(Graphics g) {
		//绘画战机
		g.drawImage(heroImg, x, y,null);
		//绘画总血条
		g.setColor(Color.ORANGE);
		g.fillRect(20, 20, allBlood, 20);//左右顶点,长宽
		//绘制实时血条
		g.setColor(Color.RED);
		g.fillRect(20, 20, blood, 20);
		//绘画战机实时分数
		g.setFont(new Font("宋体",Font.BOLD,50));
		g.setColor(Color.GREEN);
		g.drawString("当前分数:"+score, 800, 50);
		
	}
	
	

}

2.敌机类

package cn.rjxy.planegame;

import java.awt.Graphics;
import java.awt.Image;

import javax.swing.ImageIcon;

/**
 * 
 * 敌机类
 * 属性:敌机中心坐标x,y,敌机有效半径r,speed,敌机背景图片epImg
 * 方法:paint();
 */

public class EnemyPlane {
	private int x,y,r,speed;
	private Image epImg;
	private int epNum = 0;	//敌机数量
	public int getX() {
		return x;
	}
	public int setX(int x1) {
		return this.x=x1;
	}
	public int getY() {
		return y;
	}
	public int setY(int y1) {
		return this.y=y1;
	}
	public int getR() {
		return r;
	}
	public int setR(int r1) {
		return this.r=r1;
	}
	public int getSpeed() {
		return speed;
	}
	public int setSpeed(int speed1) {
		return this.speed=speed1;
	}
	public int getEpNum() {
		return epNum;
	}
	public int setEpNum(int epNum1) {
		return this.epNum=epNum1;
	}
	public void EnemyPlane() {
		epNum = (int)(Math.random()*15)+1;//敌机0——15随机(这是敌机与战机不同的地方)
		String epString = null;
//通过if-else实现每张图片都能随机展现。因为图片名称刚好为01-19
		if(epNum<=9) {
			epString = "0"+epNum;	
		}
		else
			epString=""+epNum;
		//分配图片
		 epImg = new ImageIcon ("image/img/ep"+epString+".png").getImage();//保证每张图片都能展现
		
		
	}
    //这个与EnemyPlane里面是一样的,所实现的也是一样的,这是在敌机战机发生碰撞后会调用的。在此就不删除了
	public void changeEnemyPlane() {
		//随机显示敌机
		epNum = (int)(Math.random()*15)+1;//敌机0——15随机
		String epString = null;
		if(epNum<=9) {
			epString = "0"+epNum;	
		}
		else
			epString=""+epNum;
		//分配图片
		 epImg = new ImageIcon ("image/img/ep"+epString+".png").getImage();
		
	}
	public void paint(Graphics g) {//画敌机
		g.drawImage(epImg, getX()-getR(), getY()-getR(), null);
		
	}
}

3.子弹类

package cn.rjxy.planegame;

import java.awt.Graphics;
import java.awt.Image;

import javax.swing.ImageIcon;

/**
 * 
 * 功能:子弹类
 * 属性:中心坐标x,y,子弹的有效半径r,背景图片bulletImg
 * 方法:属性的访问器和设置器,打游戏过程中子弹绘画功能:paint()
 * 
 */

public class Bullet {
	private int x,y,r;//坐标  半径
	private Image bulletImg = new ImageIcon("image/img/fire.png").getImage();//子弹图片
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getR() {
		return r;
	}
	public void setR(int r) {
		this.r = r;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
	public Image getBulletImg() {
		return bulletImg;
	}
	public void setBulletImg(Image bulletImg) {
		this.bulletImg = bulletImg;
	}
	
	public void paint(Graphics g) {
		g.drawImage(bulletImg, x, y-r, null);
	}
	
	

}

第三天

在前两天可以说是将游戏界面上的东西显示了出来,那么今天,就是我们应该如何实现他们的碰撞。即战机与敌机相撞,敌机与子弹相撞。代码在下面体现。

package cn.rjxy.planegame;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.ArrayList;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

//游戏界面 实现多线程
public class MyJPanel extends JPanel implements Runnable,MouseMotionListener{
private Hero hero=new Hero();
private ArrayList<EnemyPlane> epList=new ArrayList<EnemyPlane>();//创建集合类
private ArrayList<Bullet> buList=new ArrayList<Bullet>();
//背景图片属性
private Image bgImg1=null;

private  int bgX,bgY;
//初始化战机数目
private int epNum=10;
//初始化背景
private Image bgImg=new ImageIcon("image/img/bg2.jpg").getImage();
private Image goImg=new ImageIcon("image/img/gameover.jpg").getImage();
    public MyJPanel(Dimension dim) {
	//初始化屏幕的高和宽   定义背景图片
	      bgX=dim.width;
	      bgY=dim.height;
	      int bgNum=(int )((Math.random()*5)+1);
	      bgImg = new ImageIcon("image/img/bg"+bgNum+".jpg").getImage();
	      
	//初始化战机
	hero.setR(57);
	hero.setX(bgX/2);
	hero.setY(bgY-3*hero.getR());
	hero.setAllBlood(200);
	hero.setBlood(200);
	hero.setScore(0);
	//初始化敌机
	for(int i=0;i<epNum;i++) {
		EnemyPlane ep=new EnemyPlane();
		ep.setR(30);//敌机半径
		ep.setX((int)(Math.random()*bgX)+1);
		ep.setY((int)(Math.random()*bgY)+1);
		ep.setSpeed((int)(Math.random()*5)+1);
		epList.add(ep);
	}
	this.addMouseMotionListener(this);
}
public void paint(Graphics g) {
	super.paint(g);
	//画背景
	g.drawImage(bgImg, 0, 0, bgX, bgY, null);
	//画战机
	hero.paint(g);
	//画敌机
	for(int i=0;i<epList.size();i++) {
		epList.get(i).paint(g);
	}
	//画子弹
	for(int i=0;i<buList.size();i++) {
		buList.get(i).paint(g);
	}
	if(hero.getBlood()<=0) {
		g.drawImage(goImg, 0, 0,bgX, bgY, null);
	}
}
		g.drawString("本次分为"+maxScore,bgx/2,bgy-200);
		
	}

}
	
	@Override
	//鼠标按下并拖动 战机的坐标更改
	public void mouseDragged(MouseEvent e) {
		// TODO Auto-generated method stub
		hero.setX(e.getX());
		hero.setY(e.getY());
		repaint();
	}
	@Override
        //鼠标挪动,战机的坐标更改
	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub
		hero.setX(e.getX());
		hero.setY(e.getY());
		repaint();
	}
	@Override
        //此函数中实现碰撞,
	public void run() {
		// TODO Auto-generated method stub
		int count=0;
		while(true) {
			if(hero.getBlood()>0) {
				//初始化子弹
				//子弹步进了10,新生成一个子弹
				if(count%10==0) {
					initBullet();
				}
				count++;	
			}
		
		//让敌机下落 下落同时判断每个敌机是否与子弹或战机相撞
			
			
		for(int i=0;i<epList.size();i++) {
			EnemyPlane ep=epList.get(i);
			//让敌机下落
			if(ep.getY()>bgY) {//如果当前敌机以及下落出
				epList.remove(i);
				ep.setX((int)(Math.random()*bgX)+1);
				ep.setY(0-ep.getR());
				ep.setSpeed((int)(Math.random()*5)+1);
				ep.changeEnemyPlane();
				epList.add(ep);
			}else {//如果没有落出屏幕 让它以1——5的随机速度下落
				ep.setY(ep.getY()+ep.getSpeed());
			}
			
			
			
			//判断该敌机与战机是否相撞
			boolean b=isHeat(ep,hero);
			if(b==true) {
				ep.setX((int)(Math.random()*bgX));
				ep.setY(0-ep.getR());
				ep.setSpeed((int)(Math.random()*5)+1);
				ep.changeEnemyPlane();
				epList.add(ep);
				hero.setBlood(hero.getBlood()-hero.getAllBlood()/10);
			}
		}


		//让子弹飞 飞的同时判断是否与敌机相撞 影响分数
		for(int i=0;i<buList.size();i++) {
			Bullet bu=buList.get(i);
			if(bu.getY()<=0-bu.getR()) {//子弹飞出
				buList.remove(i);
			}else {//子弹没飞出
				bu.setY(bu.getY()-10);
			}	


		//逐一判断当前子弹是否与敌机集合中的敌机相撞
			for(int j=0;j<epList.size();j++) {
				EnemyPlane ep=epList.get(j);
				if(isHeat(ep,bu)) {
					buList.remove(i);
					epList.remove(j);
					ep.setX((int)(Math.random()*bgX)+1);
					ep.setY(0-ep.getR());
					ep.setSpeed((int)(Math.random()*5)+1);
					ep.changeEnemyPlane();
					epList.add(ep);
					hero.setScore(hero.getScore()+10);
				}
			}
			}//子弹飞
		repaint();
		try {
			Thread.sleep(10);
		}catch(Exception e){
			e.printStackTrace();
		}
		}//while
	}//run
	//实现判断子弹与敌机是否相撞
	private boolean isHeat(EnemyPlane ep, Bullet bu) {
		// TODO Auto-generated method stub
		if((ep.getX()-bu.getX())*(ep.getX()-bu.getX())
			+(ep.getY()-bu.getY())*(ep.getY()-bu.getY())
		>(ep.getR()+bu.getR())*(ep.getR()+bu.getR())){
			return false;
		}else {
			return true;
		}
	}
		
		private boolean isHeat(EnemyPlane ep, Hero g) {
			// TODO Auto-generated method stub
			if((ep.getX()-g.getX())*(ep.getX()-g.getX())
				+(ep.getY()-g.getY())*(ep.getY()-g.getY())
			>(ep.getR()+g.getR())*(ep.getR()+g.getR())){
				return false;
			}else {
				return true;
			}
			
		}
           //上升子弹
	private void initBullet() {
		// TODO Auto-generated method stub
		Bullet bu=new Bullet();
		bu.setX(hero.getX());
		bu.setY(hero.getY());
		bu.setR(60);
		buList.add(bu);
	}
	}

第四天

今天主要是写出一个结束界面,结束界面在MyJpanel中直接调用一张图片便可以实现。以及要完成一个重新开始游戏界面的窗口,这两段代码就与第一天的比较相似。可以根据第一天所学的进行雷同写,代码在下面,可以稍微对照。

1.重新开始游戏?

package cn.rjxy.planegame;

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**

 * @function 游戏重新开始界面
 
 *
 */
public class Againgame  extends JFrame  implements ActionListener{
	private JButton button_start = new JButton();
	private JButton button_end = new JButton();
	public Againgame(){


		/**
		 * 1.创建一个300*400,居中显示的窗体
		 *  a.创建一个JFrame
		 *  b.设置标题
		 *  c.设置默认关闭方式
		 *  d.设置窗体的大小以及在屏幕中的显示方式
		 *  e.设置为可见,设置窗体大小不变
		 */
		JFrame jf = new JFrame();
		jf.setTitle("是否重新开始?");
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置默认关闭方式 


		//jf.setSize(300,400);
		Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
		jf.setBounds((dim.width-300)/2,(dim.height-400)/2 ,300, 100);//窗体在屏幕上显示的位置
		jf.setResizable(true);//大小不可改变
		jf.setVisible(true);//窗口可见
		


		//设置面板
		JPanel panel= new JPanel();
		button_start.setText("重新开始");
		button_end.setText("结束游戏");
		button_start.addActionListener(this);
		button_end.addActionListener(this);
		
		panel.add(button_start);
		panel.add(button_end);
		jf.add(panel);
		panel.setVisible(true);
	}
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub
		if(e.getSource()==button_start){
			new Started();	
		}
		if(e.getSource()==button_end){
			System.exit(0);
		}
	}
}

第五天

其实四天基本上已经完成了简单的飞机大战,最初级已经制作完成了,我们都知道,游戏肯定有终极的啊,比如,大Boss,所以,最后有做一个大Boss,这个代码则与敌机是一模一样的,也是定义一个专门的类,定义属性,同时在MyJPanel中实现 大Boss的应用,代码在下面供参考。

1.大Boss类

package cn.rjxy.planegame;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.ImageIcon;

public class Boss1 {
	public int x;//中心横坐标
	public int y;//中心纵坐标
	private int r;//感应半径
	private int allBlood;//满血
	private int blood;//剩余血量
	//private int score;//分数
	private Image heroImg=new ImageIcon("image/img/boss.jpg").getImage();
	Dimension dim=Toolkit.getDefaultToolkit().getScreenSize();
	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 getR() {
		return r;
	}public void setR(int r) {
		this.r = r;
	}public int getAllBlood() {
		return allBlood;
	}public void setAllBlood(int allBlood) {
		this.allBlood = allBlood;
	}public int getBlood() {
		return blood;
	}public void setBlood(int blood) {
		this.blood = blood;
	}public void paint(Graphics g){
		//绘制boss
		g.drawImage(heroImg, x-r, y-r, null);
		//绘制满血条
	    g.setColor(Color.yellow);
	    g.fillRect((dim.width-600)/2, 10, allBlood, 10);
	    //绘制剩余血条
	    g.setColor(Color.red);
	    g.fillRect((dim.width-600)/2, 10, blood, 10);
	    }
	public Boss1 get(int i) {
		// TODO Auto-generated method stub
		return null;
	}
	}

2.在MyJPanel中的变动

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.ArrayList;

import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JPanel;
/**
 * 
 * 
 *
 */
//游戏界面 实现多线程
public class MyJPanel extends JPanel implements Runnable,MouseMotionListener{
private Hero hero=new Hero();
private ArrayList<EnemyPlane> epList=new ArrayList<EnemyPlane>();//创建集合类
private ArrayList<Bullet> buList=new ArrayList<Bullet>();
private Boss1 boss1=new Boss1();//boss1
//背景图片属性
private Image bgImg1=null;

private  int bgX,bgY;
//初始化战机数目
private int epNum=10;
//初始化背景
private Image bgImg=new ImageIcon("image/img/bg2.jpg").getImage();
private Image goImg=new ImageIcon("image/img/gameover.jpg").getImage();
    public MyJPanel(Dimension dim) {
	//初始化屏幕的高和宽   定义背景图片
	      bgX=dim.width;
	      bgY=dim.height;
	      int bgNum=(int )((Math.random()*5)+1);
	      bgImg = new ImageIcon("image/img/bg"+bgNum+".jpg").getImage();
	      
	//初始化战机
	hero.setR(57);
	hero.setX(bgX/2);
	hero.setY(bgY-3*hero.getR());
	hero.setAllBlood(200);
	hero.setBlood(200);
	hero.setScore(0);
	//初始化敌机
	for(int i=0;i<epNum;i++) {
		EnemyPlane ep=new EnemyPlane();
		ep.setR(30);//敌机半径
		ep.setX((int)(Math.random()*bgX)+1);
		ep.setY((int)(Math.random()*bgY)+1);
		ep.setSpeed((int)(Math.random()*5)+1);
		epList.add(ep);
		//初始化大boss
		boss1.setX((bgX -boss1.getR() *2) / 2);
		boss1.setR(100);
		boss1.setY(150);
		boss1.setAllBlood(600);
		boss1.setBlood(600);
	}
	this.addMouseMotionListener(this);
}
public void paint(Graphics g) {
	super.paint(g);
	//画背景
	g.drawImage(bgImg, 0, 0, bgX, bgY, null);
	//画战机
	hero.paint(g);
	//画敌机
	for(int i=0;i<epList.size();i++) {
		epList.get(i).paint(g);
	}
	//画子弹
	for(int i=0;i<buList.size();i++) {
		buList.get(i).paint(g);
	}
	//画boss
			if(hero.getScore() >=500){
				g.setColor(Color.red);
				g.setFont(new Font("宋体", Font.BOLD, 30));
				g.drawString("大Boss出现", 1000, 80);
			boss1.paint(g);
			}
			if(boss1.getBlood()<=0){
				g.setColor(Color.red);
				g.setFont(new Font("宋体", Font.BOLD, 30));
				g.drawString("已歼灭", 1000, 50);
//游戏结束界面

	if(hero.getBlood()<=0) {
		g.drawImage(goImg, 0, 0,bgX, bgY, null);
		g.setFont(new Font("宋体",Font.BOLD,70));
		g.setColor(Color.black);
		g.drawString("当前分数是:"+hero.getScore(),50,650);
	}
			}
}


		//显示最高分
		//显示最高分
	
			 /*int maxScore = 0;
			 File file = new File("date/MaxScore.txt");
			 
			try {
		
				if(!file.exists()){
					//如果保存分数文件不存在,创建文件,创建输入流写入数据
		file.createNewFile();
		FileWriter writer = new FileWriter(file);
		BufferedWriter bw = new BufferedWriter(writer);
			bw.write(hero.getScore()+"");
			bw.flush();
			bw.close();
			maxScore = hero.getScore();
				} else {
					//创建输出流,读取文件
					InputStreamReader reader = new InputStreamReader(new FileInputStream(file));
					BufferedReader br = new BufferedReader(reader);
					String line = "";
					int score = 0;
					if (null !=(line = br.readLine())) {
						//如果读到数据
						score = Integer.parseInt(line);
						if(hero.getScore() > score){
							FileWriter writer = new FileWriter(file);
							BufferedWriter bw = new BufferedWriter(writer);
							bw.write(hero.getScore()+"");
							bw.flush();
							bw.close();
							maxScore = hero.getScore();
						} else {
							maxScore = score;
						}
					} else {
						//如果文件内容为空
						System.out.println("手动删除maxScore.txt文件重新运行");
					}
					br.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}

			//显示当前分数
			//绘制GAMEOVER
			if (hero.getBlood() <= 0) {
				g.drawImage(goImg, 0, 0, bgX, bgY, null);
					//当前分数
				try {
					Writer writer = null;
					if(!file.exists()){//第一次访问文件路径
						file.createNewFile();
						writer = new FileWriter(file);
						writer.write(hero.getScore()+"");
						//FileWriter的flush()方法是从OutputStreamWriter中继承来的,其作用就是清空缓冲区并完成文件写入操作的。
						writer.flush();
						maxScore = hero.getScore();
					}else{//第二次后访问文件
						writer = new FileWriter(file);
						writer.write(hero.getScore()+""); 
						writer.flush();
						maxScore = hero.getScore();
						System.out.println("######");
						writer.close();

					} 
				}catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
			}
}
*/
	
	@Override
	//鼠标按下并拖动 战机的坐标更改
	public void mouseDragged(MouseEvent e) {
		// TODO Auto-generated method stub
		if(hero.getBlood()>0){
			hero.setX(e.getX());
			hero.setY(e.getY());
			repaint();
		}
		if(hero.getBlood()<=0){
			new Againgame();
		}
	}
	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub
		
		}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		int count=0;
		while(true) {
			if(hero.getBlood()>0&&boss1.getBlood()>=0) {
				//初始化子弹
				//子弹步进了10,新生成一个子弹
				if(count%10==0) {
					initBullet();
				}
				count++;	
			}
		
		//让敌机下落 下落同时判断每个敌机是否与子弹或战机相撞
			
			
		for(int i=0;i<epList.size();i++) {
			EnemyPlane ep=epList.get(i);
			//让敌机下落
			if(ep.getY()>bgY) {//如果当前敌机以及下落出
				epList.remove(i);
				ep.setX((int)(Math.random()*bgX)+1);
				ep.setY(0-ep.getR());
				ep.setSpeed((int)(Math.random()*5)+1);
				ep.changeEnemyPlane();
				epList.add(ep);
			}else {//如果没有落出屏幕 让它以1——5的随机速度下落
				ep.setY(ep.getY()+ep.getSpeed());
			}
			
			
			
			//判断该敌机与战机是否相撞
			boolean b=isHeat(ep,hero);
			if(b==true) {
				ep.setX((int)(Math.random()*bgX));
				ep.setY(0-ep.getR());
				ep.setSpeed((int)(Math.random()*5)+1);
				ep.changeEnemyPlane();
				epList.add(ep);
				hero.setBlood(hero.getBlood()-hero.getAllBlood()/10);
			}
		}
		//让子弹飞 飞的同时判断是否与敌机相撞 影响分数
		for(int i=0;i<buList.size();i++) {
			Bullet bu=buList.get(i);
			if(bu.getY()<=0-bu.getR()) {//子弹飞出
				buList.remove(i);
			}else {//子弹没飞出
				bu.setY(bu.getY()-10);
			}	
			//boss与子弹相撞
			if(hero.getScore()>500){
			if(boss1.getBlood()>0){
				boolean e=isHeat(bu,boss1);
				if(e==true){
					buList.remove(i);
					boss1.setBlood(boss1.getBlood()-40);
				
				}
			}
			else{
				boss1.setAllBlood(0);
				boss1.setX(2000);
				boss1.setY(2000);
			
			}
		}
		//逐一判断当前子弹是否与敌机集合中的敌机相撞
			for(int j=0;j<epList.size();j++) {
				EnemyPlane ep=epList.get(j);
				if(isHeat(ep,bu)) {
					buList.remove(i);
					epList.remove(j);
					ep.setX((int)(Math.random()*bgX)+1);
					ep.setY(0-ep.getR());
					ep.setSpeed((int)(Math.random()*5)+1);
					ep.changeEnemyPlane();
					epList.add(ep);
					hero.setScore(hero.getScore()+10);
				}
			}
			}//子弹飞
		repaint();
		try {
			Thread.sleep(30);
		}catch(Exception e){
			e.printStackTrace();
		}
		}//while
	}//run
	//实现判断子弹与敌机是否相撞
	private boolean isHeat(EnemyPlane ep, Bullet bu) {
		// TODO Auto-generated method stub
		if((ep.getX()-bu.getX())*(ep.getX()-bu.getX())
			+(ep.getY()-bu.getY())*(ep.getY()-bu.getY())
		>(ep.getR()+bu.getR())*(ep.getR()+bu.getR())){
			return false;
		}else {
			return true;
		}
	}
		
		private boolean isHeat(EnemyPlane ep, Hero g) {
			// TODO Auto-generated method stub
			if((ep.getX()-g.getX())*(ep.getX()-g.getX())
				+(ep.getY()-g.getY())*(ep.getY()-g.getY())
			>(ep.getR()+g.getR())*(ep.getR()+g.getR())){
				return false;
			}else {
				return true;
			}
			
		}
		private boolean isHeat(Bullet bu, Boss1 boss1) {
			if ((boss1.getX() - bu.getX()) * (boss1.getX() - bu.getX())
					+ (boss1.getY() - bu.getX()) * (boss1.getY() - bu.getX()) > (boss1.getR() + bu.getX())
							* (bu.getR() + boss1.getX())) {
				return true;
				} 
			else {
				return false;
				}
			}
			
		

	private void initBullet() {
		// TODO Auto-generated method stub
		Bullet bu=new Bullet();
		bu.setX(hero.getX());
		bu.setY(hero.getY());
		bu.setR(60);
		buList.add(bu);
	}
	}

当然,飞机大战还有很多的优化可以去做,比如关卡,形式多元化,记录最高分,用户登录,等一系列。加油吧。

因为自己也是一个小白,所以这也算是搔首弄姿了吧,如果您有宝贵意见,希望能够提出来,真的很渴望进步。谢谢!

  • 10
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值