飞机大战游戏补充

这是上篇飞机大战全部思路及源码的链接
——————————————————————————————————————

这篇东西主要是补充说明上一篇中我画布类中的方法,以及我在做的时候碰到的一些bug。

public class GamePanel extends JPanel {
	BufferedImage bg = null;

	// new英雄机对象
	hero hero = new hero();
	// new敌机对象
//	Ep ep = new Ep();
	// 建立敌机集合 不使用数组做容器是因为敌机数量未知,建立数组先要定义数组长度
	List<Ep> eps = new ArrayList<Ep>();
	// 建立子弹的弹药库
	List<Fire> fs = new ArrayList<Fire>();

	// 定义分数
	int socre;
	boolean gameover;// 设置开关
	int power = 1;// 火力值

	/*
	 * 开始游戏的方法 建立一个线程
	 */
	public void action() {
		new Thread() {
			public void run() {
				while (true) {
					// if语句判断是否gameover
					if (!gameover) {
						epEnter();// 敌机进场
						epMove();

						// 发射子弹
						shoot();

						// 子弹移动
						fireMove();
						shootEp();
						hit();
					}
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
					repaint();// 刷新界面
				}
			}

			/*
			 * 检测子弹是否打到敌机
			 */
			public void shootEp() {
				// 遍历所有子弹
				for (int i = 0; i < fs.size(); i++) {
					Fire f = fs.get(i);
					bang(f);
				}

			}

			/*
			 * 判断子弹是否击中敌机
			 */
			private void bang(Fire f) {
				for (int i = 0; i < eps.size(); i++) {
					Ep e = eps.get(i);
					if (e.shootBy(f)) {
						e.hp--;
						// 当敌机没hp,死亡
						if (e.hp <= 0) {
							if (e.type == 12) {
								power++;
								if (power > 3) {
									hero.hp++;
									power = 3;
								}
							}
							eps.remove(e);// 移除敌机
							fs.remove(f);// 移除子弹
						}

						// 增加分数
						socre += 10;
						if(socre%1000==0) {
							Random rd = new Random();
							int index = rd.nextInt(5) + 1;
							bg = ImageUtil.getImage("/img/bg" + index + ".jpg");
							repaint();// 刷新界面
							hero.hp++;
						}
					}
				}

			}
		}.start();
	}

	/**
	 * 检测敌机是否撞到了英雄机
	 */

	protected void hit() {
		// 遍历敌机
		for (int i = 0; i < eps.size(); i++) {
			// 获取一个敌机
			Ep e = eps.get(i);
			// 如果敌机被英雄机撞上了
			if (e.hitBy(hero)) {
				// 1.删除敌机
				eps.remove(e);
				// 2.英雄机的血量减少
				hero.hp--;
				// 英雄机的火力恢复为1
				power = 1;
				// 3.增加分数
				socre += 10;
				
				// 4.当英雄机的血量减少到0时,游戏结束
				if (hero.hp <= 0) {
					// 游戏结束
					gameover = true;
				}
			}
		}
	}

	public void fireMove() {
		for (int i = 0; i < fs.size(); i++) {
			Fire f = fs.get(i);
			f.move();

		}

	}

	// 发射子弹
	int fireindax = 0;// 记录执行的次数

	public void shoot() {
		fireindax++;
		if (fireindax >= 10) {
			if (power == 1) {
				// 创建子弹
				Fire fire3 = new Fire(hero.x + 45, hero.y - 20, 1);
				// 将子弹加入到弹药库
				fs.add(fire3);
			} else if (power == 2) {
				// 创建子弹
				Fire fire1 = new Fire(hero.x + 15, hero.y, 1);
				// 将子弹加入到弹药库
				fs.add(fire1);
				// 创建子弹
				Fire fire2 = new Fire(hero.x + 75, hero.y, 1);
				// 将子弹加入到弹药库
				fs.add(fire2);
			} else if (power == 3) {
				// 创建子弹
				Fire fire1 = new Fire(hero.x + 15, hero.y, 0);
				// 将子弹加入到弹药库
				fs.add(fire1);
				// 创建子弹
				Fire fire2 = new Fire(hero.x + 75, hero.y, 2);
				// 将子弹加入到弹药库
				fs.add(fire2);
				// 创建子弹
				Fire fire3 = new Fire(hero.x + 45, hero.y - 20, 1);
				// 将子弹加入到弹药库
				fs.add(fire3);
			}
			fireindax = 0;// 计算器
		}
	}

	public void epMove() {
		for (int i = 0; i < eps.size(); i++) {
			Ep e = eps.get(i);
			e.move();
		}

	}

	/*
	 * 敌机入场方法 该方法在死循环中一直调用
	 */

	int indax = 0;

