Java飞机大战小游戏(四):敌我飞机的相爱相杀

  • 项目:飞机大战小游戏之绘制敌我飞机的碰撞检测
  • 项目简介:飞机大战小游戏的角色特征+行为
  • 开发工具:eclipse
  • 语言:Java
  • 知识点:Rectangle、模块化、监听器、定时器

代码架构:程序分两个包,共七个类,将前面的代码整合一个,然后修改主程序即可
在这里插入图片描述

操作效果图:
在这里插入图片描述

ImageUtil.java:游戏加载图片的工具类

HitUtil.java:碰撞检测工具类

package com.demo.util;

import java.awt.Rectangle;
import java.awt.image.BufferedImage;

import com.demo.model.EnemyBullet;
import com.demo.model.HeroBullet;
import com.demo.model.HeroPlane;
import com.demo.model.SmallPlane;

/**
 * 碰撞工具类
 */
public class HitUtil {
	/**
	 * 第一种碰撞逻辑:2个矩形碰撞
	 *  矩形1的参数是:左上角的坐标是(x1,y1),宽度是w1,高度是h1;
	 *  矩形2的参数是:左上角的坐标是(x2,y2),宽度是w2,高度是h2。
	 */
	private static boolean isHit(int x1, int y1, int w1,int h1, int x2,int y2,int w2, int h2) {
		
		//两者的矩形范围	
		Rectangle tank1 = new Rectangle(x1,y1,w1,h1);
		Rectangle tank2 = new Rectangle(x2,y2,w2,h2);
		//判断两个矩形是否有交集,crash 为 true 说明碰撞了
		return tank1.intersects(tank2);
	}
	
	//英雄子弹与敌机子弹碰撞
	public static boolean heroBulletHitBullet(HeroBullet hb, EnemyBullet eb) {
		BufferedImage x = hb.getImage();
		BufferedImage y = eb.getImage();
		return isHit(hb.getX(), hb.getY(), x.getWidth(), x.getHeight(), eb.getX(), eb.getY(), y.getWidth(), y.getHeight());
	}
	//英雄子弹与小敌机碰撞
	public static boolean heroBulletHitPlane(HeroBullet hb, SmallPlane eb) {
		BufferedImage x = hb.getImage();
		BufferedImage y = eb.getImage();
		return isHit(hb.getX(), hb.getY(), x.getWidth(), x.getHeight(), eb.getX(), eb.getY(), y.getWidth(), y.getHeight());
	}
	
	//英雄飞机与敌机子弹碰撞
	public static boolean heroPlaneHitBullet(HeroPlane hb, EnemyBullet eb) {
		BufferedImage x = hb.getImage();
		BufferedImage y = eb.getImage();
		return isHit(hb.getX()-x.getWidth()/6, hb.getY()-x.getHeight()/6, x.getWidth()/3, x.getHeight()/3, eb.getX(), eb.getY(), y.getWidth(), y.getHeight());
	}
	
	/**
	 * 第一种碰撞逻辑:2个矩形碰撞,取矩形内最大圆碰撞,即2个矩形转为2个圆形碰撞
	 *   r1  r2 分别为2个圆的半径
	 *   第一个圆圆心:(x1,y1) 
	 *   第二个圆圆心:(x2,y2)  
	 *   
	 * 原理:勾股定理  
	 * 公式:(x1-x2)^2 + (y1 - y2)^2 < r1 + r2   
	 *  
	 */
	//英雄飞机与敌机碰撞
	public static boolean heroPlaneHitEnamyPlane(HeroPlane hb, SmallPlane eb) {
		BufferedImage x = hb.getImage();
		BufferedImage y = eb.getImage();
		
		int centerX1 =hb.getX();
		int centerY1 =hb.getY();
		int centerX2 = eb.getX() + y.getWidth()/2, centerY2 = eb.getY() + y.getHeight()/2;
		// 求两圆的圆心距
		double length = Math.sqrt(Math.pow(centerX1 - centerX2, 2)+ Math.pow(centerY1 - centerY2, 2));
		
		int r1 = Math.min(x.getWidth(), x.getHeight())/2;
		int r2 = Math.min(y.getWidth(), y.getHeight())/2;
		
		return length < (r1 + r2);
	}
	
}

HeroPlane.java / HeroBullet.java:我方飞机和子弹

SmallPlane.java:添加敌机状态 - - 活着、死了

package com.demo.model;

import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import com.demo.util.ImageUtil;

/**
 * 小敌机
 */
public class SmallPlane {

	private int x; // 飞机放置在面板上的x轴
	private int y; // 飞机放置在面板上的y轴
	
