`

java模拟微信打飞机开发思路

    博客分类:
  • Java
 
阅读更多

一、要求:

         创建玩家飞机,敌方飞机,均能发子弹,撞击后能移除相应对象。

二、思路:

      类的定义以及具体需要实现的功能:

     UI//窗体,控制玩家移动的鼠标监听器,刷新窗体的方法,Esc的键盘监听器,游戏的初始化,暂停等

       UpdataCenter//刷新窗体的线程

     MyPlane//玩家飞机,判断是否被敌人撞,被敌人子弹击中,控制背景移动

       Bullet//玩家的子弹,控制自己移动,判断是否和敌方子弹相遇抵消

       EnermyPlane//敌方飞机,父类,敌机移动以及出界的相应操作

       EnermyPlaneLarge//敌方飞机大号,控制自己移动,判断是否被玩家子弹击中

       EnermyPlaneMedium//敌方飞机中号,控制自己移动,判断是否被玩家子弹击中

       EnermyPlaneSmall//敌方飞机小号,不发子弹,控制自己移动,判断是否被玩家子弹击中

       EnermyThread//创建敌方飞机线程,不定时创建各类敌机的对象

       SendShot//随机创建敌方子弹的线程,定时发送子弹攻击玩家

       Shot//敌方子弹(自己控制发射)

 

      其它功能:加入分数统计,关卡,生命等数据。

 

三、具体实现:

 

UI.java

定义属性:

  static ArrayList<Bullet> bulList = new ArrayList<Bullet>();

static ArrayList<Shot> shotList = new ArrayList<Shot>();

static ArrayList<SendShot> ssList = new ArrayList<SendShot>();

static ArrayList<EnermyPlane> enermyList = new ArrayList<EnermyPlane>();

static int score = 0;

static int largeScore = 0;

static int pass = 1;

static int backgroundY = 0;

static boolean pause = false;//当Esc按下的时候暂停所有线程

 

在窗口上加入JPanel center。重写JPanel的paint()方法,便于重绘。

在paint里面便利队列 绘制所有飞机,子弹,分数等信息。

 

UpdataCenter.java

重写run()方法,不断center.repaint()。

 

MyPlane.java

定义属性:

  int speed;//飞机移动速度,用键盘控制移动的时候会有用。

int x, y;//飞机当前所在位置,用这个来画,死了之后移到-100,-100。1s后移到xt,yt

int xt, yt;//保存飞机初始时出现的位置

int count = 0, count1 = 0;//用来控制发子弹和背景移动的时间间隔

static int lives = 3;//生命默认3条

int width, height;//飞机图片宽度和高度

boolean canDie = true;//己方每次被撞之后下一条生命有2s无敌时间

 

draw方法:

 

 

public void draw(Graphics g) {
	g.drawImage(myPlane.getImage(), x, y, width, height, null);
}

 

判断是否被撞的方法以及被撞了之后的处理:

 

	/**
	 * 是否和敌方撞到
	 */
	public void bump() {

		// 和任何一种飞机相撞
		if (canDie) {
			// 判断是否游戏结束
			for (int i = 0; i < UI.enermyList.size() && lives > 0; i++) {
				EnermyPlane eps = UI.enermyList.get(i);

				if ((eps.x + eps.width >= x && eps.x <= x + width
						&& eps.y + eps.height / 2 >= y && eps.y <= y + height
						/ 2 - 10)
						|| (eps.x + eps.width / 2 + 20 >= x
								&& eps.x + eps.width / 2 - 20 <= x + width
								&& eps.y + eps.height >= y && eps.y <= y
								+ height)) {
					UI.enermyList.remove(eps);
					haveBump();
					return;
				}
			}

			// 和敌方子弹相撞
			for (int i = 0; i < UI.shotList.size() && lives > 0; i++) {
				Shot st = UI.shotList.get(i);
				if (st.x + st.size >= x && st.x <= x + width
						&& st.y + st.size >= y && st.y <= y + height) {
					UI.shotList.remove(st);
					haveBump();
				}
			}
		}
	}

	/**
	 * 被撞了
	 */
	public void haveBump() {

		lives--;
		explode.play();
		if (lives <= 0) {
			GameOver();
		}
		// 撞到了就移除自己的飞机,过1s再加进来。并且前面2s不会再被撞死
		x = -100;
		y = -100;
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		x = xt;
		y = yt;
		canDie = false;

	}

 

其余方法:

       backgroundMove();//控制背景移动

       GameOver();//游戏结束的处理

 

重写run方法:

public void run() {
		while (lives > 0) {
			try {
				if (!UI.pause) {
					backgroundMove();
					if (!canDie) {
						Thread.sleep(2000);
						canDie = true;
					}//这2s不判断是否被撞
//BUG:这样的话不能发子弹,背景不能移动
					bump();
					if (count % 5 == 0) {
						// 放子弹
						Bullet bul = new Bullet(x + width / 2, y);
						UI.bulList.add(bul);
						new Thread(bul).start();
					}
					count++;
				}

				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

 

Bullet.java

定义属性:

        int speed;

int x, y;

boolean isLive;

int size = 10;

 

构造方法中初始化数据:

public Bullet(int x, int y) {
	speed = 15;
	this.x = x - size / 2;
	this.y = y;
	isLive = true;
}

 

move方法:

 

void move() {
	y -= speed;
	if (y <= 0) {
		isLive = false;
		UI.bulList.remove(this);
	}
}

 

在bump()中判断是否与敌方子弹相撞,重写Thread的run方法,在里面调用move();bump();

while (isLive) {

if (!UI.pause) {

move();

bump();

}

。。。

}

 

EnermyPlane.java

定义属性:

  boolean isLive = true;

Random rd = new Random();

SendShot ss;

int second = rd.nextInt(3000) + 2000;// 发子弹

int x, y,speed;

int width,height;

 

public void moveDown() {

y += speed;

if (y > centerHeight) {//超过最下面了

isLive = false;

//从队列移除

UI.enermyList.remove(this);

}

}

 

public void draw(Graphics g){//在子类中实现

}

 

EnermyPlaneSmall.java(其余两类飞机一样的)

 

构造方法中初始化数据:

        public EnermyPlaneSmall() {

speed = 2 + UI.pass;

isLive = true;

width = enermyPlaneSmall.getIconWidth() / 2;

height = enermyPlaneSmall.getIconHeight() / 2;

x = rd.nextInt(400);

y = -height;

                //ss = new SendShot(this);//发子弹

//UI.ssList.add(ss);

//new Thread(ss).start();

}

 

在bump中判断是否被玩家子弹击中。

 

EnermyThread.java

 

run()中的关键代码:

 

while (MyPlane.lives > 0) {// 我方还存在生命
				// 每隔5s出3-6个小的,共出4-6次.
				if (!UI.pause) {
					for (int k = 0; k < 2; k++) {
						for (int j = 0; j < rd.nextInt(4) + 2
								&& MyPlane.lives > 0; j++) {
							for (int i = 0; i < rd.nextInt(3) + 3; i++) {
								EnermyPlaneSmall eps = new EnermyPlaneSmall();
								UI.enermyList.add(eps);
								new Thread(eps).start();
							}
							Thread.sleep(4000);
						}
						// 出2个中的
						for (int i = 0; i < 2 && MyPlane.lives > 0; i++) {
							EnermyPlaneMedium epm = new EnermyPlaneMedium();
							UI.enermyList.add(epm);
							new Thread(epm).start();
						}
						Thread.sleep(3000);
					}
					// 出来一个Boss
					if (MyPlane.lives > 0) {
						EnermyPlaneLarge epl = new EnermyPlaneLarge();
						UI.enermyList.add(epl);
						new Thread(epl).start();
					}
				}
			}

 

SendShot.java

 

在run中生成Shot对象,并Thread.sleep(ep.second);

如果这个飞机被打死了,这个对象就移出队列,且不再生成Shot对象了。

 

Shot.java

 

定义属性:

        int size = 4;

EnermyPlane ep;

int speed = 8;

int x, y;

 

boolean isLive = true;

 

	@Override
	public void run() {
		while (isLive) {
			if (!UI.pause) {
				isLive = ep.isLive;
				moveDown();
			}
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		if (!ep.isLive) {// 清除剩余的子弹
			UI.shotList.remove(this);
		}
	}

	void draw(Graphics g) {
		g.setColor(Color.white);
		g.fillOval(ep.x + ep.width / 2, y, size, size);
	}

	public void moveDown() {
		y += speed;
		if (y >= 600) {
			UI.shotList.remove(this);
		}
	}

 

附上效果图:



 

 

 

当前已知bug:
撞击判断有很大的误差,最高分有时候会比分数小,游戏结束了后还不能重新开始,玩家挂了一次之后2s无敌时间导致不能发子弹而且背景也不动。

 

 

  • 大小: 41.2 KB
  • 大小: 36.9 KB
  • 大小: 35.3 KB
5
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics