一、游戏说明
玩家通过移动鼠标控制飞机移动(飞机恒在左侧,怪兽由右侧出现),点击鼠标左键发射炮弹,炮弹击中怪兽则怪兽爆炸,玩家得一分,在第一关中玩家累计得分达指定分数后即可通关,第二关中需要击败boss才能通过。玩家通过第二关时,显示玩家本局得分,更新并显示历史10个最佳得分的排行榜。若玩家在游戏过程中被怪兽或boss技能击中则玩家失败,需重新开始挑战。玩家只有通过了第一关后才能继续挑战第二关。若玩家在游戏中突然有事需要离开,且下次有时间时想继续玩,可以点击退出并存档按钮实现游戏存档,下次打开游戏时会自动读档,即继续上次的游戏。
二、 整体框架(括号中代表创建了其对象)
程序入口、窗口: PlaneWar类(Ball、Monster、BossThread、GameSaved、Mouse、MovePlane、MyThread、WipeThread)。
怪兽爆炸: BlastThread(Fragment)。
Boss技能释放:BossThread(Ball)。
游戏存档:GameSave。
炮弹发射: Mouse(Ball)。
飞机移动: MovePlane。
程序核心:MyThread(BossThread、 BlastThread)。
怪兽生成:WipeThread。
其它类:Ball类为炮弹类,Monster类为怪兽类,Fragment为怪兽爆炸碎片类,Parent为Ball类、Monster类和Fragment类的父类。
三、具体实现
3.1 Parent类
说明:Parent类为Fragment类、Ball类和Monster类的父类以实现代码复用,在游戏中无实际意义。
//Ball类和Monster类的父类,代码复用,无实际意义
public class Parent
{
protected int x,y;
public void setXY(int x,int y)
{
this.x=x;
this.y=y;
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
}
3.2 Ball类
说明:一个Ball类对象代表一个炮弹,该类的属性和方法都继承自Parent类。属性为炮弹的横、纵坐标。
3.3 Monster类
说明:一个Monster类对象代表一头怪兽,该类的属性和方法都继承自Parent类。属性为怪兽的横、纵坐标。
3.4 Fragment类
说明:一个Fragment类对象代表一个怪兽碎片,属性为碎片横、纵坐标(继承自Parent类),碎片颜色和尺寸。
//怪兽爆炸后的碎片类
public class Fragment extends Parent
{
private int size,color;//碎片尺寸、颜色
//对碎片进行初始化
public Fragment(int x,int y,int c)
{
this.x=x;
this.y=y;
color=c;
Random r=new Random();
size=r.nextInt(10);
}
public int getSize()
{
return size;
}
public int getColor()
{
return color;
}
}
3.5 BlastThread类
说明:BlastThread类为怪兽的爆炸线程以实现被击中怪兽的爆炸效果。
3.5.1 属性
private int x0,y0;//需要爆炸的图片坐标
private Graphics g;
3.5.2 获取碎片
实现思路:对需要产生爆炸效果的怪兽图片每隔15个像素创建一个Fragment类对象,该对象的初始坐标和颜色与对应像素的坐标和颜色相同。所有碎片加入碎片队列。
//获取所有碎片并存入alf队列
for(int i=0;i<img.getWidth();i++)
{
for(int j=0;j<img.getHeight();j=j+15)
{
Fragment f=new Fragment(i,j,img.getRGB(i, j));
alf.add(f);
}
}
3.5.3 碎片移动
实现思路:每隔一定时间将碎片移动并显示,重复100次。碎片移动通过碎片原坐标加一个随机数再减去一个常数实现。每次显示碎片之前将所有碎片画到缓冲区,然后将缓冲区中的图画到窗口内。
//每隔一定时间将碎片移动并显示,重复100次
for(int i=0;i<100;i++)
{
try
{
sleep(10);
}
catch(InterruptedException e)
{}
BufferedImage bi=new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
Graphics br=bi.getGraphics();
for(int j=0;j<alf.size();j++)
{
alf.get(j).setXY(alf.get(j).getX()+r.nextInt(11)-5,alf.get(j).getY()+r.nextInt(11)-5);
br.setColor(new Color(alf.get(j).getColor()));
br.fillOval(alf.get(j).getX(), alf.get(j).getY(), alf.get(j).getSize(), alf.get(j).getSize());
}
g.drawImage(bi, x0, y0, null);
}
3.6 BossThread类
说明:BossThread类用于实现Boss技能的释放(Boss共两种技能,第一种为Boss发射11发炮弹同时以不同斜率像飞机移动,第二种为在boss一侧同时产生10发炮弹,炮弹均向飞机水平移动。)。boss每隔一定时间释放一次技能,两种技能交替释放。
3.6.1 属性
//dx=-3
private ArrayList<Ball> ball0=new ArrayList<Ball>();//y为初始值
private ArrayList<Ball> upball1=new ArrayList<Ball>();//y=500+dx/11
private ArrayList<Ball> upball2=new ArrayList<Ball>();//y=500+2dx/11
private ArrayList<Ball> upball3=new ArrayList<Ball>();//y=500+3dx/11
private ArrayList<Ball> upball4=new ArrayList<Ball>();//y=500+4dx/11
private ArrayList<Ball> upball5=new ArrayList<Ball>();//y=500+9dx/22
private ArrayList<Ball> downball1=new ArrayList<Ball>();//y=500-dx/11
private ArrayList<Ball> downball2=new ArrayList<Ball>();//y=500-2dx/11
private ArrayList<Ball> downball3=new ArrayList<Ball>();//y=500-3dx/11
private ArrayList<Ball> downball4=new ArrayList<Ball>();//y=500-4dx/11
private ArrayList<Ball> downball5=new ArrayList<Ball>();//y=500-9dx/22
3.6.2 技能一
实现思路:依次创建11个Ball类对象,每个Ball类对象的初始横坐标均为1100,初始纵坐标均为495。同时将所有对象加入相应队列。
//释放第一种技能
Ball ball=new Ball();
ball.setXY(1100,495);
ball0.add(ball);
ball=new Ball();
ball.setXY(1100,495);
upball1.add(ball);
ball=new Ball();
ball.setXY(1100,495);
upball2.add(ball);
ball=new Ball();
ball.setXY(1100,495);
upball3.add(ball);
ball=new Ball();
ball.setXY(1100,495);
upball4.add(ball);
ball=new Ball();
ball.setXY(1100,495);
upball5.add(ball);
ball=new Ball();
ball.setXY(1100,495);
downball1.add(ball);
ball=new Ball();
ball.setXY(1100,495);
downball2.add(ball);
ball=new Ball();
ball.setXY(1100,495);
downball3.add(ball);
ball=new Ball();
ball.setXY(1100,495);
downball4.add(ball);
ball=new Ball();
ball.setXY(1100,495);
downball5.add(ball);
3.6.3 技能二
实现思路:依次创建10个Ball类对象,每个Ball类对象的初始横坐标均为1100,初始纵坐标为随机数。同时将所有对象加入ball0队列。
//boss释放二钟技能
Random r=new Random();
for(int i=0;i<10;i++)
{
ball=new Ball();
ball.setXY(1100,r.nextInt(900)+75);
ball0.add(ball);
}
3.7 GameSave类
说明:当玩家点击按钮“退出并存档”后对游戏进行存档并退出程序。
实现思路:GameSave类为“退出并存档”按钮的动作监听类,为该按钮注册GameSave类对象监听者后,玩家用鼠标点击按钮后便会执行退出并存档操作。存档是将关卡号,玩家得分,飞机纵坐标(横坐标恒为0),玩家发射出的所有炮弹坐标,所有怪兽坐标存入“save.txt”文档。若当前关卡为第二关,还需存储boss血量和boss释放的所有炮弹的坐标。当游戏结束时应自动将“sava.txt”文档清空(Mythread实现)。读档(PlaneWar实现)即将该文档中所有内容读出,每次运行程序时应首先读档。
3.7.1 属性
private ArrayList<Ball> alball;
private ArrayList<Monster> almonster;
private ArrayList <Ball> ball0;//y=500
private ArrayList<Ball> upball1;//y=500+dx/11
private ArrayList<Ball> upball2;//y=500+2dx/11
private ArrayList<Ball> upball3;//y=500+3dx/11
private ArrayList<Ball> upball4;//y=500+4dx/11
private ArrayList<Ball> upball5;//y=500+9dx/22
private ArrayList<Ball> downball1;//y=500-dx/11
private ArrayList<Ball> downball2;//y=500-2dx/11
private ArrayList<Ball> downball3;//y=500-3dx/11
private ArrayList<Ball> downball4;//y=500-4dx/11
private ArrayList<Ball> downball5;//y=500-9dx/22
3.7.2 具体实现
int l=PlaneWar.getLevel();
try
{
BufferedWriter out=new BufferedWriter(new FileWriter("save.txt"));
//存关卡
out.write(""+l);
out.newLine();
//存玩家得分
out.write(""+MyThread.getScore());
out.newLine();
//存飞机纵坐标
out.write(""+MyThread.getPlaneY());
out.newLine();
//存玩家发出的炮弹
for(int i=0;i<alball.size();i++)
{
out.write(alball.get(i).getX()+","+alball.get(i).getY()+" ");
}
out.newLine();
//存怪兽
for(int i=0;i<almonster.size();i++)
{
out.write(almonster.get(i).getX()+","+almonster.get(i).getY()+" ");
}
out.newLine();
//如果为第二关且boss已出现,则继续存储
if(l==2&&MyThread.getScore()>50)
{
//存boss血量
out.write(""+MyThread.getBlood());
out.newLine();
//存boss发出的炮弹
for(int i=0;i<ball0.size();i++)
{
out.write(ball0.get(i).getX()+","+ball0.get(i).getY()+" ");
}
out.newLine();
for(int i=0;i<upball1.size();i++)
{
out.write(upball1.get(i).getX()+","+upball1.get(i).getY()+" ");
}
out.newLine();
for(int i=0;i<upball2.size();i++)
{
out.write(upball2.get(i).getX()+","+upball2.get(i).getY()+" ");
}
out.newLine();
for(int i=0;i<upball3.size();i++)
{
out.write(upball3.get(i).getX()+","+upball3.get(i).getY()+" ");
}
out.newLine();
for(int i=0;i<upball4.size();i++)
{
out.write(upball4.get(i).getX()+","+upball4.get(i).getY()+" ");
}
out.newLine();
for(int i=0;i<upball5.size();i++)
{
out.write(upball5.get(i).getX()+","+upball5.get(i).getY()+" ");
}
out.newLine();
for(int i=0;i<downball1.size();i++)
{
out.write(downball1.get(i).getX()+","+downball1.get(i).getY()+" ");
}
out.newLine();
for(int i=0;i<downball2.size();i++)
{
out.write(downball2.get(i).getX()+","+downball2.get(i).getY()+" ");
}
out.newLine();
for(int i=0;i<downball3.size();i++)
{
out.write(downball3.get(i).getX()+","+downball3.get(i).getY()+" ");
}
out.newLine();
for(int i=0;i<downball4.size();i++)
{
out.write(downball4.get(i).getX()+","+downball4.get(i).getY()+" ");
}
out.newLine();
for(int i=0;i<downball5.size();i++)
{
out.write(downball5.get(i).getX()+","+downball5.get(i).getY()+" ");
}
out.newLine();
}
out.flush();//将缓冲区内容存至“save.txt”
out.close();
}
catch(IOException a)
{
a.getStackTrace();
}
System.exit(0);//安全退出程序
3.8 Mouse类
说明:玩家每点击窗口内部一次,便会在飞机处发射一枚炮弹。
实现思路:Mouse类为鼠标监听类,给窗口注册Mouse类对象为鼠标监听者,当玩家点击窗口时
创建一个Ball类对象,该对象初始横坐标为25,初始纵坐标为鼠标的纵坐标。然后将该对象加入玩家炮弹队列alball。
3.8.1 属性
private static ArrayList<Ball> alball;//炮弹队列
3.8.2 具体实现
Ball ball=new Ball();
ball.setXY(25, e.getY()-5);
alball.add(ball);
3.9 MovePlane类
说明:飞机横坐标恒为0,当鼠标移动时设置MyThrea类的飞机图片中心纵坐标与鼠标相同。
实现思路:MovePlane类为鼠标移动监听类,给窗口注册MovePlane类对象为鼠标移动监听者,当玩家鼠标在窗口内移动时设置MyThrea类的飞机图片中心纵坐标与鼠标纵坐标相同。同时将飞机在相应位置画出。
3.9.1 属性
private ImageIcon image=new ImageIcon("plane.png");
private Graphics g;
private int px=0,py=500;//飞机左上角坐标
3.9.2 具体实现
py=e.getY()-25;
if(py<=75)
{
py=75;
}
g.drawImage(image.getImage(),px,py,null);
MyThread.setPlaneY(py);
3.10 MyThread类
说明:MyThread类为这个程序的核心,实现设置不同关卡怪兽的步长,炮弹和怪兽的移动,与MovePlane类配合实现飞机的移动,显示玩家得分,当有怪兽被玩家飞机的炮弹击中时创建一个 BlastThread类对象并启动该怪兽的爆炸线程以实现其爆炸效果,判断游戏是否结束,若游戏第一关结束且玩家获胜,则弹出对话框让玩家选择是否继续下一关,若继续则调用PlaneWa类r的next函数开始下一关,否则退出程序。若游戏第一关结束且玩家通关失败,则弹出对话框让玩家选择是否再来一次,若再来一次则调用PlaneWar类的playAgain函数重新开始第一关,否则退出程序。若游戏第二关结束且玩家通关失败,则弹出对话框让玩家选择是否再来一次,若再来一次则调用PlaneWar类的playAgain函数重新开始第一关,否则退出程序。若游戏第二关结束且玩家胜利,显示玩家本局得分,更新并显示历史10个最佳得分的排行榜(利用Mysql实现),同时弹出对话框让玩家选择是否再来一次,若再来一次则调用PlaneWar的playAgain函数重新开始第一关,否则退出程序。第二关中当玩家得分达到50时实现boss的出现和boss技能的释放,显示boss的血量。当游戏结束时清空存档文件。
3.10.1 属性
private Graphics g;
private static int score;//玩家得分,初始值为0
private ArrayList<Ball> alball;
private ArrayList<Monster> almonster;
private JTextField jtf;
private static int px=0,py;//飞机左上角坐标,py初始值为500
private boolean running=true;
private int c;//玩家的选择
private JFrame jf;
private int step=1;//怪兽步长
private static int blood;//boss血量,初始值为50
//dx=-3
private ArrayList <Ball> ball0;//y=500
private ArrayList<Ball> upball1;//y=500+dx/11
private ArrayList<Ball> upball2;//y=500+2dx/11
private ArrayList<Ball> upball3;//y=500+3dx/11
private ArrayList<Ball> upball4;//y=500+4dx/11
private ArrayList<Ball> upball5;//y=500+9dx/22
private ArrayList<Ball> downball1;//y=500-dx/11
private ArrayList<Ball> downball2;//y=500-2dx/11
private ArrayList<Ball> downball3;//y=500-3dx/11
private ArrayList<Ball> downball4;//y=500-4dx/11
private ArrayList<Ball> downball5;//y=500-9dx/22
3.10.2 实现炮弹和怪兽的自动移动
实现思路:每隔较短的时间清屏然后将物体的坐标按某种规则更新并将物体在新坐标处显示,让物体看起来像是在移动,当然也应该将移出界面的物体从队列中移除。例如实现玩家发射出的所有炮弹的自动移动就是每隔一段较短的时间清屏后将以下代码运行一次。
//更新alball中的炮弹位置,显示alball中的炮弹
for(int i=0;i<alball.size();i++)
{
if(alball.get(i).getX()<1198)
{
alball.get(i).setXY(alball.get(i).getX()+2,alball.get(i).getY());
g.fillOval(alball.get(i).getX(), alball.get(i).getY(), 10, 10);
}
else
{
alball.remove(i);
i--;
}
}
3.10.3 正确显示飞机
上面说过通过MovePlane类可以实现当鼠标移动时,飞机移动到相应位置;但当鼠标静止时飞机的显示它就无能为力了。但当飞机移动时我们都将飞机的最新坐标传递给了MyThread类,于是我们可以通过每隔较短时间重绘飞机来实现静止飞机的显示。
3.10.4 判断碰撞
即判断两个图片是否有重叠部分,例如判断玩家发出的一个炮弹是否击中一头怪兽。
if((almonster.get(i).getX()-alball.get(j).getX()<10&&alball.get(j).getX()-almonster.get(i).getX()<image.getIconWidth())&&(almonster.get(i).getY()-alball.get(j).getY()<10&&alball.get(j).getY()-almonster.get(i).getY()<image.getIconHeight()))
当有玩家的炮弹击中怪兽时玩家得分应该加1并显示,同时启动被击中怪兽的爆炸线程。若为第一关,应判断玩家累计得分是否达到要求,达到要求则玩家通过,可以继续下一关。若为第二关且得分达到要求则应启动boss技能释放线程,每隔较短时间重绘boss。
BlastThread bt=new BlastThread(almonster.get(i).getX(),almonster.get(i).getY(),g);
bt.start();
score++;
jtf.setText("Score:"+score);
almonster.remove(i);
i--;
alball.remove(j);
//判断玩家是否通过第一关
if(score==10&&PlaneWar.getLevel()==1)
{
gameOverSave();
PlaneWar.setRunning(false);
running=false;
c=JOptionPane.showOptionDialog(jf,"", "Pass",JOptionPane.DEFAULT_OPTION,JOptionPane.PLAIN_MESSAGE,null,new Object[]{"下一关","忍痛离开"},"下一关");
if(c==0)
{
PlaneWar.next();
}
else
{
System.exit(0);
}
}
//判断是否应该出现boss
if(score==50&&PlaneWar.getLevel()==2)
{
score++;
BossThread boss=new BossThread(ball0,upball1,upball2,upball3,upball4,upball5,downball1,downball2,downball3,downball4,downball5);
boss.start();//boss开始释放技能
}
break;
当玩家炮弹击中boss时,boss血量应该减一。
for(int k=0;k<alball.size();k++)
{
if((alball.get(k).getX()-1088<112&&1088-alball.get(k).getX()<10)&&(alball.get(k).getY()-430<140&&430-alball.get(k).getY()<10))
{
blood--;
alball.remove(k);
k--;
}
}
//重绘boss血量
g.clearRect(1100, 40, 100, 20);
g.setColor(Color.red);
g.fillRect(1100, 40,2*blood,20);
g.setColor(Color.orange);
当boss血量<=0时,玩家通过第二关,输出玩家本局得分,更新并输出得分排行榜。
if(blood<=0)
{
gameOverSave();
PlaneWar.setRunning(false);
//输出玩家本局得分,更新数据库中的排行榜并输出
Connection conn = null;
PreparedStatement ps= null;
ResultSet rs = null;
String url = "jdbc:mysql://localhost:3306/myfirstdb";
try
{
Class.forName("com.mysql.jdbc.Driver");
}
catch (ClassNotFoundException e1)
{
e1.printStackTrace();
}
try
{
//获取连接对象
conn = DriverManager.getConnection(url ,"root","1234");
// 获取执行sql的工具对象
ps = conn.prepareStatement("SELECT * FROM planewar");
//调用执行查询的方法,返回查询结果集
rs = ps.executeQuery();
}
catch (SQLException e)
{
e.printStackTrace();
}
int s;
int i=1;
System.out.println("您的得分为:"+score);
System.out.println("当前排行榜为:");
// 遍历处理结果
try
{
ps=conn.prepareStatement("update planewar set score=? where id=?");
while (rs.next())
{
s=rs.getInt(2);
if(score>s)
{
ps.setInt(1, score);
ps.setInt(2,i);
ps.executeUpdate();
System.out.println(score);
score=s;
}
else
{
System.out.println(s);
}
i++;
}
//关闭资源
rs.close();
ps.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
//让玩家选择继续还是退出
c=JOptionPane.showOptionDialog(jf,"", "恭喜你通过了所有关卡",JOptionPane.DEFAULT_OPTION,JOptionPane.PLAIN_MESSAGE,null,new Object[]{"再来一次","忍痛离开"},"再来一次");
if(c==0)
{
PlaneWar.playAgain();
}
else
{
System.exit(0);
}
break;
}
若玩家飞机被怪兽或boss技能击中,玩家挑战失败,以下为飞机被怪兽击中的代码。
//判断是否有怪兽击中飞机,若有则玩家失败
for(int k=0;k<almonster.size();k++)
{
if((almonster.get(k).getX()-px<50&&px-almonster.get(k).getX()<70)&&(almonster.get(k).getY()-py<50&&py-almonster.get(k).getY()<87))
{
running=false;
defeat();
break;
}
}
上述代码,在run函数中每隔10ms执行一次,以下为default函数
//玩家失败后需进行的一些操作
public void defeat()
{
gameOverSave();
PlaneWar.setRunning(false);
c=JOptionPane.showOptionDialog(jf,"", "Defeat",JOptionPane.DEFAULT_OPTION,JOptionPane.PLAIN_MESSAGE,null,new Object[]{"再来一次","忍痛离开"},"再来一次");
if(c==0)
{
PlaneWar.playAgain();
}
else
{
System.exit(0);
}
}
gameOver函数,游戏结束时将"save.txt"清空
public void gameOverSave()
{
try
{
BufferedWriter out=new BufferedWriter(new FileWriter("save.txt"));
out.write("");
out.flush();
out.close();
}
catch(IOException e)
{
e.getStackTrace();
}
}
3.11 PlaneWar类
说明:其Main函数为程序入口,当程序开始执行时先进行读档然后显示游戏画面,创建相关对象,启动相关线程,为窗口和按钮注册监听者,其playAgain函数实现游戏的重新开始,next函数实现第二关的开始。
3.11.1 属性
private static ArrayList<Ball> alball=new ArrayList<Ball>();//用于存储界面中所有炮弹
private static ArrayList<Monster> almonster=new ArrayList<Monster>();//用于存储界面中所有怪兽
private static JFrame jf=new JFrame();//窗口对象
private static Mouse mouse=new Mouse();//鼠标监听类对象
private static JTextField jtf=new JTextField("");//文本框,用于显示玩家得分
private static MovePlane mp=new MovePlane();//鼠标移动监听类对象
private static Graphics g;//窗口内容画笔
private static boolean running=true;//记录程序是否处于游戏状态
private static int level=1;//关卡号
//boss发出的炮弹,dx=-3
private static ArrayList<Ball> ball0=new ArrayList<Ball>();//y=500
private static ArrayList<Ball> upball1=new ArrayList<Ball>();//y=500+dx/11
private static ArrayList<Ball> upball2=new ArrayList<Ball>();//y=500+2dx/11
private static ArrayList<Ball> upball3=new ArrayList<Ball>();//y=500+3dx/11
private static ArrayList<Ball> upball4=new ArrayList<Ball>();//y=500+4dx/11
private static ArrayList<Ball> upball5=new ArrayList<Ball>();//y=500+9dx/22
private static ArrayList<Ball> downball1=new ArrayList<Ball>();//y=500-dx/11
private static ArrayList<Ball> downball2=new ArrayList<Ball>();//y=500-2dx/11
private static ArrayList<Ball> downball3=new ArrayList<Ball>();//y=500-3dx/11
private static ArrayList<Ball> downball4=new ArrayList<Ball>();//y=500-4dx/11
private static ArrayList<Ball> downball5=new ArrayList<Ball>();//y=500-9dx/22
3.11.2 读档
int score=0;
int py=500;
int blood=50;
//读档
String s=new String();
String[] str;
try
{
BufferedReader in=new BufferedReader(new FileReader("save.txt"));
s=in.readLine();
if(s!=null)
{
level=Integer.parseInt(s);
s=in.readLine();
score=Integer.parseInt(s);
s=in.readLine();
py=Integer.parseInt(s);
try
{
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
alball.add(b);
}
}
catch( NumberFormatException e)
{}
try
{
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Monster monster=new Monster();
monster.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
almonster.add(monster);
}
}
catch( NumberFormatException e)
{}
if(level==2&&score>50)
{
s=in.readLine();
blood=Integer.parseInt(s);
try
{
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
ball0.add(b);
}
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
upball1.add(b);
}
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
upball2.add(b);
}
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
upball3.add(b);
}
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
upball4.add(b);
}
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
upball5.add(b);
}
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
downball1.add(b);
}
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
downball2.add(b);
}
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
downball3.add(b);
}
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
downball4.add(b);
}
s=in.readLine();
str=s.split(" ");
for(int i=0;i<str.length;i++)
{
String[] xy=str[i].split(",");
Ball b=new Ball();
b.setXY(Integer.parseInt(xy[0]),Integer.parseInt(xy[1]));
downball5.add(b);
}
}
catch( NullPointerException e)
{}
BossThread boss=new BossThread(ball0,upball1,upball2,upball3,upball4,upball5,downball1,downball2,downball3,downball4,downball5);
boss.start();//boss开始继续技能
}
}
in.close();
}
catch(IOException e)
{
e.getStackTrace();
}
3.11.3 初始化
初始化游戏界面,获取窗口画笔,创建相关对象,为按钮和窗口注册相应监听者,启动相关线程。。。
jf.setTitle("飞机大战");
jf.setSize(1200,1000);
jf.setLayout(null);
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
jf.setResizable(false);
jf.setBackground(Color.BLACK);
g=jf.getGraphics();
mouse.setALBall(alball);//将队列alball传递给鼠标监听类对象mouse
Container c=jf.getContentPane();
c.setBackground(Color.black);//将窗口内容背景设置为黑色
jf.addMouseListener(mouse);//给窗口注册鼠标监听者
//创建文本框用于记分
jtf.setBounds(0, 0,80,20);
jtf.setEditable(false);
jf.add(jtf);
GameSave gs=new GameSave(alball,almonster,ball0,upball1,upball2,upball3,upball4,upball5,downball1,downball2,downball3,downball4,downball5);
JButton jb=new JButton("退出并存档");
jb.addActionListener(gs);
jb.setBounds(560,0,100,30);
jf.add(jb);
MyThread m=new MyThread(alball,almonster,jtf,jf,g,ball0,upball1,upball2,upball3,upball4,upball5,downball1,downball2,downball3,downball4,downball5,score,py,blood);
mp.setG(g);
jf.addMouseMotionListener(mp);//给给窗口注册鼠标移动监听者
m.start();
//创建并启动产生怪兽的线程
WipeThread wt=new WipeThread();
wt.setALMonster(almonster);
wt.start();
3.11.4 重新开始和下一关函数
//下一关由此进入
public static void next()
{
//将炮弹列表清空
alball.clear();
//将怪兽列表清空
almonster.clear();
level=2;
running=true;
MyThread m=new MyThread(alball,almonster,jtf,jf,g,ball0,upball1,upball2,upball3,upball4,upball5,downball1,downball2,downball3,downball4,downball5,0,500,50);
WipeThread wt=new WipeThread();
wt.setALMonster(almonster);
m.start();
wt.start();
}
//重新开始由此进入
public static void playAgain()
{
//将炮弹列表清空
alball.clear();
//将怪兽列表清空
almonster.clear();
level=1;
running=true;
MyThread m=new MyThread(alball,almonster,jtf,jf,g,ball0,upball1,upball2,upball3,upball4,upball5,downball1,downball2,downball3,downball4,downball5,0,500,50);
WipeThread wt=new WipeThread();
wt.setALMonster(almonster);
m.start();
wt.start();
}
3.12 WipeThread
说明:实现怪兽的产生。
实现思路:每隔一定时间创建一个Monster类对象,该对象初始横坐标为1130,初始纵坐标随机生成,然后将该对象加入almonster队列。
3.12.1 属性
private static ArrayList<Monster> almonster;
3.12.2 怪兽产生
Monster monster=new Monster();
monster.setXY(1130,r.nextInt(835)+75);
almonster.add(monster);