	// 定义构造函数
	public SmallPlane() {
		this.x = new Random().nextInt(GameStart.WIDTH - IMAGES[0].getWidth());
		this.y = -IMAGES[0].getHeight();
	}
	
	//状态
	public static final int ALIVE = 0; //活着
	public static final int DEATH = 1;	//死了,击中目标:飞机/对方子弹
	public static final int DELETE = 2; //可删除, 画布中不需要画出来
	
	private  int state = ALIVE;		//默认是表示活着

    private static BufferedImage[] IMAGES;
	static {
		IMAGES = new BufferedImage[5];
		for (int i = 0; i < IMAGES.length; i++) {
			IMAGES[i] = ImageUtil.readImage("smallplane"+i+".png");
		}
	}
	//小敌机的图标
	private int index = 1; //图标索引
	public BufferedImage getImage() {
		if(state == ALIVE) {
			return IMAGES[0];
		}else {
			if(state == DEATH) {
				if(index == IMAGES.length) {
					state = DELETE;
				}else {
					return IMAGES[index];
				}
			}
			index ++;
		}
		return null;
	}

	/**
	 * 行为
	 */
	// 移动
	public void movePlane() {
		this.y += 3;
	}

	// 子弹的移动
	public void moveBullet() {
		this.y += 3;
	}

	// 开火的方法
	public List<EnemyBullet> fire() {
		List<EnemyBullet> list = new ArrayList<EnemyBullet>();
		list.add(new EnemyBullet(this.x + IMAGES[0].getWidth() / 2, this.y + IMAGES[0].getHeight() / 2));
		return list;
	}
	
	//是否越界
	public boolean isOutOfBound() {
		return  this.y > GameStart.HEIGHT + IMAGES[0].getHeight();
	}
	
	//getters/setters方法
}

HeroBullet.java:添加敌机子弹状态 - - 活着、死了

package com.demo.model;

import java.awt.image.BufferedImage;

import com.demo.util.ImageUtil;

/**
 * 飞机子弹
 */
public class HeroBullet{
	
	protected int x;  //画布的x轴
	protected int y;  //画布的y轴
	
	//子弹的状态
	public static final int ALIVE = 0; //活着
	public static final int DEATH = 1;	//死了,击中目标:飞机/对方子弹
	public static final int DELETE = 2; //可删除, 画布中不需要画出来
	
	private  int state = ALIVE;			//默认是表示活着
	
	//构造函数
	public HeroBullet(int x,int y){
		this.x = x;
		this.y = y;
	}
	
	//定义多张图片
	private static BufferedImage[] IMAGES;
	static {
		IMAGES = new BufferedImage[5];
		for (int i = 0; i < IMAGES.length; i++) {
			IMAGES[i] = ImageUtil.readImage("herobullet"+i+".png");
		}
	}
	//飞机子弹的图标
	private int index = 1; //图标索引
	public BufferedImage getImage() {
		if(state == ALIVE) {
			return IMAGES[0];
		}else {
			if(state == DEATH) {
				if(index == IMAGES.length) {
					state = DELETE;
				}else {
					return IMAGES[index];
				}
			}
			index ++;
		}
		return null;
	}
	
	//行为->	移动
	public void move(){
		this.y -= 3; 
	}
	//出界
	public boolean isOutOfBound(){
		return this.y<0;
	}

	//getters/setters方法
}

GameStart.java:主程序

package com.demo.model;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

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

import com.demo.util.HitUtil;
import com.demo.util.ImageUtil;

/**
 * 飞机大战小游戏(四):碰撞吃鸡
 * @author suoyue_zhan
 */
public class GameStart extends JPanel {
	public static final int WIDTH = 400;		//游戏界面宽度
	public static final int HEIGHT = 654; 		//游戏界面长度

	private BufferedImage background1 = ImageUtil.readImage("background.jpg");		// 背景图片:静态
	
	private HeroPlane heroPlane = new HeroPlane(); //英雄机
	//英雄飞机子弹对象->list集合
	private List<HeroBullet> heroBullets = new ArrayList<HeroBullet>();
		
	 //将背景绘制到面板中
	private void paintHeroPlane(Graphics g) {
		BufferedImage image = heroPlane.getImage();
		
		if(heroPlane.getX() == 0) { //飞机刚出来时候
			g.drawImage(image,WIDTH/2-image.getWidth()/2, HEIGHT/2+image.getHeight(), null);
		}else {
			g.drawImage(image,heroPlane.getX()-image.getWidth()/2, heroPlane.getY() - image.getHeight()/2, null);
		}
	}
	
