首页 > 编程语言 >【经典游戏】Java实现飞机大战小游戏

【经典游戏】Java实现飞机大战小游戏

时间:2024-03-29 18:32:21浏览次数:20  
标签:Java img int 大战 width 小游戏 theta public Math

【引言】

90、00后的童年是游戏机,当时的飞机大战,一度风靡全球。

 经典项目java实现飞机大战射击游戏资源-CSDN文库

一、游戏设计

实现飞机大战游戏是一个很有趣的项目,可以帮助你学习和练习 Java 编程的各种方面,包括面向对象设计、图形界面编程等。下面是一个详细的分析,涵盖了设计步骤思路和具体功能:

1、设计步骤思路:
  • 游戏框架搭建

    • 创建一个 Java 项目。
    • 使用 Java GUI 库(如Swing或JavaFX)来构建游戏界面。
  • 设计游戏元素

    • 飞机:玩家飞机和敌方飞机,分别有不同的属性(速度、生命值等)。
    • 子弹:玩家飞机和敌方飞机发射的子弹。
  • 游戏逻辑设计

    • 碰撞检测:检测飞机和子弹之间的碰撞。
    • 得分系统:根据击败敌机数量计算得分。
  • 用户交互

    • 键盘控制:玩家通过键盘控制飞机移动和发射子弹。
    • 鼠标控制:可以使用鼠标来控制飞机或者发射子弹。
  • 游戏流程

    • 游戏开始界面:包括开始游戏和退出游戏选项。
    • 游戏进行界面:显示飞机、敌机、得分等信息。
    • 游戏结束界面:显示得分和重新开始游戏选项。
2、具体功能:
  • 飞机移动

    • 玩家飞机随着键盘操作左右移动,避开敌机和敌方子弹。
    • 敌机在屏幕顶部生成并向下移动,玩家需要躲避它们的攻击。
  • 发射子弹

    • 玩家飞机可以发射子弹,击中敌机可以得分。
    • 敌机也可以发射子弹,玩家需要躲避或击毁它们。
  • 碰撞检测

    • 当玩家子弹击中敌机或者敌机子弹击中玩家飞机时,进行碰撞检测,减少生命值或者销毁飞机。
  • 得分计算

    • 根据击败敌机数量来计算得分,可以在界面上显示当前得分。
  • 游戏状态管理

    • 包括游戏开始、进行中和结束等状态的管理,切换不同界面和逻辑。
  • 音效和动画

    • 添加背景音乐、射击音效和爆炸动画等,增强游戏体验。
  • 游戏结束条件

    • 当玩家飞机生命值耗尽或者敌机到达底部时,游戏结束,显示得分和重新开始选项。
  • 优化和扩展

    • 优化游戏性能,处理大量敌机和子弹的情况。
    • 可以扩展游戏内容,如增加不同类型的敌机、道具等。

通过这些步骤和功能,你可以逐步实现一个简单但完整的飞机大战游戏。

二、功能设计

1.1、飞机大类

1.2 构造器

public class Plane extends PlaneWarObject {
	public double speed = 10;// 速度
	public boolean left, up, right, down;
	public int blood;// 血量
	public int level;// 等级
	public int type;// 等级
	public int score = 0;// 积分

	/**
	 * 无参构造
	 */
	public Plane() {
		super();
	}

	public Plane(PlaneWarClient pwc, boolean good) {
		this.fire = false;
		this.x = (Constant.GAME_WIDTH - width) / 2;
		this.y = Constant.GAME_HEIGHT - height;
		this.img = ImageUtil.images.get("myPlane_01_01");
		this.width = img.getWidth(null);
		this.height = img.getHeight(null);
		this.pwc = pwc;
		this.good = good;
		this.blood = Constant.MYPLANE_MAX_BOOLD;
		this.level = 1;
		this.type = 1;
	}

	/**
	 * 带参构造
	 */

	public Plane(int x, int y, Image img, int width, int height) {
		super();
		this.x = x;
		this.y = y;
		this.img = img;
		this.width = width;
		this.height = height;
	}

	public Plane(int x, int y, String imageName) {
		super();
		this.x = x;
		this.y = y;
		this.img = ImageUtil.images.get(imageName);
		this.width = img.getWidth(null);
		this.height = img.getHeight(null);
	}

	public Plane(int x, int y, Image img) {
		super();
		this.x = x;
		this.y = y;
		this.img = img;
		this.width = img.getWidth(null);
		this.height = img.getHeight(null);
	}


}

1.3 内部方法

 * 是否开火
	 */
	public boolean fire;

	/**
	 * 我方飞机发子弹的方法
	 */
	public void fire() {
		// pwc.musics.add(mu);
		new MusicUtil("fire3").start();
		Missile missile = new Missile(pwc, this.x, this.y, "myPlane_missile_0" + type + "_0" + level, good);
		missile.x += (this.width - missile.width) / 2;
		missile.y -= height;
		pwc.missiles.add(missile);
	}

	boolean superFire;

	/**
	 * 超级子弹
	 */
	public void superFire() {
		if (superFireCount > 0) {
			int num = 24;
			for (int i = 1; i <= num; i++) {
				Missile missile = new Missile(pwc, this.x, this.y, "myPlane_missile_super", 6, good);
				int r = (int) (Math.sqrt(width * width + height * height) / 2);
				int theta = 360 * i / num;
				missile.setTheta(theta);
				missile.x = (int) (missile.x + (width / 2 + r * Math.sin(Math.toRadians(theta)) - missile.width / 2));
				missile.y = (int) (missile.y
						- ((r * Math.cos(Math.toRadians(theta)) - height / 2 + missile.height / 2)));
				pwc.missiles.add(missile);
			}
			superFireCount--;
		}
		superFire = false;
	}

	/**
	 * 判断是否存活
	 */
	public boolean live = true;

	@Override
	public void move() {
		if (left) {
			x -= speed;
		}
		if (right) {
			x += speed;
		}
		if (up) {
			y -= speed;
		}
		if (down) {
			y += speed;
		}
		outOfBounds();
		if (fire)
			fire();
		if (superFire)
			superFire();
	}

	@Override
	public void draw(Graphics g) {
		img = ImageUtil.images.get("myPlane_0" + type + "_0" + level);
		if (blood <= 0 && live) {
			live = false;
			Explode ex = new Explode(pwc, x, y);
			ex.x += (width - ex.width) / 2;
			ex.y += (height - ex.height) / 2;
			pwc.explodes.add(ex);
			pwc.enemyPlanes.clear();
			pwc.missiles.clear();
			pwc.items.clear();

		}

		if (live) {
			g.drawImage(img, x, y, null);
			move();
		}
		drawBloodAndScore(g);
	}

	/**
	 * 画血条和积分
	 * 
	 * @param g
	 */
	private void drawBloodAndScore(Graphics g) {
		Image bloodImg = ImageUtil.images.get("myBlood");
		Image blood_blank = ImageUtil.images.get("myBlood_blank");
		Image scoreImg = ImageUtil.images.get("score");
		int i = 0;
		g.drawImage(bloodImg, 10, 40, null);
		int num = (int) (((double) ((bloodImg.getWidth(null)) - 56) / (Constant.MYPLANE_MAX_BOOLD))
				* (Constant.MYPLANE_MAX_BOOLD - blood) / blood_blank.getWidth(null));
		for (int j = 0; j < num; j++) {
			g.drawImage(blood_blank, 10 + bloodImg.getWidth(null) - blood_blank.getWidth(null) * (j + 1), 40 + 14,
					null);
		}
		// 画积分
		g.drawImage(ImageUtil.images.get("score"), 10, 40 + bloodImg.getHeight(null) + 12, null);
		g.setFont(new Font("微软雅黑", Font.BOLD, 40));
		g.setColor(Color.WHITE);
		g.drawString(score + "", 10 + scoreImg.getWidth(null) + 10, 40 + bloodImg.getHeight(null) + 50);
	}

	/**
	 * 大招剩余次数
	 */
	public int superFireCount = 0;

	/**
	 * 按下键盘的方法
	 * 
	 * @param e
	 */
	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_A:
			left = true;
			break;
		case KeyEvent.VK_S:
			down = true;
			break;
		case KeyEvent.VK_D:
			right = true;
			break;
		case KeyEvent.VK_W:
			up = true;
			break;
		case KeyEvent.VK_J:// 发子弹
			superFire = false;
			fire = true;
			break;
		case KeyEvent.VK_SPACE:// 发超级子弹
			fire = false;
			superFire = true;
			break;
		}
	}

	/**
	 * 松开键盘的方法
	 * 
	 * @param e
	 *            键盘事件
	 */
	public void keyReleased(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_A:
			left = false;
			break;
		case KeyEvent.VK_S:
			down = false;
			break;
		case KeyEvent.VK_D:
			right = false;
			break;
		case KeyEvent.VK_W:
			up = false;
			break;
		case KeyEvent.VK_J:// 发子弹
			fire = false;
			break;
		}
	}

2、敌人出场

创建敌人对象过程中是随机的,有可能是小敌机、大敌机、也有可能是小道具;
工厂方法都是生产对象的;

若方法操作仅仅与参数相关而与对象无关时用静态方法,方法分为工具方法和工厂方法,工厂方法返回值类型为对象。

3、子弹击打方法接口

public class Missile extends PlaneWarObject {
	boolean live;
	int speed;
	int type;
	public Missile() {
		super();
	}

	public Missile(PlaneWarClient pwc, int x, int y, String imageName,boolean good) {
		this.live = true;
		this.x = x;
		this.y = y;
		this.img = ImageUtil.images.get(imageName);
		this.width = img.getWidth(null);
		this.height = img.getWidth(null);
		this.pwc = pwc;
		this.speed=10;
		this.good=good;
	}
	public Missile(PlaneWarClient pwc, int x, int y, String imageName,int type,boolean good) {
		this(pwc, x, y, imageName,good);
		this.type=type;
	}


	public void setTheta(int theta) {
		this.theta = theta;
	}

	private int theta;
	/**
	 * 子弹击打飞机的方法
	 */
	public boolean hitPlane(Plane p){
		if(this.getRectangle().intersects(p.getRectangle())&&this.good!=p.isGood()&&p.live){
			this.live=false;
			if(p.level>=1){
				p.blood-= 10*p.level;
			}else{
				p.blood-= 20;
			}
			pwc.missiles.remove(this);
			return true;
		}else{
			return false;
		}
	}
	/**
	 * 子弹击打飞机的方法
	 */
	public boolean hitPlanes(List<EnemyPlane> enemyPlanes){
		for (EnemyPlane enemyPlane : enemyPlanes) {
			if(this.hitPlane(enemyPlane)){
				return true;
			}
		}
		return false;
	}
	

	/**
	 * 子弹出界
	 */
	private void outOfBounds() {
		if ((x >= (Constant.GAME_WIDTH-width) || x <= 0) || (y >= (Constant.GAME_HEIGHT - height) || y <= 0)) {
			this.live = false;
			this.pwc.missiles.remove(this);
		}
	}

}

4、子弹类型

@Override
	public void move() {
		switch (type) {
		case 100:// 水平平移
			if (x >= (Constant.GAME_WIDTH) || x <= 0 - width) {
				speed = -speed;
			}
			x += speed;
			break;
		case 1:// 水平平移
			x += speed * 3;
			if (x >= (Constant.GAME_WIDTH - width)) {
				speed = -speed;
			}
			break;
		case 2:// 竖直平移
			y += speed * 3;
			break;
		case 3:// 正弦线
			x = (int) (center.x - width + (center.x - width) * Math.sin(theta));
			theta += speed / 10;
			y += speed * 10;
			break;
		case 4:// 余弦线
			x = (int) (center.x - width + (center.x - width) * Math.cos(theta));
			theta += speed / 10;
			y += speed * 10;
			break;
		case 5:// 双曲线
			x = (int) (center.x - width + 50 * 1 / Math.cos(theta));
			y = (int) (center.y - height + 50 * Math.sin(theta) / Math.cos(theta));
			theta += speed / 20;
			break;
		case 6:// 星形线
			x = (int) (center.x - width / 2 + 200 * Math.pow(Math.cos(theta), 3));
			y = (int) (center.y + 200 * Math.pow(Math.sin(theta), 3)) - 200;
			theta += speed / 20;
			break;
		case 7:// 心形线
			x = (int) (center.x + r * (2 * Math.cos(theta + Math.PI / 2) + Math.cos(2 * theta + Math.PI / 2)));
			y = (int) (center.y + r * (2 * Math.sin(theta + Math.PI / 2) + Math.sin(2 * theta + Math.PI / 2)));
			theta += speed;
			break;
		}
		if (type!=100&&random.nextInt(1000) > 995 && live) {
			fire();
		}
		if(type==100&&random.nextInt(1000)>990&&live){
			fire();
		}
	}

三、效果展示

1、游戏

2、拾取道具

3、游戏结束

四、资源获取

经典项目java实现飞机大战射击游戏资源-CSDN文库

标签:Java,img,int,大战,width,小游戏,theta,public,Math
From: https://blog.csdn.net/m0_46013789/article/details/136824830

相关文章

  • Spring Boot 获取 bean 的 3 种方式!还有谁不会?,Java面试官
    @AutowiredprivatestaticAutoMethodDemoServicestaticAutoMethodDemoService;@PostConstructpublicvoidinit(){staticAutoMethodDemoService=autoMethodDemoService;}publicstaticStringgetAuthorizer(){returnstaticAutoMethodDemoService.test();}}......
  • JavaScript代码安全性提升:选择和使用JS混淆工具的指南
    引言在Web开发中,JavaScript是一种常用的脚本语言,然而,由于其代码容易被他人轻易获取和修改,为了保护JavaScript代码的安全性和版权,我们需要使用JS混淆工具。本文将介绍什么是JS混淆工具、为什么要使用以及如何选择合适的JS混淆工具,同时还会列举一些常用的JS混淆工具。 正文什......
  • 五款常用在线JavaScript加密混淆工具详解:jscrambler、JShaman、jsfack、ipaguard和jje
    摘要本篇技术博客将介绍五款常用且好用的在线JavaScript加密混淆工具,包括jscrambler、JShaman、jsfack、freejsobfuscator和jjencode。通过对这些工具的功能及使用方法进行详细解析,帮助开发人员更好地保护和加密其JavaScript代码,提升网站的安全性和保密性。 引言在当今......
  • 代码随想录算法训练营第二十四天(回溯1)|77. 组合(JAVA)
    文章目录回溯理论基础概念类型回溯模板77.组合解题思路源码回溯理论基础概念回溯是递归的副产品,本质上是一种穷举回溯解决的问题可以抽象为一种树形结构类型回溯主要用来解决以下问题组合问题:N个数里面按一定规则找出k个数的集合切割问题:一个字符串按一定......
  • 代码随想录算法训练营第二十三天(二叉树9)|669. 修剪二叉搜索树、108. 将有序数组转换为
    文章目录669.修剪二叉搜索树解题思路源码108.将有序数组转换为二叉搜索树解题思路源码538.把二叉搜索树转换为累加树解题思路源码669.修剪二叉搜索树给你二叉搜索树的根节点root,同时给定最小边界low和最大边界high。通过修剪二叉搜索树,使得所有节点的值......
  • JavaScript new一个对象的详细过程
    JavaScriptnew一个对象的详细过程new实现过程new实现原理new手写实现实现过程/原理开辟一块内存,创建一个空对象执行构造函数对这个空对象进行构造给空对象添加__proto__属性调用函数改变this指向最后返回this指向的新对象(如果是引用类型则返回引用类型......
  • Java 的数组详解
    数组的定义数组是相同类型数据的有序集合数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标(编号、标记)来访问它,下标是从0开始的,如果是存10个数组,那么下标是从0~9的代码举例publ......
  • java的ArrayList类
    ArrayList<E>E是自定义数据类型ArrayList类:构造函数: 成员方法: public boolean add(E e):将指定元素加到集合末尾Appendsthespecifiedelementtotheendofthislist.publicclassArray{publicstaticvoidmain(String[]args){ArrayLista......
  • 2.java openCV4.x 入门-hello OpenCV
    专栏简介......
  • java postgres单体库迁移postgres集群库java
    packagecom.slsl.digital.twin.manage.controller.project;importcom.google.common.collect.Lists;importcom.slsl.digital.twin.common.utils.CollectionUtils;importjava.sql.*;importjava.util.*;importjava.util.stream.Collectors;publicclassTest{......