	public void epEnter() {
		indax++;
		if (indax >= 20) {
			Ep e = new Ep();
			eps.add(e);// 把敌机不断加入到集合里面
			indax = 0;
		}
	}

	public GamePanel(GameFrame frame) {
		setBackground(Color.BLACK);
		bg = ImageUtil.getImage("/img/bg2.jpg");

		// 使用鼠标监听器
		// 1创建鼠标监听器
		MouseAdapter md = new MouseAdapter() {

			@Override
			public void mouseClicked(MouseEvent e) {
				// 点击鼠标时,会执行的代码
				// 如果游戏结束了,点击屏幕时重新开始游戏
				if (gameover) {
					// 重新开始游戏
					// 需要做些什么事情?
					// 重新创建一个英雄机
					hero = new hero();
					// 重置游戏开关
					gameover = false;
					// 分数清0
					socre = 0;
					eps.clear();// 清空敌机集合
					fs.clear();// 清空子弹集合
					// 随机背景图
					Random rd = new Random();
					int index = rd.nextInt(5) + 1;
					bg = ImageUtil.getImage("/img/bg" + index + ".jpg");
					repaint();
				}
			}

			// 2确定鼠标监听事件
			@Override
			public void mouseMoved(MouseEvent e) {
				int mX = e.getX();
				int mY = e.getY();
				// 判断游戏是否结束,结束则不能移动
				if (!gameover) {
					hero.MovetoMouse(mX, mY);
				}
				repaint();// 刷新界面
			}

		};
		// 将适配器加到监听器中
		addMouseListener(md);
		addMouseMotionListener(md);

		// ------------------------------------------
		// 使用键盘监听器

//		KeyAdapter kd = new KeyAdapter() {
//			@Override
//			public void keyPressed(KeyEvent e) {
//				int KeyCode = e.getKeyCode();
//				if (KeyCode == KeyEvent.VK_UP || KeyCode == KeyEvent.VK_W) {
//					hero.MoveUp();
//					repaint();// 刷新界面
//				} else if (KeyCode == KeyEvent.VK_DOWN || KeyCode == KeyEvent.VK_S) {
//					hero.MoveDown();
//					repaint();// 刷新界面
//				} else if (KeyCode == KeyEvent.VK_LEFT || KeyCode == KeyEvent.VK_A) {
//					hero.MoveLeft();
//					repaint();// 刷新界面
//				} else if (KeyCode == KeyEvent.VK_RIGHT || KeyCode == KeyEvent.VK_D) {
//					hero.MoveRight();
//					repaint();// 刷新界面
//				}
//			}
//		};
//		frame.addKeyListener(kd);// 键盘适配器要加到窗体监听器

	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		// draw有先后顺序,先画会被后画覆盖
		g.drawImage(bg, 0, 0, null);
		g.drawImage(hero.img, hero.x, hero.y, hero.w, hero.h, null);

		// 遍历集合里面的所有敌机并显示出来
		for (int i = 0; i < eps.size(); i++) {
			Ep ep = eps.get(i);
			g.drawImage(ep.img, ep.x, ep.y, ep.w, ep.h, null);
		}

		// 遍历集合里面的所有子弹并显示出来
		for (int i = 0; i < fs.size(); i++) {
			Fire fire = fs.get(i);
			g.drawImage(fire.img, fire.x, fire.y, fire.w, fire.h, null);
		}

		// 画分数
		g.setColor(Color.white);
		g.setFont(new Font("楷体", Font.BOLD, 20));
		g.drawString("分数: " + socre, 10, 30);

		// 画英雄机的血量
		for (int i = 0; i < hero.hp; i++) {
			g.drawImage(hero.img, 470, 5+ i * 30, 30, 30, null);
		}

		// 当游戏结束时,显示Gameover
		if (gameover) {
			g.setColor(Color.red);
			g.setFont(new Font("楷体", Font.BOLD, 35));
			g.drawString("GAMEOVER!", 35, 300);
			g.setColor(Color.green);
			g.setFont(new Font("楷体", Font.BOLD, 20));
			g.drawString("提醒你点击屏幕重新开始游戏", 40, 350);
		}
	}
}

