Java学习之路:简单的飞机大战游戏(敌机下落篇)

本文详细介绍了一款飞机大战游戏的设计思路与实现过程,重点介绍了敌机下落规则、使用线程控制游戏元素移动、双缓冲技术减少画面闪烁等关键技术点。

在实现这个游戏之前,我们首先需要知道项目可能要用到哪些知识点:
重绘,线程,双缓冲,数据结构的应用

差不多是这大概有这些,如果不够的话我们再加。
首先,我们应该实现敌机下落,在这里大概思路和利用线程使小球下落差不多。不同的是,我在这里用到了三种敌机,分别为小、大、BOSS机三种。然后给予这三种敌机不同的下落规则(即速度、出现的时间、是否伴随子弹的发射等等)来给游戏适当的增加点难度。

以下是我的大概设计思路和下落规则,大家可以参考一下

1.飞机是在一开始的时候就出现的,先出现什么飞机?速度?什么位置出现?频率?
	先出小飞机,再出大飞机,当所有的大小飞机都消失以后出现BOSS机.
	小飞机的速度较快:8	大飞机的速度较慢:4	BOSS机的速度最慢:2
	频率:每隔1秒出现一架小飞机,每出现4架小飞机后出现一架大飞机,最后出现BOSS机.
	位置:在窗体的范围内,考虑到png图片的高度和宽度,所以出现的时候注意减去相应的高度和宽度.
	
2.小飞机,大飞机,BOSS机需要使用不同的vector类来保存,取出的时候再使用一个vector类来保存(保存的时候应该
将三个vector类中原来的飞机移除).再将保存起来的飞机依次进行画出.当出现4架小飞机的时候就出现一架大飞机,当
小飞机和大飞机都出现完了以后,出现BOSS机.注意:大飞机和BOSS机的时候伴随着子弹的发出.

3.子弹:
	子弹在大飞机和BOSS机出现的时候出现.且速度优于大飞机和BOSS机.因为小飞机没有子弹,在这里我们利用byte标记
	来区别于小飞机和其他两种飞机,另外也需要将子弹标记,以防止子弹生成子弹。
	
4.使用两个线程:
	(1)一个线程用来实现将不同的vector向量取出的飞机(先将大小飞机取出以后,再取出BOSS机,每取一次小飞机的
	时候将count记一次数,当count==4的时候,取出一架大飞机.当小飞机和大飞机全部取完以后再取出BOSS机),并保存在一个
	统一的vector向量中.	
	(2)另一个线程用来实现画飞机和子弹并使其移动.
	
5.效果图出现过于闪烁的情况可以利用双缓冲技术来减少闪烁。

以下是代码主类,主要生成窗体和敌机,并将敌机保存在不同的vector向量中。

public class BallMain {

	public Graphics g;
	public Vector<Ball> vector, minVector, maxVector, bossVector;
	public ImageIcon img;

	public static void main(String[] args) {
		BallMain bm = new BallMain();
		bm.init();

	}

	public void init() {
		JFrame frame = new JFrame();
		frame.setTitle("飞机大战");
		frame.setSize(800, 800);
		frame.setDefaultCloseOperation(3);
		frame.setLocationRelativeTo(null);
		frame.setBackground(Color.white);
		frame.setResizable(false); // 不允许改变窗体大小

		frame.setVisible(true);

		this.g = frame.getGraphics();

		minVector = new Vector<Ball>();
		maxVector = new Vector<Ball>();
		bossVector = new Vector<Ball>();
		vector = new Vector<Ball>();

		initPlane(frame);

		BallThread bt = new BallThread(vector, minVector, maxVector,
				bossVector, frame);
		bt.start();

		BallGraThread bll = new BallGraThread(vector, frame,
				frame.getGraphics());
		bll.start();
	}

	public void initPlane(JFrame frame) {
		Random rand = new Random();
		// 小飞机的生成
		for (int i = 0; i < 8; i++) {
			ImageIcon icon = new ImageIcon("plane/plane0.png");
			int r = icon.getIconWidth() / 2;
			int x = rand.nextInt(frame.getWidth() - icon.getIconWidth()) + r;
			int y = -icon.getIconHeight();
			int vy = 8;
			Ball b = new Ball(icon.getImage(), x, y, r, vy, (byte) 1);
			minVector.add(b);
		}
		// 大飞机的生成
		for (int i = 0; i < 2; i++) {
			ImageIcon icon = new ImageIcon("plane/plane1.png");
			int r = icon.getIconWidth() / 2;
			int x = rand.nextInt(frame.getWidth() - icon.getIconWidth()) + r;
			int y = -icon.getIconHeight();
			int vy = 4;

			Ball b = new Ball(icon.getImage(), x, y, r, vy, (byte) 2);
			maxVector.add(b);
		}
		// Boss机的生成
		ImageIcon icon = new ImageIcon("plane/plane2.png");
		int r = icon.getIconWidth() / 2;
		int x = rand.nextInt(frame.getWidth() - icon.getIconWidth()) + r;
		int y = -icon.getIconHeight();
		int vy = 2;
		Ball b = new Ball(icon.getImage(), x, y, r, vy, (byte) 3);
		bossVector.add(b);
	}
}

以下为飞机的下落规则:

public BallThread(Vector<Ball> vector, Vector<Ball> minVector,
			Vector<Ball> maxVector, Vector<Ball> bossVector, JFrame frame) {
		this.vector = vector;
		this.minVector = minVector;
		this.maxVector = maxVector;
		this.bossVector = bossVector;

		this.frame = frame;
	}

	public void run() {
		int count = 0;
		while (true) {
			if (minVector.size() > 0) {
				vector.add(minVector.remove(0));
				++count;
				if (count == 4) {
					if (maxVector.size() > 0) {
						vector.add(maxVector.remove(0));
						count = 0;
					}
				}
			}
			if (vector.size() == 0) {
				vector.add(bossVector.remove(0));
				break;
			}
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

利用双缓冲减少闪烁,画出飞机并擦除,使其不断更新位置:

public class BallGraThread extends Thread {

	public Vector<Ball> vector;
	public JFrame frame;
	public Graphics g;
	public BufferedImage image;
	public Graphics ig;

	public BallGraThread(Vector<Ball> vector, JFrame frame, Graphics g) {
		this.vector = vector;
		this.frame = frame;
		this.g = g;
	}

	public void run() {
		if (image == null) {
			
			//创建一个带透明色的BufferedImage对象
			image = new BufferedImage(frame.getWidth(), frame.getHeight(),
					BufferedImage.TYPE_INT_ARGB);
			//获取画笔对象.
			ig = image.getGraphics();
		}
		while (true) {
			//擦除.
			ig.setColor(frame.getContentPane().getBackground());
			ig.fillRect(0, 0, frame.getWidth(), frame.getHeight());

			for (int i = 0; i < vector.size(); i++) {
				Ball ball = vector.get(i);
				ball.draw(ig);
				ball.move(vector, frame, ig);
			}

			g.drawImage(image, 0, 0, frame);

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

		}
	}
}

子弹类,标记子弹来区分三种敌机,当飞机和子弹飞出窗体外后将其移除与vector:

public class Ball {
	public int x, y;
	public int flag = 1;
	public Color color;
	public Image img;
	public BulletThread ba;
	int r;
	int vy;
	byte type;
	Random random = new Random();

	public Ball(Image img, int x, int y, int r, int vy, byte type) {
		this.img = img;
		this.x = x;
		this.y = y;
		this.r = r;
		this.vy = vy;
		this.type = type;
	}

	public void move(Vector<Ball> vector, JFrame frame, Graphics g) {
		if (y >= 0 && flag == 1) {
			// 如果是大飞机或者BOSS机的话,就发射子弹.
			if (type == 2 || type == 3) {
				ba = new BulletThread(vector, this);
				ba.start();
				flag = 2;
				System.out.println(ba);
			}
		}

		if (y >= frame.getHeight()) {
			img = new ImageIcon("planne/bullet.png").getImage();
			g.drawImage(img, x, y, 2 * r, 2 * r, null);
			System.out.println(ba);
			if (type == 2 || type == 3)
				ba.stopFlag = false;
			vector.remove(this);
		}
		y = y + vy;
	}

	public void draw(Graphics g) {
		// 需要将ImageIcon转为Image类型的.
		g.drawImage(img, x, y, 2 * r, 2 * r, null);

	}

}

画出子弹并添加于vector向量中,使其移动:

public class BulletThread extends Thread {
	public Vector<Ball> vector;
	public Ball ball;// 大飞机的数据来生成子弹
	public boolean stopFlag = true;
	public boolean pauseFlag = true;

	public BulletThread(Vector<Ball> vector, Ball ball) {
		this.vector = vector;
		this.ball = ball;
	}

	public void run() {
		while (stopFlag) {
			if (pauseFlag) {
				int x = ball.x + ball.r;
				int y = ball.y + 2 * ball.r;
				int r = 20;
				Image img = new ImageIcon("plane/bullet.png").getImage();
				int vy = ball.vy + 4;
				Ball bullet = new Ball(img, x, y, r, vy, (byte) 0);
				vector.add(bullet);
			}
			try {
				Thread.sleep(4000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

以上差不多就是敌机的下落,其他的一些功能尚未完善,比如可以给敌机添加不同的血量再来增加难度,大家可以根据自己的发挥来写出属于自己的飞机大战游戏。

基于Java飞机大战游戏主要需要我方飞机和敌方飞机,还有子弹,特殊nPC,开始背景,结束背景,以及背景音乐。我方飞机可以随意移动,敌方飞机无规律出现。游戏玩家通过鼠标移动控制飞机移动,我方飞机游戏开始时就一直能发射子弹,当我方子弹碰到敌方飞机时,敌方飞机消失。当玩家飞机碰到敌方子弹时,生命值减一,直到玩家飞机生命值为一时,游戏结束。基本模块包括:游戏状态控制功能模块、游戏难度的调整模块、游戏界面绘画功能模块、玩家游戏控制功能模块等。本系统结构如下: (1)游戏状态控制功能模块:游戏的状态控制包括运行及结束游戏,首先进入游戏的开始页面,在游戏进行时,玩家必须躲避或者击落敌方飞机,玩家飞机的生命值降低为0的时候游 戏就会结束,弹出游戏结束界面 (2)游戏难度的调整模块:玩家玩的时间越长游戏的难度越高,敌方飞机的数量越多、敌方飞机出现的频率越高,玩家保证飞机的存活的难度越高,操作难度相应也高。 (3)游戏界面绘画功能模块:左上角会显示玩家飞机当前生命值,游戏时间,当前分数,其他地方用来输出玩家对我方飞机的控制与敌方飞机的动作显示 (4)玩家游戏控制功能模块: 玩家可以通过控制鼠标或者键盘来控制方飞机(Hero airplane)的移动。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值