	//绘制飞机的分数与生命
	private void  paintScoreAndLife(Graphics g) {
		g.setColor(new Color(255, 0, 0));				//设置画笔颜色	红0	绿0	蓝0	(0~255)
		g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 20));	//设置字体	字体、样式、字号
		g.drawString("score: "+heroPlane.getScore(), 10, 25);
		g.drawString("life: "+heroPlane.getLife(), 10, 45);
	}
	//绘制飞机子弹
	public void paintHeroBullet(Graphics g){
		for(int i=0;i<heroBullets.size();i++){
			//每个英雄的子弹
			HeroBullet heroBullet = heroBullets.get(i);
			BufferedImage image = heroBullet.getImage();
			
			if(image != null && !heroBullet.isOutOfBound()) {

				g.drawImage(image, heroBullet.getX(), heroBullet.getY(), null);
		
			}
		}
	}
	//飞机发射子弹
	private void heroPlaneFire(){
		List<HeroBullet> list = heroPlane.fire();
		
		//收集子弹,动态绘制
		heroBullets.addAll(list);
	}
	//飞机子弹移动
	private void heroBulletMove() {
		for (HeroBullet heroBullet : heroBullets) {
			heroBullet.move();
		}
	}
	
	//敌机的集合
	private List<SmallPlane> enemyPlanes = new ArrayList<>();
	//敌机登场
	private void enemyPlaneEnter() {
		enemyPlanes.add(new SmallPlane());
	}
	//绘制敌机
	private void paintEnemyPhane(Graphics g) {
		for (int i = 0; i < enemyPlanes.size(); i++) {
			SmallPlane enemyPlane = enemyPlanes.get(i);
			BufferedImage image = enemyPlane.getImage();
			if(image != null && !enemyPlane.isOutOfBound()) {
				g.drawImage(image, enemyPlane.getX(), enemyPlane.getY(), null);
			}
		}
	}
	//小敌机移动
	public void enemyPlaneMove() {
		for (SmallPlane enemyPlane : enemyPlanes) {
				enemyPlane.movePlane();

		}
	}
	private List<EnemyBullet> enemyBullets = new ArrayList<EnemyBullet>(); //敌机子弹集合
	//敌机发送子弹
	private void enemyPlaneFire() {
		for (int i = 0; i < enemyPlanes.size(); i++) {
			SmallPlane enemyPlane = enemyPlanes.get(i);
			List<EnemyBullet> list = enemyPlane.fire();
			enemyBullets.addAll(list);
		}
	}
	//绘制敌机子弹:当子弹出界后,不要绘制出来
	private void paintEnemyBullet(Graphics g) {
		for(int i = 0; i < enemyBullets.size(); i++) {
			EnemyBullet enemyBullet = enemyBullets.get(i);
			BufferedImage image = enemyBullet.getImage();
			if(image != null && !enemyBullet.isOutOfBound()) {
				g.drawImage(image, enemyBullet.getX(), enemyBullet.getY(), null);
			}
		}
	}
	//敌机子弹移动
	private void enemyBulletMove() {
		for (EnemyBullet enemyBullet : enemyBullets) {
			enemyBullet.move();
		}
	}
	
	//检查是否碰撞
	private void checkHit() {
		
		//飞机子弹与敌机子弹碰撞
		for(HeroBullet heroBullet : heroBullets) {
			for(EnemyBullet enemyBullet : enemyBullets) {
				if(heroBullet.getState() == HeroBullet.ALIVE && 
						enemyBullet.getState() == EnemyBullet.ALIVE &&
							HitUtil.heroBulletHitBullet(heroBullet, enemyBullet)
						) {
					heroBullet.setState(HeroBullet.DEATH);
					enemyBullet.setState(EnemyBullet.DEATH);
					
					System.out.println("飞机子弹与敌机子弹撞了.....");
				}
			}
		}
		
		//飞机子弹与敌机碰撞 
		for(HeroBullet heroBullet : heroBullets) {
			for(SmallPlane enemyPlane : enemyPlanes) {
				if(heroBullet.getState() == HeroBullet.ALIVE && 
						enemyPlane.getState() == SmallPlane.ALIVE &&
							HitUtil.heroBulletHitPlane(heroBullet, enemyPlane)
						) {
					heroBullet.setState(HeroBullet.DEATH);
					enemyPlane.setState(SmallPlane.DEATH);
					
					System.out.println("飞机子弹与敌机撞了.....");
				}
			}
		}
		
		//英雄飞机与敌机子弹碰撞		
		//英雄飞机与敌机碰撞
		
	}
		
	//清除碰撞
	private void clearHitObject() {
		//英雄子弹
		synchronized (heroBullets) {
			Iterator<HeroBullet> iter1 = heroBullets.iterator();
			while(iter1.hasNext()) {
				HeroBullet next = iter1.next();
				if(next.isOutOfBound() || next.getState() != HeroBullet.ALIVE) {
					iter1.remove();
				}
			}
		}
		
		//敌机子弹
		synchronized (enemyBullets) {			
			Iterator<EnemyBullet> iter2 = enemyBullets.iterator();
			while(iter2.hasNext()) {
				EnemyBullet next = iter2.next();
				if(next.isOutOfBound() || next.getState() != EnemyBullet.ALIVE) {
					iter2.remove();			//从底层集合中删除此迭代器返回的最后一个元素(可选操作)
				}
			}
		}
		
		//敌机
		synchronized (enemyPlanes) {
			//敌机
			Iterator<SmallPlane> iter3 = enemyPlanes.iterator();
			while(iter3.hasNext()) {
				SmallPlane next = iter3.next();
				if(next.isOutOfBound() || next.getState() != SmallPlane.ALIVE) {
					iter3.remove();
				}
			}
		}
		
	}	
	
	// 重写JPanel的绘制方法-->>所有图片都在该方法上执行
	@Override
	public void paint(Graphics g) {
		
		//绘制背景图
		g.drawImage(background1, 0, 0, null);
		
		this.paintHeroPlane(g);			//调用方法,绘制飞机
		this.paintHeroBullet(g);		//调用方法绘制飞机子弹
		this.paintScoreAndLife(g);		//绘制飞机的分数与生命
		
		this.paintEnemyPhane(g);		//绘制敌机
		this.paintEnemyBullet(g);		//绘制敌机子弹

	}
	
	/**
	 * 窗口初始化
	 */
	public void init() {
		JFrame jFrame = new JFrame("飞机大战"); // 设置窗口标题

		jFrame.add(this); // this表示主类,也表示画板

		jFrame.setSize(WIDTH, HEIGHT); // 设置窗口大小
		jFrame.setLocationRelativeTo(null); // 设置窗口居中
		jFrame.setAlwaysOnTop(true); // 设置窗口总是在顶端
		jFrame.setResizable(false); // 设置不允许拖拉
		jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗口时退出程序
		jFrame.setIconImage(new ImageIcon("./images/icon.png").getImage()); // 设置图标
		jFrame.setVisible(true); // 使窗口显示出来
				
		initListener();		//安装程序监听器	
		initTimer();		//设置定时器,用于实现游戏中所有的动态逻辑效果
	}
	
	/**
	 * 监控鼠标的监听器
	 */
	private void initListener() {
		//使用鼠标监听器的适配器
		MouseAdapter adapter = new MouseAdapter() {
			@Override
			public void mouseMoved(MouseEvent e) {
				//获取鼠标的x坐标与y坐标
				System.out.println("x: " + e.getX() + "y: " + e.getY());
				//飞机跟随鼠标移动
				heroPlane.move(e.getX(), e.getY());
				repaint();  //重新绘制飞机, 底层是重写执行paint方法
			}
		};		
		//添加鼠标监听器
		this.addMouseListener(adapter);
		this.addMouseMotionListener(adapter);		
	}
	
	/**
	 * 定时器
	 */
	private long count = 0;	//控制频率
	public void initTimer(){
		
		Timer timer = new Timer();		//定时器对象
		long delay = 10; 
		long period = 10;
		//定时执行操作
		//参数1:每隔一段时间执行的操作
		//参数2:几毫米之后执行定时器
		//参数3:每个几毫米执行一次
		timer.schedule(new TimerTask() {
			@Override
			public void run() {		
			
				//飞机发射子弹
				if(count % 10 == 0 ){
					heroPlaneFire(); 	
				}				
				//英雄子弹移动
				//if(count % 2 == 0){
					heroBulletMove();	
				//}
							
				//敌机登场
				if(count % 50 == 0) {
					enemyPlaneEnter();
				}			
				//敌机移动
				if(count % 2 == 0) {
					enemyPlaneMove();
				}
				//敌机发送子弹
				if(count % 50 == 0) {
					enemyPlaneFire();
				}
				//敌机子弹的移动
				enemyBulletMove();
				
				//检查是否碰撞了
				checkHit();
				
				//清除碰撞后的对象
				if(count % 10 == 0) {
					clearHitObject();
				}
				
				if(count == Long.MAX_VALUE-1){
					count = 0;
				}
				count++;		
			
				repaint(); //重新绘制页面
			}
		}, delay,period);
	}

	/*
	 * 程序入口main()
	 */
	public static void main(String[] args) {
		System.out.println("游戏开始了.....");

		GameStart gameStart = new GameStart();
		gameStart.init(); //显示主界面
	}
	
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值