代码从上而下说明
开启线程,让多个敌机多个子弹得以同时进场,用死循环让方法能一直被调用。
public void action() {
		new Thread() {
			public void run() {
				while (true) {
					// if语句判断是否gameover
					if (!gameover) {
						epEnter();// 敌机进场
						epMove();

						// 发射子弹
						shoot();

						// 子弹移动
						fireMove();
						shootEp();
						hit();
					}
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						// TODO 自动生成的 catch 块
						e.printStackTrace();
					}
					repaint();// 刷新界面
				}
			}

————————————————————————————————

射击方法,从集合中遍历所有子弹,再执行bang()方法判断子弹是否击中敌机并执行血量减少,分数增加等操作。
public void shootEp() {
				// 遍历所有子弹
				for (int i = 0; i < fs.size(); i++) {
					Fire f = fs.get(i);
					bang(f);
				}

			}

			/*
			 * 判断子弹是否击中敌机
			 */
			private void bang(Fire f) {
				for (int i = 0; i < eps.size(); i++) {
					Ep e = eps.get(i);
					if (e.shootBy(f)) {
						e.hp--;
						// 当敌机没hp,死亡
						if (e.hp <= 0) {
							if (e.type == 12) {
								power++;
								if (power > 3) {
									hero.hp++;
									power = 3;
								}
							}
							eps.remove(e);// 移除敌机
							fs.remove(f);// 移除子弹
						}

						// 增加分数
						socre += 10;
						if(socre%1000==0) {
							Random rd = new Random();
							int index = rd.nextInt(5) + 1;
							bg = ImageUtil.getImage("/img/bg" + index + ".jpg");
							repaint();// 刷新界面
							hero.hp++;
						}
					}
				}

			}

————————————————————————————————

该方法用于判断敌机是否撞到战机,碰撞后敌机与战机属性的一系列变化。
/**
	 * 检测敌机是否撞到了英雄机
	 */

	protected void hit() {
		// 遍历敌机
		for (int i = 0; i < eps.size(); i++) {
			// 获取一个敌机
			Ep e = eps.get(i);
			// 如果敌机被英雄机撞上了
			if (e.hitBy(hero)) {
				// 1.删除敌机
				eps.remove(e);
				// 2.英雄机的血量减少
				hero.hp--;
				// 英雄机的火力恢复为1
				power = 1;
				// 3.增加分数
				socre += 10;
				
				// 4.当英雄机的血量减少到0时,游戏结束
				if (hero.hp <= 0) {
					// 游戏结束
					gameover = true;
				}
			}
		}
	}

————————————————————————————————

该方法遍历集合中的所有子弹,并调用Fire类的move()方法进行子弹的移动。
public void fireMove() {
		for (int i = 0; i < fs.size(); i++) {
			Fire f = fs.get(i);
			f.move();

		}

	}
该方法遍历集合中的所有敌机,并调用Ep类中的move()方法进行移动
public void epMove() {
		for (int i = 0; i < eps.size(); i++) {
			Ep e = eps.get(i);
			e.move();
		}

	}

————————————————————————————————

这是一个定义射击的方法,定义战机不同火力的子弹情况,计数器减缓子弹的出现速度,将子弹加入到集合中。
// 发射子弹
	int fireindax = 0;// 记录执行的次数

	public void shoot() {
		fireindax++;
		if (fireindax >= 10) {
			if (power == 1) {
				// 创建子弹
				Fire fire3 = new Fire(hero.x + 45, hero.y - 20, 1);
				// 将子弹加入到弹药库
				fs.add(fire3);
			} else if (power == 2) {
				// 创建子弹
				Fire fire1 = new Fire(hero.x + 15, hero.y, 1);
				// 将子弹加入到弹药库
				fs.add(fire1);
				// 创建子弹
				Fire fire2 = new Fire(hero.x + 75, hero.y, 1);
				// 将子弹加入到弹药库
				fs.add(fire2);
			} else if (power == 3) {
				// 创建子弹
				Fire fire1 = new Fire(hero.x + 15, hero.y, 0);
				// 将子弹加入到弹药库
				fs.add(fire1);
				// 创建子弹
				Fire fire2 = new Fire(hero.x + 75, hero.y, 2);
				// 将子弹加入到弹药库
				fs.add(fire2);
				// 创建子弹
				Fire fire3 = new Fire(hero.x + 45, hero.y - 20, 1);
				// 将子弹加入到弹药库
				fs.add(fire3);
			}
			fireindax = 0;// 计数器
		}
	}

————————————————————————————————

该方法与上一个方法作用一致,
/*
	 * 敌机入场方法 该方法在死循环中一直调用
	 */

	int indax = 0;

	public void epEnter() {
		indax++;
		if (indax >= 20) {
			Ep e = new Ep();
			eps.add(e);// 把敌机不断加入到集合里面
			indax = 0;
		}
	}

————————————————————————————————

该方法用于定义背景,清空背景等操作
public GamePanel(GameFrame frame) {
		setBackground(Color.BLACK);
		bg = ImageUtil.getImage("/img/bg2.jpg");

		// 使用鼠标监听器
		// 1创建鼠标监听器
		MouseAdapter md = new MouseAdapter() {

			@Override
			public void mouseClicked(MouseEvent e) {
				// 点击鼠标时,会执行的代码
				// 如果游戏结束了,点击屏幕时重新开始游戏
				if (gameover) {
					// 重新开始游戏
					// 需要做些什么事情?
					// 重新创建一个英雄机
					hero = new hero();
					// 重置游戏开关
					gameover = false;
					// 分数清0
					socre = 0;
					eps.clear();// 清空敌机集合
					fs.clear();// 清空子弹集合
					// 随机背景图
					Random rd = new Random();
					int index = rd.nextInt(5) + 1;
					bg = ImageUtil.getImage("/img/bg" + index + ".jpg");
					repaint();
				}
			}		

————————————————————————————————

这是定义鼠标或者键盘监听的方法
// 2确定鼠标监听事件
			@Override
			public void mouseMoved(MouseEvent e) {
				int mX = e.getX();
				int mY = e.getY();
				// 判断游戏是否结束,结束则不能移动
				if (!gameover) {
					hero.MovetoMouse(mX, mY);
				}
				repaint();// 刷新界面
			}

		};
		// 将适配器加到监听器中
		addMouseListener(md);
		addMouseMotionListener(md);

		// ------------------------------------------
		// 使用键盘监听器

//		KeyAdapter kd = new KeyAdapter() {
//			@Override
//			public void keyPressed(KeyEvent e) {
//				int KeyCode = e.getKeyCode();
//				if (KeyCode == KeyEvent.VK_UP || KeyCode == KeyEvent.VK_W) {
//					hero.MoveUp();
//					repaint();// 刷新界面
//				} else if (KeyCode == KeyEvent.VK_DOWN || KeyCode == KeyEvent.VK_S) {
//					hero.MoveDown();
//					repaint();// 刷新界面
//				} else if (KeyCode == KeyEvent.VK_LEFT || KeyCode == KeyEvent.VK_A) {
//					hero.MoveLeft();
//					repaint();// 刷新界面
//				} else if (KeyCode == KeyEvent.VK_RIGHT || KeyCode == KeyEvent.VK_D) {
//					hero.MoveRight();
//					repaint();// 刷新界面
//				}
//			}
//		};
//		frame.addKeyListener(kd);// 键盘适配器要加到窗体监听器

	}

————————————————————————————————

该方法用于在背景上显示出飞行物和一些其他内容
	@Override
	public void paint(Graphics g) {
		super.paint(g);
		// draw有先后顺序,先画会被后画覆盖
		g.drawImage(bg, 0, 0, null);
		g.drawImage(hero.img, hero.x, hero.y, hero.w, hero.h, null);

		// 遍历集合里面的所有敌机并显示出来
		for (int i = 0; i < eps.size(); i++) {
			Ep ep = eps.get(i);
			g.drawImage(ep.img, ep.x, ep.y, ep.w, ep.h, null);
		}

		// 遍历集合里面的所有子弹并显示出来
		for (int i = 0; i < fs.size(); i++) {
			Fire fire = fs.get(i);
			g.drawImage(fire.img, fire.x, fire.y, fire.w, fire.h, null);
		}

		// 画分数
		g.setColor(Color.white);
		g.setFont(new Font("楷体", Font.BOLD, 20));
		g.drawString("分数: " + socre, 10, 30);

		// 画英雄机的血量
		for (int i = 0; i < hero.hp; i++) {
			g.drawImage(hero.img, 470, 5+ i * 30, 30, 30, null);
		}

		// 当游戏结束时,显示Gameover
		if (gameover) {
			g.setColor(Color.red);
			g.setFont(new Font("楷体", Font.BOLD, 35));
			g.drawString("GAMEOVER!", 35, 300);
			g.setColor(Color.green);
			g.setFont(new Font("楷体", Font.BOLD, 20));
			g.drawString("提醒你点击屏幕重新开始游戏", 40, 350);
		}
	}

————————————————————————————————

下面是我在做时候碰到的一些bug总结

问题1:在调用 repaint(); 方法刷新界面时出现每刷新一次闪一次的情况。
我的解决方法:我一开始继承的是Panel类而不是JPanel,改成继承JPanel类后恢复正常
问题2:出现数组越界
我的解决方法:检查自己的所有遍历集合中是否把i<集合.size() 写成i<=集合.size()。
问题3:飞行物没有显示出来
我的解决方法:需要在窗体类中加入运行游戏方法后面加入frame.setVisible(true);显示飞行物。
问题4:三目运算符和字符串拼接时出现的问题
该问题知识总结:+号可以用作加法,也可以用作拼接字符串,当加号遇到双引号之前做加法,遇到双引号开始或之后都只做连接,连接之后的结果都是字符串。
如下图:

在这里插入图片描述

发布了11 篇原创文章 · 获赞 0 · 访问量 173

猜你喜欢

转载自blog.csdn.net/weixin_44824500/article/details/104393664