这里写目录标题
- TankBigWarGame
- 介绍
- 界面展示
- 项目架构
- 安装教程
- 游戏说明
- 项目涉及技术功能
- 游戏结束判断
- 项目不足与优化空间
- 相关代码展示
- 主方法Main
- 绘图界面 MyPanelForGame
- Tank父类
- 敌方坦克 EnemyTank
- 玩家坦克 PlayerTank
- 音乐播放 AePlayWave
- 韩老师写的代码
- 坦克爆炸Boom
- 游戏结束 EndGame
- 敌方坦克坐标 Node
- 右侧游戏数据 Record
- 射击 Shot
TankBigWarGame
介绍
TankBigWar,坦克大战,跟着韩顺平老师的30天Java基础课程一点一点自己敲的,完成后很有成就感
项目源码放到了码云上,需要的可以自取
坦克大战项目
界面展示
整体展示了设计布局
右侧玩家信息栏,如下图所示:
项目架构
软件架构说明:简单用JFrame组件绘制的坦克和界面,对于多线程、面向对象编程、JFrame的使用有很好的帮助,是初学者不错的练手项目。
安装教程
- 下载后只需要执行Main方法即可
- 声音和txt文件统一放到src目录底下,用的是相对路径编写的代码,所以不用担心运行不了
- 启动Main方法后,要在控制台选择是新游戏还是读档,键盘输入1:新游戏;键盘输入2:读档
游戏说明
- 右侧是击毁敌方坦克数量、玩家坦克剩余数量
- 进入游戏后,一般输入法会切换成中文,要默认切换一下再进行操作
- 键盘方向键控制坦克方向,空格键射击。
- 进入游戏后按数字键1可以召唤敌方坦克
- 进入游戏后,如果我方坦克被敌方摧毁,可以按数字键2原地复活
- 进入游戏后有BGM背景音乐、我方发射子弹有音效、我方或者敌方坦克被摧毁有爆炸音效
项目涉及技术功能
- 玩家坦克移动、开火、撞墙判定
- 敌方坦克多线程移动、开火、移动时碰撞判定和转向
- 背景音乐
- 游戏进度存档
- 玩家击毁后原地复活
- 召唤敌方坦克
- 显示玩家坦克剩余生命,显示击毁敌方坦克数量
- 点击叉关闭窗体后保存敌方坦克位置,后续读档的时候可以恢复敌方坦克位置
游戏结束判断
- 敌方击败我方坦克3条命,即游戏结束
项目不足与优化空间
- 游戏结束后无背景音乐
- 碰撞处理:敌方坦克在运行时,碰撞后会发生转向无误,但是如果转向的时候发生碰撞,则两辆坦克会卡住
- 可以增加游戏结束机制:比如可以增加胜利条件,击毁多少敌方坦克就可以胜利,或者增加我方的家,一旦敌方击毁我家即失败
- 在召唤敌方的基础上,做到触发定时任务,每隔一段时间召唤一定数量敌方坦克
- 增加我方坦克的碰撞处理
- 直接点叉关闭窗口的时候,保存我方坦克位置,下次读档的时候恢复我方坦克位置、敌方子弹位置、我方子弹位置
- 增加一定障碍物:墙壁、河流、绿茵等等
- 显示敌方剩余坦克数量
相关代码展示
主方法Main
package com.View;
import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Scanner;
/**
* @author wty
* @date 2022/10/21 0:07
* 主方法启动
*/
public class Main extends JFrame {
MyPanelForGame mypanel = null;
static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
new Main();
}
public Main() {
System.out.println("请输入选择:");
System.out.println("1:开始新游戏");
System.out.println("2:读取存档");
String key = scanner.nextLine();
mypanel = new MyPanelForGame(key);
// 将mypanel启动
new Thread(mypanel).start();
this.add(mypanel);
// 窗口的大小(窗口大小)
this.setSize(1300, 800);
this.addKeyListener(mypanel);
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
this.setVisible(true);
this.setTitle("Tank Big Game");
// 在JFram增加相应和关闭窗口的处理:
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent windowEvent) {
System.out.println("监听到关闭窗口");
Record.saveRecordEnemy();
Record.saveRecordPlayer();
System.exit(0);
}
});
}
}
绘图界面 MyPanelForGame
package com.View;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.util.Vector;
/**
* @author wty
* @date 2022/10/21 0:01
* 绘图区
* 为了不停的重绘子弹,必须要MyPanelForGame实现一个Runnable接口,当作线程使用
*/
public class MyPanelForGame extends JPanel implements KeyListener, Runnable {
// 定义我的坦克
PlayerTank playerTank = null;
Vector<EnemyTank> enemyTanks = new Vector<>();
int enemyTankSize = 3; // 敌人 坦克的数量
// 炸弹
Vector<Boom> booms = new Vector<>();
// 定义三张炸弹图片,用于显示爆炸效果
// 当子弹击中敌人时,就加载图片
Image image_boom1 = null;
Image image_boom2 = null;
Image image_boom3 = null;
// 我方坦克生命值
Image image_heart = null;
// 定义一个nodes存放Record中的node信息
private static Vector<Node> nodes = new Vector<>();
private String key = "";
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public Vector<EnemyTank> getEnemyTanks() {
return enemyTanks;
}
public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
this.enemyTanks = enemyTanks;
}
public MyPanelForGame(String key) {
// 先判断记录的文件是否存在
// 如果存在,就正常执行,如果不存在,提示只能开启新游戏,并把key = 1
File fileEnemy = new File(Record.getRecordFile());
File filePlayer = new File(Record.getRecordFilePlay());
if (fileEnemy.exists() && filePlayer.exists()) {
nodes = Record.getNodesandCountEnemy(); // 初始化时,将右侧敌人游戏数据读取
Record.getNodesandCountPlayer();// 初始化时,将右侧玩家游戏数据读取
} else {
System.out.println("文件不存在,只能开启新游戏!");
key = "1";
}
setKey(key); // 设置是否是新游戏
// 针对是新游戏还是读取存档
switch (key) {
case "1":
initEnemyTank(); // 新游戏
Record.setAllEnemyTankCount(0);
Record.setAllPlayerTankCount(3);
break;
case "2":
loadEnemyTank(); // 读取存档
loadPlayerTank();
break;
default:
System.out.println("您的输入有误,请重新输入");
}
// 加在这里(初始化敌人的坦克)
initPlayerTank();
// 初始化炸弹的图片
image_boom1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));
image_boom2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));
image_boom3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));
image_heart = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/heart.png"));
// 播放音乐
new AePlayWave("src\\111.wav").start();
}
// 初始化敌人的坦克
public void initEnemyTank() {
// 将MyPanelForGame的VectorenemyTanks赋值给Record的enemyTanks
Record.setEnemyTanks(enemyTanks);
// 初始化敌人的坦克
for (int i = 0; i < enemyTankSize; i++) {
// 每创建一个敌人坦克,就设定速度和方向
EnemyTank enemyTank = new EnemyTank(200 * (i + 1), 0);
enemyTank.setSpeed(4);
enemyTank.setDirection(2);
// 给敌人坦克增加子弹初始位置
Shot shot = new Shot(enemyTank.getX() + 37, enemyTank.getY() + 70, enemyTank.getDirection());
// 并且把子弹加入EnemyTank的enemy_Shoots管理
enemyTank.getEnemy_Shoots().add(shot);
// 将enemyTank集合设置给setEnemyTanks
enemyTank.setEnemyTanks(enemyTanks);
// 启动shot对象
new Thread(shot).start();
enemyTanks.add(enemyTank);
// 启动敌人坦克自动移动的线程
new Thread(enemyTank).start();
}
}
// 读取存档敌人的坦克
public void loadEnemyTank() {
// 将MyPanelForGame的VectorenemyTanks赋值给Record的enemyTanks
Record.setEnemyTanks(enemyTanks);
// 初始化敌人的坦克
for (int i = 0; i < nodes.size(); i++) {
Node node = nodes.get(i);
// 每创建一个敌人坦克,就设定速度和方向
EnemyTank enemyTank = new EnemyTank(node.getX(), node.getY());
enemyTank.setSpeed(4);
enemyTank.setDirection(node.getDirection());
// 给敌人坦克增加子弹初始位置
Shot shot = new Shot(enemyTank.getX() + 37, enemyTank.getY() + 70, enemyTank.getDirection());
// 并且把子弹加入EnemyTank的enemy_Shoots管理
enemyTank.getEnemy_Shoots().add(shot);
// 将enemyTank集合设置给setEnemyTanks
enemyTank.setEnemyTanks(enemyTanks);
// 启动shot对象
new Thread(shot).start();
enemyTanks.add(enemyTank);
// 启动敌人坦克自动移动的线程
new Thread(enemyTank).start();
}
}
public void initPlayerTank() {
// 初始化玩家坦克
playerTank = new PlayerTank(300, 400);
//playerTank = new PlayerTank(30, 40);
// 设置速度
playerTank.setSpeed(4);
playerTank.setDirection(0);
// 存储玩家坐标
Record.setX_player(playerTank.getX());
Record.setY_player(playerTank.getY());
Record.setDirection_player(playerTank.getDirection());
}
// 读取存档中玩家坦克的信息
public void loadPlayerTank() {
// 初始化玩家坦克
playerTank = new PlayerTank(Record.getX_player(), Record.getY_player());
//playerTank = new PlayerTank(30, 40);
// 设置速度
playerTank.setSpeed(4);
playerTank.setDirection(Record.getDirection_player());
}
// 展示玩家信息
public void showGameInfo(Graphics graphics) {
graphics.setColor(Color.BLACK);
Font font = new Font("宋体", Font.BOLD, 25);
graphics.setFont(font);
graphics.drawString("您累积击毁坦克", 1020, 30);
// 击毁敌方坦克
drawTank(1020, 60, graphics, 0, 0); // 方向朝上,己方坦克
graphics.setColor(Color.BLACK);
graphics.drawString(Record.getAllEnemyTankCount() + " ", 1170, 100);
// 我方坦克生命
graphics.drawImage(image_heart, 1020, 200, 84, 84, this);
graphics.setColor(Color.BLACK);
graphics.drawString("X " + Record.getAllPlayerTankCount() + " ", 1170, 250);
// 游戏提示
graphics.setColor(Color.BLACK);
Font font2 = new Font("黑体", Font.PLAIN, 23);
graphics.setFont(font2);
graphics.drawString("操作指引:", 1020, 400);
graphics.drawString("方向键控制方向", 1020, 450);
graphics.drawString("空格开火", 1020, 500);
graphics.drawString("数字键1增加敌方坦克", 1020, 550);
graphics.drawString("数字键2初始我方坦克", 1020, 600);
}
@Override
public void paint(Graphics graphics) {
super.paint(graphics);
// 背景(黑色的) 游戏场景
graphics.fillRect(0, 0, 1000, 750);
// 右侧玩家信息栏
showGameInfo(graphics);
// 玩家坦克
if (playerTank.isLive() && playerTank != null) {
drawTank(playerTank.getX(), playerTank.getY(), graphics, playerTank.getDirection(), 0);
}
//drawTank(playerTank.getX() + 100, playerTank.getY(), graphics, 1, 0);
//drawTank(playerTank.getX() + 100, playerTank.getY() + 100, graphics, 2, 0);
//drawTank(playerTank.getX(), playerTank.getY() + 100, graphics, 3, 0);
// 绘制敌人坦克
for (int i = 0; i < enemyTanks.size(); i++) {
// enemyTank是Vector里面存储的是EnemyTank对象
EnemyTank enemyTank = enemyTanks.get(i);
// 判断当前坦克是否存活,存活才能画
if (enemyTank.isLive() == true) {
drawTank(enemyTank.getX(), enemyTank.getY(), graphics, enemyTank.getDirection(), 1);
// 敌人坦克的子弹
for (int j = 0; j < enemyTank.getEnemy_Shoots().size(); j++) {
Shot shot = enemyTank.getEnemy_Shoots().get(j);
if (shot != null && false != shot.isLive()) {
System.out.println("敌人子弹被绘制");
graphics.setColor(new Color(210, 180, 140));
graphics.fill3DRect(shot.getX(), shot.getY(), 6, 6, false);
} else {
enemyTank.getEnemy_Shoots().remove(shot); // 移除子弹
}
}
} else {
enemyTanks.remove(enemyTank);
}
}
//drawTank(playerTank.getX() - 100, playerTank.getY() - 300, graphics, 2, 1);
//drawTank(playerTank.getX(), playerTank.getY() - 300, graphics, 2, 1);
//drawTank(playerTank.getX(), playerTank.getY() + 200, graphics, 3, 1);
// 绘制子弹
// 子弹在边界内且仍然存活,就绘制子弹
if (playerTank.getShot() != null && false != playerTank.getShot().isLive()) {
System.out.println("子弹被绘制");
graphics.setColor(new Color(135, 206, 250));
graphics.fill3DRect(playerTank.getShot().getX(), playerTank.getShot().getY(), 6, 6, false);
// if (playerTank.getDirection() == 0 || playerTank.getDirection() == 2){
// graphics.fill3DRect(playerTank.getShot().getX(),playerTank.getShot().getY(),6,13,false);
// }else if(playerTank.getDirection() == 1 || playerTank.getDirection() == 3){
// graphics.fill3DRect(playerTank.getShot().getX(),playerTank.getShot().getY(),13,6,false);
// }
}
// 我方坦克发射多枚子弹
if (playerTank.getManyShoots().size() > 0) {
for (int i = 0; i < playerTank.getManyShoots().size(); i++) {
Shot shot = playerTank.getManyShoots().get(i);
if (shot != null && false != shot.isLive()) {
// 这里指的是每一个集合中的坦克对象发射子弹的位置,比较关键,容易写错
graphics.fill3DRect(shot.getX(), shot.getY(), 6, 6, false);
} else {
// 子弹碰壁或者已经消亡,就从集合里去掉
playerTank.getManyShoots().remove(shot);
}
}
}
// 休眠一下确保炸弹爆炸
try {
Thread.sleep(70);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 绘制爆炸,如果Vector集合中有元素,那么就画炸弹
for (int i = 0; i < booms.size(); i++) {
// 取出炸弹
Boom boom = booms.get(i);
// 根据当前bomb对象的life数,画出对应图片
if (boom.getLife() > 6) {
System.out.println("触发爆炸动画3");
graphics.drawImage(image_boom1, boom.getX(), boom.getY(), 80, 80, this);
} else if (boom.getLife() > 3) {
System.out.println("触发爆炸动画2");
graphics.drawImage(image_boom2, boom.getX(), boom.getY(), 80, 80, this);
} else {
System.out.println("触发爆炸动画1");
graphics.drawImage(image_boom3, boom.getX(), boom.getY(), 80, 80, this);
}
boom.lifeKill();
// 如果生命值为0,那么就从集合中移除
if (boom.getLife() == 0) {
booms.remove(boom);
}
}
}
/**
* 绘制坦克
*
* @param x 横坐标
* @param y 纵坐标
* @param graphics 画笔
* @param direction 方向
* @param type 坦克类型(玩家、敌人)
*/
public void drawTank(int x, int y, Graphics graphics, int direction, int type) {
// 绘制坦克
// 绘制对应的形状
switch (direction) {
case 0: // 向上方向
if (0 == type) { // 玩家坦克
drawPlayerTankUp(x, y, graphics, direction);
} else { // 敌方坦克
drawEnemyTankUp(x, y, graphics, direction);
}
break;
case 1: // 向右的方向
if (0 == type) {// 玩家坦克
drawPlayerTankRight(x, y, graphics, direction);
} else { // 敌方坦克
drawEnemyTankRight(x, y, graphics, direction);
}
break;
case 2: // 向下的方向
if (0 == type) {// 玩家坦克
drawPlayerTankDown(x, y, graphics, direction);
} else { // 敌方坦克
drawEnemyTankDown(x, y, graphics, direction);
}
break;
case 3:// 向左的方向
if (0 == type) {// 玩家坦克
drawPlayerTankLeft(x, y, graphics, direction);
} else { // 敌方坦克
drawEnemyTankLeft(x, y, graphics, direction);
}
break;
default:
System.out.println("其他情况暂时不处理");
}
}
/**
* 自己坦克的颜色--朝上
*
* @param x
* @param y
* @param graphics
* @param direction
*/
public void drawPlayerTankUp(int x, int y, Graphics graphics, int direction) {
// 左边履带
graphics.setColor(new Color(173, 216, 230));
graphics.fill3DRect(x, y, 20, 80, false);
//graphics.fillRect(30, 40, 20, 80);
graphics.fillOval(x - 5, y, 10, 20);
graphics.fillOval(x - 5, y + 20, 10, 20);
graphics.fillOval(x - 5, y + 40, 10, 20);
graphics.fillOval(x - 5, y + 60, 10, 20);
// 左边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x, y + 20, x + 10, y + 20);
graphics.drawLine(x, y + 40, x + 10, y + 40);
graphics.drawLine(x, y + 60, x + 10, y + 60);
// 中间驾驶舱
graphics.setColor(new Color(135, 206, 250));
graphics.fillRect(x + 20, y + 20, 40, 40);
// 炮膛
graphics.setColor(new Color(70, 130, 180));
graphics.drawLine(x + 40, y, x + 40, y + 30);
// 炮膛前面一个圆
graphics.setColor(new Color(95, 158, 160));
graphics.fillOval(x + 37, y - 10, 6, 13);
// 圆形盖子
graphics.setColor(new Color(95, 158, 160));
graphics.fillOval(x + 30, y + 30, 20, 20);
// 右边履带
graphics.setColor(new Color(173, 216, 230));
graphics.fill3DRect(x + 60, y, 20, 80, false);
graphics.fillOval(x + 75, y, 10, 20);
graphics.fillOval(x + 75, y + 20, 10, 20);
graphics.fillOval(x + 75, y + 40, 10, 20);
graphics.fillOval(x + 75, y + 60, 10, 20);
// 右边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 70, y + 20, x + 80, y + 20);
graphics.drawLine(x + 70, y + 40, x + 80, y + 40);
graphics.drawLine(x + 70, y + 60, x + 80, y + 60);
}
/**
* 自己坦克的颜色--朝右
*
* @param x
* @param y
* @param graphics
* @param direction
*/
public void drawPlayerTankRight(int x, int y, Graphics graphics, int direction) {
// 左边履带
graphics.setColor(new Color(173, 216, 230));
graphics.fill3DRect(x, y, 80, 20, false);
//graphics.fillRect(30, 40, 20, 80);
graphics.fillOval(x, y - 5, 20, 10);
graphics.fillOval(x + 20, y - 5, 20, 10);
graphics.fillOval(x + 40, y - 5, 20, 10);
graphics.fillOval(x + 60, y - 5, 20, 10);
// 左边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 20, y, x + 20, y + 10);
graphics.drawLine(x + 40, y, x + 40, y + 10);
graphics.drawLine(x + 60, y, x + 60, y + 10);
// 中间驾驶舱
graphics.setColor(new Color(135, 206, 250));
graphics.fillRect(x + 20, y + 20, 40, 40);
// 炮膛
graphics.setColor(new Color(70, 130, 180));
graphics.drawLine(x + 50, y + 40, x + 80, y + 40);
// 炮膛前面一个圆
graphics.setColor(new Color(95, 158, 160));
graphics.fillOval(x + 80, y + 37, 13, 6);
// 圆形盖子
graphics.setColor(new Color(95, 158, 160));
graphics.fillOval(x + 30, y + 30, 20, 20);
// 右边履带
graphics.setColor(new Color(173, 216, 230));
graphics.fill3DRect(x, y + 60, 80, 20, false);
graphics.fillOval(x, y + 75, 20, 10);
graphics.fillOval(x + 20, y + 75, 20, 10);
graphics.fillOval(x + 40, y + 75, 20, 10);
graphics.fillOval(x + 60, y + 75, 20, 10);
// 右边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 20, y + 80, x + 20, y + 70);
graphics.drawLine(x + 40, y + 80, x + 40, y + 70);
graphics.drawLine(x + 60, y + 80, x + 60, y + 70);
}
/**
* 自己坦克的颜色--向下
*
* @param x
* @param y
* @param graphics
* @param direction
*/
public void drawPlayerTankDown(int x, int y, Graphics graphics, int direction) {
// 左边履带
graphics.setColor(new Color(173, 216, 230));
graphics.fill3DRect(x, y, 20, 80, false);
//graphics.fillRect(30, 40, 20, 80);
graphics.fillOval(x - 5, y, 10, 20);
graphics.fillOval(x - 5, y + 20, 10, 20);
graphics.fillOval(x - 5, y + 40, 10, 20);
graphics.fillOval(x - 5, y + 60, 10, 20);
// 左边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x, y + 20, x + 10, y + 20);
graphics.drawLine(x, y + 40, x + 10, y + 40);
graphics.drawLine(x, y + 60, x + 10, y + 60);
// 中间驾驶舱
graphics.setColor(new Color(135, 206, 250));
graphics.fillRect(x + 20, y + 20, 40, 40);
// 炮膛
graphics.setColor(new Color(70, 130, 180));
graphics.drawLine(x + 40, y + 30, x + 40, y + 60);
// 炮膛前面一个圆
graphics.setColor(new Color(95, 158, 160));
graphics.fillOval(x + 37, y + 70, 6, 13);
// 圆形盖子
graphics.setColor(new Color(95, 158, 160));
graphics.fillOval(x + 30, y + 30, 20, 20);
// 右边履带
graphics.setColor(new Color(173, 216, 230));
graphics.fill3DRect(x + 60, y, 20, 80, false);
graphics.fillOval(x + 75, y, 10, 20);
graphics.fillOval(x + 75, y + 20, 10, 20);
graphics.fillOval(x + 75, y + 40, 10, 20);
graphics.fillOval(x + 75, y + 60, 10, 20);
// 右边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 70, y + 20, x + 80, y + 20);
graphics.drawLine(x + 70, y + 40, x + 80, y + 40);
graphics.drawLine(x + 70, y + 60, x + 80, y + 60);
}
/**
* 自己坦克的颜色--朝左
*
* @param x
* @param y
* @param graphics
* @param direction
*/
public void drawPlayerTankLeft(int x, int y, Graphics graphics, int direction) {
// 左边履带
graphics.setColor(new Color(173, 216, 230));
graphics.fill3DRect(x, y, 80, 20, false);
//graphics.fillRect(30, 40, 20, 80);
graphics.fillOval(x, y - 5, 20, 10);
graphics.fillOval(x + 20, y - 5, 20, 10);
graphics.fillOval(x + 40, y - 5, 20, 10);
graphics.fillOval(x + 60, y - 5, 20, 10);
// 左边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 20, y, x + 20, y + 10);
graphics.drawLine(x + 40, y, x + 40, y + 10);
graphics.drawLine(x + 60, y, x + 60, y + 10);
// 中间驾驶舱
graphics.setColor(new Color(135, 206, 250));
graphics.fillRect(x + 20, y + 20, 40, 40);
// 炮膛
graphics.setColor(new Color(70, 130, 180));
graphics.drawLine(x + 30, y + 40, x, y + 40);
// 炮膛前面一个圆
graphics.setColor(new Color(95, 158, 160));
graphics.fillOval(x - 10, y + 37, 13, 6);
// 圆形盖子
graphics.setColor(new Color(95, 158, 160));
graphics.fillOval(x + 30, y + 30, 20, 20);
// 右边履带
graphics.setColor(new Color(173, 216, 230));
graphics.fill3DRect(x, y + 60, 80, 20, false);
graphics.fillOval(x, y + 75, 20, 10);
graphics.fillOval(x + 20, y + 75, 20, 10);
graphics.fillOval(x + 40, y + 75, 20, 10);
graphics.fillOval(x + 60, y + 75, 20, 10);
// 右边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 20, y + 80, x + 20, y + 70);
graphics.drawLine(x + 40, y + 80, x + 40, y + 70);
graphics.drawLine(x + 60, y + 80, x + 60, y + 70);
}
//--------敌人的坦克-----------//
/**
* 敌人坦克的颜色--朝上
*
* @param x
* @param y
* @param graphics
* @param direction
*/
public void drawEnemyTankUp(int x, int y, Graphics graphics, int direction) {
// 左边履带
graphics.setColor(new Color(255, 215, 0));
graphics.fill3DRect(x, y, 20, 80, false);
//graphics.fillRect(30, 40, 20, 80);
graphics.fillOval(x - 5, y, 10, 20);
graphics.fillOval(x - 5, y + 20, 10, 20);
graphics.fillOval(x - 5, y + 40, 10, 20);
graphics.fillOval(x - 5, y + 60, 10, 20);
// 左边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x, y + 20, x + 10, y + 20);
graphics.drawLine(x, y + 40, x + 10, y + 40);
graphics.drawLine(x, y + 60, x + 10, y + 60);
// 中间驾驶舱
graphics.setColor(new Color(218, 165, 32));
graphics.fillRect(x + 20, y + 20, 40, 40);
// 炮膛
graphics.setColor(new Color(210, 180, 140));
graphics.drawLine(x + 40, y, x + 40, y + 30);
// 炮膛前面一个圆
graphics.setColor(new Color(210, 180, 140));
graphics.fillOval(x + 37, y - 10, 6, 13);
// 圆形盖子
graphics.setColor(new Color(210, 180, 140));
graphics.fillOval(x + 30, y + 30, 20, 20);
// 右边履带
graphics.setColor(new Color(255, 215, 0));
graphics.fill3DRect(x + 60, y, 20, 80, false);
graphics.fillOval(x + 75, y, 10, 20);
graphics.fillOval(x + 75, y + 20, 10, 20);
graphics.fillOval(x + 75, y + 40, 10, 20);
graphics.fillOval(x + 75, y + 60, 10, 20);
// 右边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 70, y + 20, x + 80, y + 20);
graphics.drawLine(x + 70, y + 40, x + 80, y + 40);
graphics.drawLine(x + 70, y + 60, x + 80, y + 60);
}
/**
* 敌人坦克的颜色--朝右
*
* @param x
* @param y
* @param graphics
* @param direction
*/
public void drawEnemyTankRight(int x, int y, Graphics graphics, int direction) {
// 左边履带
graphics.setColor(new Color(255, 215, 0));
graphics.fill3DRect(x, y, 80, 20, false);
//graphics.fillRect(30, 40, 20, 80);
graphics.fillOval(x, y - 5, 20, 10);
graphics.fillOval(x + 20, y - 5, 20, 10);
graphics.fillOval(x + 40, y - 5, 20, 10);
graphics.fillOval(x + 60, y - 5, 20, 10);
// 左边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 20, y, x + 20, y + 10);
graphics.drawLine(x + 40, y, x + 40, y + 10);
graphics.drawLine(x + 60, y, x + 60, y + 10);
// 中间驾驶舱
graphics.setColor(new Color(218, 165, 32));
graphics.fillRect(x + 20, y + 20, 40, 40);
// 炮膛
graphics.setColor(new Color(210, 180, 140));
graphics.drawLine(x + 50, y + 40, x + 80, y + 40);
// 炮膛前面一个圆
graphics.setColor(new Color(210, 180, 140));
graphics.fillOval(x + 80, y + 37, 13, 6);
// 圆形盖子
graphics.setColor(new Color(210, 180, 140));
graphics.fillOval(x + 30, y + 30, 20, 20);
// 右边履带
graphics.setColor(new Color(255, 215, 0));
graphics.fill3DRect(x, y + 60, 80, 20, false);
graphics.fillOval(x, y + 75, 20, 10);
graphics.fillOval(x + 20, y + 75, 20, 10);
graphics.fillOval(x + 40, y + 75, 20, 10);
graphics.fillOval(x + 60, y + 75, 20, 10);
// 右边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 20, y + 80, x + 20, y + 70);
graphics.drawLine(x + 40, y + 80, x + 40, y + 70);
graphics.drawLine(x + 60, y + 80, x + 60, y + 70);
}
/**
* 敌人的坦克的颜色--向下
*
* @param x
* @param y
* @param graphics
* @param direction
*/
public void drawEnemyTankDown(int x, int y, Graphics graphics, int direction) {
// 左边履带
graphics.setColor(new Color(255, 215, 0));
graphics.fill3DRect(x, y, 20, 80, false);
//graphics.fillRect(30, 40, 20, 80);
graphics.fillOval(x - 5, y, 10, 20);
graphics.fillOval(x - 5, y + 20, 10, 20);
graphics.fillOval(x - 5, y + 40, 10, 20);
graphics.fillOval(x - 5, y + 60, 10, 20);
// 左边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x, y + 20, x + 10, y + 20);
graphics.drawLine(x, y + 40, x + 10, y + 40);
graphics.drawLine(x, y + 60, x + 10, y + 60);
// 中间驾驶舱
graphics.setColor(new Color(218, 165, 32));
graphics.fillRect(x + 20, y + 20, 40, 40);
// 炮膛
graphics.setColor(new Color(210, 180, 140));
graphics.drawLine(x + 40, y + 40, x + 40, y + 70);
// 炮膛前面一个圆
graphics.setColor(new Color(210, 180, 140));
graphics.fillOval(x + 37, y + 70, 6, 13);
// 圆形盖子
graphics.setColor(new Color(210, 180, 140));
graphics.fillOval(x + 30, y + 30, 20, 20);
// 右边履带
graphics.setColor(new Color(255, 215, 0));
graphics.fill3DRect(x + 60, y, 20, 80, false);
graphics.fillOval(x + 75, y, 10, 20);
graphics.fillOval(x + 75, y + 20, 10, 20);
graphics.fillOval(x + 75, y + 40, 10, 20);
graphics.fillOval(x + 75, y + 60, 10, 20);
// 右边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 70, y + 20, x + 80, y + 20);
graphics.drawLine(x + 70, y + 40, x + 80, y + 40);
graphics.drawLine(x + 70, y + 60, x + 80, y + 60);
}
/**
* 敌人坦克的颜色--朝左
*
* @param x
* @param y
* @param graphics
* @param direction
*/
public void drawEnemyTankLeft(int x, int y, Graphics graphics, int direction) {
// 左边履带
graphics.setColor(new Color(255, 215, 0));
graphics.fill3DRect(x, y, 80, 20, false);
//graphics.fillRect(30, 40, 20, 80);
graphics.fillOval(x, y - 5, 20, 10);
graphics.fillOval(x + 20, y - 5, 20, 10);
graphics.fillOval(x + 40, y - 5, 20, 10);
graphics.fillOval(x + 60, y - 5, 20, 10);
// 左边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 20, y, x + 20, y + 10);
graphics.drawLine(x + 40, y, x + 40, y + 10);
graphics.drawLine(x + 60, y, x + 60, y + 10);
// 中间驾驶舱
graphics.setColor(new Color(218, 165, 32));
graphics.fillRect(x + 20, y + 20, 40, 40);
// 炮膛
graphics.setColor(new Color(210, 180, 140));
graphics.drawLine(x + 30, y + 40, x, y + 40);
// 炮膛前面一个圆
graphics.setColor(new Color(210, 180, 140));
graphics.fillOval(x - 10, y + 37, 13, 6);
// 圆形盖子
graphics.setColor(new Color(210, 180, 140));
graphics.fillOval(x + 30, y + 30, 20, 20);
// 右边履带
graphics.setColor(new Color(255, 215, 0));
graphics.fill3DRect(x, y + 60, 80, 20, false);
graphics.fillOval(x, y + 75, 20, 10);
graphics.fillOval(x + 20, y + 75, 20, 10);
graphics.fillOval(x + 40, y + 75, 20, 10);
graphics.fillOval(x + 60, y + 75, 20, 10);
// 右边履带条纹
graphics.setColor(new Color(0, 0, 0));
graphics.drawLine(x + 20, y + 80, x + 20, y + 70);
graphics.drawLine(x + 40, y + 80, x + 40, y + 70);
graphics.drawLine(x + 60, y + 80, x + 60, y + 70);
}
// 出现问题:只有1颗子弹打到敌人的坦克,解决方案如下:
// 如果我们的坦克可以发射多发子弹
// 再判断我方子弹是否击中敌人坦克时,就需要把我们的子弹集合中所有的子弹
// 都取出来和敌人的所有坦克遍历
public void hitEnemyAllTank() {
// 遍历我们的子弹集合
for (int i = 0; i < playerTank.getManyShoots().size(); i++) {
// 拿出集合中的一颗子弹
Shot shot = playerTank.getManyShoots().get(i);
// 判断这一颗子弹是否击中敌人坦克
if (shot != null && shot.isLive()) {
// 遍历敌人所有的坦克是否别击中
for (int j = 0; j < enemyTanks.size(); j++) {
EnemyTank enemyTank = enemyTanks.get(j);
// 调用判断方法
hitTank(shot, enemyTank);
if (enemyTank.isLive() == false) {
enemyTanks.remove(enemyTank);
Record.addTankCout(); // 击毁敌方坦克后就给击毁数量+1
new AePlayWave("src\\Explosion_03.wav").start();
}
}
}
}
}
// 编写方法判断我方的子弹是否击中敌人的坦克
// 什么时候判断,-->run方法比较好
@SuppressWarnings({"all"})
public void hitTank(Shot shot, Tank tank) {
// 判断子弹击中坦克
switch (tank.getDirection()) {
case 0: // 坦克向上 被击中
case 2: // 坦克向下 被击中
if (shot.getX() > tank.getX()
&& shot.getX() < tank.getX() + 80
&& shot.getY() > tank.getY()
&& shot.getY() < tank.getY() + 80) {
shot.setLive(false);
tank.setLive(false);
// 创建Boom对象加入到booms集合中
Boom boom = new Boom(tank.getX(), tank.getY());
booms.add(boom);
}
break;
case 1:
case 3:
if (shot.getX() > tank.getX()
&& shot.getX() < tank.getX() + 80
&& shot.getY() > tank.getY()
&& shot.getY() < tank.getY() + 80) {
shot.setLive(false);
tank.setLive(false);
// 创建Boom对象加入到booms集合中
Boom boom = new Boom(tank.getX(), tank.getY());
booms.add(boom);
}
break;
}
}
// 敌人坦克击爆我方坦克
public void hitPlayerTank() {
// 遍历敌人的所有坦克
for (int i = 0; i < enemyTanks.size(); i++) {
// 取出敌人坦克
EnemyTank enemyTank = enemyTanks.get(i);
// 遍历enemyTank对象的所有子弹
for (int j = 0; j < enemyTank.getEnemy_Shoots().size(); j++) {
// 取出子弹
Shot shot = enemyTank.getEnemy_Shoots().get(j);
// 判断子弹是否击中我方坦克
if (playerTank.isLive() && null != shot && shot.isLive()) {
hitTank(shot, playerTank);
if (playerTank.isLive() == false) {
new AePlayWave("src\\Explosion_03.wav").start();
Record.setX_player(playerTank.getX());
Record.setY_player(playerTank.getY());
Record.setDirection_player(playerTank.getDirection());
Record.saveRecordPlayer();
Record.minusPlayerTankCout();
}
}
}
}
}
@Override
public void keyTyped(KeyEvent keyEvent) {
}
// 键盘按下后触发
@Override
public void keyPressed(KeyEvent e) {
if (Record.getAllPlayerTankCount() <= 0) {
return;
}
if (e.getKeyCode() == KeyEvent.VK_UP) { // 坦克向上
playerTank.setDirection(0);
if (playerTank.getY() - 10 > 0) {
playerTank.moveUp();
}
}
if (e.getKeyCode() == KeyEvent.VK_RIGHT) { // 坦克向右
playerTank.setDirection(1);
if ((int) (playerTank.getX() + 80 + 10) < 1000) {
playerTank.moveRight();
}
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) { // 坦克向下
playerTank.setDirection(2);
if ((int) (playerTank.getY() + 80 + 10) < 750) {
playerTank.moveDown();
}
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) { // 坦克向左
playerTank.setDirection(3);
if (playerTank.getX() - 10 > 0) {
playerTank.moveLeft();
}
}
if (e.getKeyCode() == KeyEvent.VK_SPACE) { // 坦克发射子弹
// 播放音乐
new AePlayWave("src\\Shoot_01.wav").start();
System.out.println("用户坦克按下空格,开始射击");
/** if (playerTank.getShot() == null){
playerTank.shotEnemy();
}
这样写的话,只能打出一颗子弹,这个示例告诉我们,
即使线程销毁了,对象是还存在的
*/
// 子弹撞墙,或者子弹打死一个坦克才能发射第二发
/**
* if (playerTank.getShot() == null || playerTank.getShot().isLive() == false){
* playerTank.shotEnemy();
}*/
// 发射多颗子弹
playerTank.shotEnemy();
}
if (e.getKeyCode() == KeyEvent.VK_1) { // 数字键1可以初始化(增加)敌人坦克
initEnemyTank();
}
if (e.getKeyCode() == KeyEvent.VK_2) { // 数字键2可以初始化(增加)玩家坦克
if (playerTank.isLive() == false) {
loadPlayerTank();
new AePlayWave("src\\Menu_Navigate_02.wav").start();
} else {
System.out.println("只有死亡时,才能初始化玩家坦克");
}
}
// 让面板重新画一次
this.repaint();
}
@Override
public void keyReleased(KeyEvent keyEvent) {
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 是否击中敌人的坦克
hitEnemyAllTank();
// 是否击中玩家坦克
hitPlayerTank();
this.repaint();
}
}
}
Tank父类
package com.View;
/**
* @author wty
* @date 2022/10/20 23:57
* 用于存放坦克模型
*/
public class Tank {
private int x; // 坦克的横坐标
private int y; // 坦克的纵坐标
private int direction; // 坦克的方向 0上,1右,2下,3左
private int speed;
private boolean isLive = true;
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
public Tank(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public int getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
// 坦克移动
public void moveUp() {
y -= speed;
}
public void moveRight() {
x += speed;
}
public void moveDown() {
y += speed;
}
public void moveLeft() {
x -= speed;
}
}
敌方坦克 EnemyTank
package com.View;
import java.util.Vector;
/**
* @author wty
* @date 2022/10/21 15:23
* <p>
* 敌人的坦克
*/
public class EnemyTank extends Tank implements Runnable {
// 使用Vector保存多个敌人的子弹
private Vector<Shot> enemy_Shoots = new Vector<>();
private int max_Shoots = 4;
// 增加用于,EnemyTank可以得到敌人坦克的Vector成员
private Vector<EnemyTank> enemyTanks = new Vector<>();
public Vector<EnemyTank> getEnemyTanks() {
return enemyTanks;
}
public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
this.enemyTanks = enemyTanks;
}
public EnemyTank(int x, int y) {
super(x, y);
}
private boolean isLive = true;
public Vector<Shot> getEnemy_Shoots() {
return enemy_Shoots;
}
public void setEnemy_Shoots(Vector<Shot> enemy_Shoots) {
this.enemy_Shoots = enemy_Shoots;
}
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
@Override
public void run() {
while (true) {
// 给敌人的坦克绘制子弹
if (isLive == true && enemy_Shoots.size() < max_Shoots) {
Shot s = null;
// 判断坦克的方向,创建对应子弹
switch (this.getDirection()) {
case 0:
s = new Shot(this.getX() + 37, this.getY(), this.getDirection());
break;
case 1:
s = new Shot(this.getX() + 80, this.getY() + 40, this.getDirection());
break;
case 2:
s = new Shot(this.getX() + 37, this.getY() + 70, this.getDirection());
break;
case 3:
s = new Shot(this.getX() + 10, this.getY() + 37, this.getDirection());
break;
}
enemy_Shoots.add(s);
// 启动敌人开枪线程
new Thread(s).start();
} else {
// 这里清空集合有疑问,待定
enemy_Shoots.clear();
}
// 根据坦克方向调动
if (isTouchEnemyTank()) { // 如果碰撞了就直接调正方向
// random 是[0, 1)
setDirection((int) (Math.random() * 4));
} else {
adjustDirection();
// random 是[0, 1)
setDirection((int) (Math.random() * 4));
}
// 多线程要考虑什么时候结束
if (isLive == false || Record.getAllPlayerTankCount() <= 0) {
break;
}
}
}
// 坦克调整方向
public void adjustDirection() {
switch (this.getDirection()) {
case 0: // 向上
for (int i = 1; i <= 30; i++) {
// 让坦克保持一个方向走一会儿
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (this.getY() - 10 > 0 && !isTouchEnemyTank()) {
moveUp();
} else {
return;
}
}
break;
case 1: // 向右
for (int i = 1; i <= 30; i++) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
if ((int) (this.getX() + 80 + 10) < 1000 && !isTouchEnemyTank()) {
moveRight();
} else {
return;
}
}
break;
case 2: // 向下
for (int i = 1; i <= 30; i++) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
if ((int) (this.getY() + 80 + 10) < 750 && !isTouchEnemyTank()) {
moveDown();
} else {
return;
}
}
break;
case 3: // 向左
for (int i = 1; i <= 30; i++) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (this.getX() - 10 > 0 && !isTouchEnemyTank()) {
moveLeft();
} else {
return;
}
}
break;
}
}
// 编写方法,判断敌人坦克和其它敌人坦克是否碰撞 碰撞返回 true 没碰撞返回 false
public boolean isTouchEnemyTank() {
switch (this.getDirection()) {
case 0: // 当前坦克向上
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
// 取出敌人坦克,然后每一辆坦克和除了自己以外的坦克进行比较是否碰撞
if (enemyTank != this) {
// x范围 [enemyTank.getX(),enemyTank.getX() + 80]
// y范围 [enemyTank.getY() -10,enemyTank.getY() + 80]
if (enemyTank.getDirection() == 0) {// 其它敌人坦克在朝上
// 当前坦克左上角坐标 [this.getX(),this.getY() - 10]
if (this.getX() >= enemyTank.getX()
&& this.getX() <= enemyTank.getX() + 80
&& this.getY() - 10 >= enemyTank.getY() - 10
&& this.getY() - 10 <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY() - 10]
if (this.getX() + 80 >= enemyTank.getX()
&& this.getX() + 80 <= enemyTank.getX() + 80
&& this.getY() - 10 >= enemyTank.getY() - 10
&& this.getY() - 10 <= enemyTank.getY() + 80) {
return true;
}
}
// x范围 [enemyTank.getX(),enemyTank.getX() + 80]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80 + 10]
if (enemyTank.getDirection() == 2) {// 其它敌人坦克在朝下
// 当前坦克左上角坐标 [this.getX(),this.getY() - 10]
if (this.getX() >= enemyTank.getX()
&& this.getX() <= enemyTank.getX() + 80
&& this.getY() - 10 >= enemyTank.getY()
&& this.getY() - 10 <= enemyTank.getY() + 80 + 10) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY() - 10]
if (this.getX() + 80 >= enemyTank.getX()
&& this.getX() + 80 <= enemyTank.getX() + 80
&& this.getY() - 10 >= enemyTank.getY()
&& this.getY() - 10 <= enemyTank.getY() + 80 + 10) {
return true;
}
}
// x范围 [enemyTank.getX(),enemyTank.getX() + 80 + 10]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80]
if (enemyTank.getDirection() == 1) {// 其它敌人坦克在朝右
// 当前坦克左上角坐标 [this.getX(),this.getY() - 10]
if (this.getX() >= enemyTank.getX()
&& this.getX() <= enemyTank.getX() + 80 + 10
&& this.getY() - 10 >= enemyTank.getY()
&& this.getY() - 10 <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY() - 10]
if (this.getX() + 80 >= enemyTank.getX()
&& this.getX() + 80 <= enemyTank.getX() + 80 + 10
&& this.getY() - 10 >= enemyTank.getY()
&& this.getY() - 10 <= enemyTank.getY() + 80) {
return true;
}
}
// x范围 [enemyTank.getX() - 10,enemyTank.getX() + 80]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80]
if (enemyTank.getDirection() == 3) {// 其它敌人坦克在朝左
// 当前坦克左上角坐标 [this.getX(),this.getY() - 10]
if (this.getX() >= enemyTank.getX() - 10
&& this.getX() <= enemyTank.getX() + 80
&& this.getY() - 10 >= enemyTank.getY()
&& this.getY() - 10 <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY() - 10]
if (this.getX() + 80 >= enemyTank.getX() - 10
&& this.getX() + 80 <= enemyTank.getX() + 80
&& this.getY() - 10 >= enemyTank.getY()
&& this.getY() - 10 <= enemyTank.getY() + 80) {
return true;
}
}
} // enemyTank != this
}
break;
case 1: // 当前坦克向右
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
// 取出敌人坦克,然后每一辆坦克和除了自己以外的坦克进行比较是否碰撞
if (enemyTank != this) {
// x范围 [enemyTank.getX(),enemyTank.getX() + 80]
// y范围 [enemyTank.getY() -10,enemyTank.getY() + 80]
if (enemyTank.getDirection() == 0) {// 其它敌人坦克在朝上
// 当前坦克左上角坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX()
&& this.getX() <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY() - 10
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80 + 10,this.getY()]
if (this.getX() + 80 + 10 >= enemyTank.getX()
&& this.getX() + 80 + 10 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY() - 10
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
}
// x范围 [enemyTank.getX(),enemyTank.getX() + 80]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80 + 10]
if (enemyTank.getDirection() == 2) {// 其它敌人坦克在朝下
// 当前坦克左上角坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX()
&& this.getX() <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80 + 10) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80 + 10,this.getY()]
if (this.getX() + 80 + 10 >= enemyTank.getX()
&& this.getX() + 80 + 10 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80 + 10) {
return true;
}
}
// x范围 [enemyTank.getX(),enemyTank.getX() + 80 + 10]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80]
if (enemyTank.getDirection() == 1) {// 其它敌人坦克在朝右
// 当前坦克左上角坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX()
&& this.getX() <= enemyTank.getX() + 80 + 10
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80 + 10,this.getY()]
if (this.getX() + 80 + 10 >= enemyTank.getX()
&& this.getX() + 80 + 10 <= enemyTank.getX() + 80 + 10
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
}
// x范围 [enemyTank.getX() - 10,enemyTank.getX() + 80]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80]
if (enemyTank.getDirection() == 3) {// 其它敌人坦克在朝左
// 当前坦克左上角坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX() - 10
&& this.getX() <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80 + 10,this.getY()]
if (this.getX() + 80 + 10 >= enemyTank.getX() - 10
&& this.getX() + 80 + 10 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
}
}// enemyTank != this
} // for
break;
case 2: // 当前坦克向下
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
// 取出敌人坦克,然后每一辆坦克和除了自己以外的坦克进行比较是否碰撞
if (enemyTank != this) {
// x范围 [enemyTank.getX(),enemyTank.getX() + 80]
// y范围 [enemyTank.getY() -10,enemyTank.getY() + 80]
if (enemyTank.getDirection() == 0) {// 其它敌人坦克在朝上
// 当前坦克左上角坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX()
&& this.getX() <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY() - 10
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY()]
if (this.getX() + 80 >= enemyTank.getX()
&& this.getX() + 80 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY() - 10
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
}
// x范围 [enemyTank.getX(),enemyTank.getX() + 80]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80 + 10]
if (enemyTank.getDirection() == 2) {// 其它敌人坦克在朝下
// 当前坦克左上角坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX()
&& this.getX() <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80 + 10) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY()]
if (this.getX() + 80 >= enemyTank.getX()
&& this.getX() + 80 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80 + 10) {
return true;
}
}
// x范围 [enemyTank.getX(),enemyTank.getX() + 80 + 10]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80]
if (enemyTank.getDirection() == 1) {// 其它敌人坦克在朝右
// 当前坦克左上角坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX()
&& this.getX() <= enemyTank.getX() + 80 + 10
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY()]
if (this.getX() + 80 >= enemyTank.getX()
&& this.getX() + 80 <= enemyTank.getX() + 80 + 10
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
}
// x范围 [enemyTank.getX() - 10,enemyTank.getX() + 80]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80]
if (enemyTank.getDirection() == 3) {// 其它敌人坦克在朝左
// 当前坦克左上角坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX() - 10
&& this.getX() <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY()]
if (this.getX() + 80 >= enemyTank.getX() - 10
&& this.getX() + 80 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
}
} // enemyTank != this
}// for
break;
case 3: // 当前坦克向左
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
// 取出敌人坦克,然后每一辆坦克和除了自己以外的坦克进行比较是否碰撞
if (enemyTank != this) {
// x范围 [enemyTank.getX(),enemyTank.getX() + 80]
// y范围 [enemyTank.getY() -10,enemyTank.getY() + 80]
if (enemyTank.getDirection() == 0) {// 其它敌人坦克在朝上
// 当前坦克左上角坐标 [this.getX() - 10,this.getY()]
if (this.getX() - 10 >= enemyTank.getX()
&& this.getX() - 10 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY() - 10
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY()]
if (this.getX() + 80 >= enemyTank.getX()
&& this.getX() + 80 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY() - 10
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
}
// x范围 [enemyTank.getX(),enemyTank.getX() + 80]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80 + 10]
if (enemyTank.getDirection() == 2) {// 其它敌人坦克在朝下
// 当前坦克左上角坐标 [this.getX() - 10,this.getY()]
if (this.getX() - 10 >= enemyTank.getX()
&& this.getX() - 10 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80 + 10) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY()]
if (this.getX() + 80 >= enemyTank.getX()
&& this.getX() + 80 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80 + 10) {
return true;
}
}
// x范围 [enemyTank.getX(),enemyTank.getX() + 80 + 10]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80]
if (enemyTank.getDirection() == 1) {// 其它敌人坦克在朝右
// 当前坦克左上角坐标 [this.getX() - 10,this.getY()]
if (this.getX() - 10 >= enemyTank.getX()
&& this.getX() - 10 <= enemyTank.getX() + 80 + 10
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY()]
if (this.getX() + 80 >= enemyTank.getX()
&& this.getX() + 80 <= enemyTank.getX() + 80 + 10
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
}
// x范围 [enemyTank.getX() - 10,enemyTank.getX() + 80]
// y范围 [enemyTank.getY(),enemyTank.getY() + 80]
if (enemyTank.getDirection() == 3) {// 其它敌人坦克在朝左
// 当前坦克左上角坐标 [this.getX() - 10,this.getY()]
if (this.getX() - 10 >= enemyTank.getX() - 10
&& this.getX() - 10 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
// 当前坦克右上角坐标 [this.getX() + 80,this.getY()]
if (this.getX() + 80 >= enemyTank.getX() - 10
&& this.getX() + 80 <= enemyTank.getX() + 80
&& this.getY() >= enemyTank.getY()
&& this.getY() <= enemyTank.getY() + 80) {
return true;
}
}
} // enemyTank != this
} // for
break;
}
return false;
}
}
玩家坦克 PlayerTank
package com.View;
import java.util.Vector;
/**
* @author wty
* @date 2022/10/21 0:00
* 玩家的坦克
*/
public class PlayerTank extends Tank{
private Shot shot = null;
private Vector<Shot> manyShoots = new Vector<>();
private int max_Shoots = 4;
public PlayerTank(int x, int y) {
super(x, y);
}
public Shot getShot() {
return shot;
}
public void setShot(Shot shot) {
this.shot = shot;
}
public Vector<Shot> getManyShoots() {
return manyShoots;
}
public void setManyShoots(Vector<Shot> manyShoots) {
this.manyShoots = manyShoots;
}
// 玩家坦克的射击行为
public void shotEnemy(){
// 控制己方坦克最大导弹量
if (manyShoots.size() >= max_Shoots){
return;
}
// 要根据当前坦克的位置创建子弹对象
switch (this.getDirection()){
case 0:
shot = new Shot(this.getX() + 37,this.getY() - 10,0);
break;
case 1:
shot = new Shot(this.getX() + 80,this.getY() + 37,1);
break;
case 2:
shot = new Shot(this.getX() + 37,this.getY() + 70,2);
break;
case 3:
shot = new Shot(this.getX() - 10,this.getY() + 37,3);
break;
}
manyShoots.add(shot);
// 启动线程
new Thread(shot).start();
}
}
音乐播放 AePlayWave
韩老师写的代码
package com.View;
import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
/**
* @author hsp
* @date 2022/10/21 0:01
* 播放音乐
*/
public class AePlayWave extends Thread {
private String filename;
public AePlayWave(String wavfile) { //构造器 , 指定文件
filename = wavfile;
}
public void run() {
File soundFile = new File(filename);
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e1) {
e1.printStackTrace();
return;
}
AudioFormat format = audioInputStream.getFormat();
SourceDataLine auline = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (Exception e) {
e.printStackTrace();
return;
}
auline.start();
int nBytesRead = 0;
//这是缓冲
byte[] abData = new byte[512];
try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0)
auline.write(abData, 0, nBytesRead);
}
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
auline.drain();
auline.close();
}
}
}
坦克爆炸Boom
package com.View;
/**
* @author wty
* @date 2022/10/21 18:38
*
* 爆炸效果
*/
public class Boom {
private int x;
private int y;
private int life = 9; // 坦克的生命,三条命
private boolean isLive = true;
public Boom(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getLife() {
return life;
}
public void setLife(int life) {
this.life = life;
}
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
// 减少生命值
public void lifeKill(){
if (life > 0){
life --;
}else {
isLive = false;
}
}
}
游戏结束 EndGame
package com.View;
import javax.swing.*;
import java.awt.*;
/**
* @author wty
* @date 2022/10/22 22:51
*/
public class EndGame extends JDialog {
public EndGame(){
setVisible(true);
setBounds(100,100,200,200);
//setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 弹出窗口自带关闭
Container container = getContentPane();
container.setLayout(null);
JLabel jLabel = new JLabel("玩家坦克被击毁,游戏结束!");
jLabel.setSize(200,100);
container.add(jLabel);
}
}
敌方坦克坐标 Node
package com.View;
/**
* @author wty
* @date 2022/10/22 18:28
* <p>
* 一个Node对象:表示一个敌人坦克的坐标和信息
*/
public class Node {
private int x;
private int y;
private int direction;
public Node(int x, int y, int direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
}
右侧游戏数据 Record
package com.View;
import java.io.*;
import java.util.Vector;
/**
* @author wty
* @date 2022/10/22 16:47
* 该类用于记录游戏信息,和文件交互,用到IO流
*/
@SuppressWarnings({"all"})
public class Record {
private static int allEnemyTankCount = 0; // 击毁敌方坦克数
private static int allPlayerTankCount = 3; // 玩家坦克生命
// 输出流
private static BufferedWriter bufferedWriter = null; // 文件处理流
private static FileWriter fileWriter = null; // 文件节点流
private static String recordFile = "src\\EnemyRecord.txt";
// 用于存储玩家坦克的坐标
private static BufferedWriter bufferedWriterPlay = null; // 文件处理流
private static FileWriter fileWriterPlay = null; // 文件节点流
private static String recordFilePlay = "src\\PlayerRecord.txt";
// 输入流
private static BufferedReader bufferedReader = null; // 文件处理流
private static FileReader fileReader = null; // 文件节点流
// 读取玩家坐标
private static BufferedReader bufferedReaderPlayer = null; // 文件处理流
private static FileReader fileReaderPlayer = null; // 文件节点流
// 定义Vector集合,指向MyPanel对象的敌人坦克
private static Vector<EnemyTank> enemyTanks = null;
// 定义一个Vector类型的Node用于存放敌方信息
private static Vector<Node> nodes = new Vector<>();
private static int x_player;
private static int y_player;
private static int direction_player;
public static String getRecordFile() {
return recordFile;
}
public static void setRecordFile(String recordFile) {
Record.recordFile = recordFile;
}
public static String getRecordFilePlay() {
return recordFilePlay;
}
public static void setRecordFilePlay(String recordFilePlay) {
Record.recordFilePlay = recordFilePlay;
}
public static int getX_player() {
return x_player;
}
public static void setX_player(int x_player) {
Record.x_player = x_player;
}
public static int getY_player() {
return y_player;
}
public static void setY_player(int y_player) {
Record.y_player = y_player;
}
public static int getDirection_player() {
return direction_player;
}
public static void setDirection_player(int direction_player) {
Record.direction_player = direction_player;
}
public static void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
Record.enemyTanks = enemyTanks;
}
public static int getAllEnemyTankCount() {
return allEnemyTankCount;
}
public static void setAllEnemyTankCount(int allEnemyTankCount) {
Record.allEnemyTankCount = allEnemyTankCount;
}
public static int getAllPlayerTankCount() {
return allPlayerTankCount;
}
public static void setAllPlayerTankCount(int allPlayerTankCount) {
Record.allPlayerTankCount = allPlayerTankCount;
}
// 读取文件恢复敌人相关信息
public static Vector<Node> getNodesandCountEnemy() {
try {
// 先判断文件是否存在
File file = new File(recordFile);
if (null != file && 0 != file.length() && file.exists()){
bufferedReader = new BufferedReader(new FileReader(recordFile));
allEnemyTankCount = Integer.parseInt(bufferedReader.readLine());
//allPlayerTankCount = Integer.parseInt(bufferedReader.readLine());
// 生成Node集合
String str_cont = "";
while((str_cont = bufferedReader.readLine()) != null) {
String[] s = str_cont.split(" ");
Node node = new Node(Integer.parseInt(s[0]), Integer.parseInt(s[1]), Integer.parseInt(s[2]));
nodes.add(node); // 把坐标存入Node集合(Vector)中
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedReader != null){
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return nodes;
}
// 读取文件恢复敌人相关信息
public static void getNodesandCountPlayer() {
try {
// 先判断文件是否存在
File file = new File(recordFilePlay);
if (null != file && 0 != file.length() && file.exists()){
bufferedReaderPlayer = new BufferedReader(new FileReader(recordFilePlay));
allPlayerTankCount = Integer.parseInt(bufferedReaderPlayer.readLine());
x_player = Integer.parseInt(bufferedReaderPlayer.readLine());
y_player = Integer.parseInt(bufferedReaderPlayer.readLine());
direction_player = Integer.parseInt(bufferedReaderPlayer.readLine());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedReader != null){
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return;
}
// 当玩家击毁一辆敌方坦克
public static void addTankCout() {
// 静态对象,可以类名.变量名
Record.allEnemyTankCount++;
}
// 当玩家坦克被敌方击毁时
public static void minusPlayerTankCout() {
// 静态对象,可以类名.变量名
Record.allPlayerTankCount--;
if (allPlayerTankCount <= 0){
System.out.println("玩家坦克被击毁,游戏结束!");
new EndGame();
}
}
// 增加一个方法保存击败坦克数量等游戏信息
// 保存敌方坦克的坐标和方向
public static void saveRecordEnemy() {
try {
bufferedWriter = new BufferedWriter(new FileWriter(recordFile));
bufferedWriter.write(allEnemyTankCount + "\r\n"); // 换行
//bufferedWriter.write(allPlayerTankCount + "\r\n"); // 换行
System.out.println("写入allPlayerTankCount:" + allPlayerTankCount);
//bufferedWriter.newLine();
// 遍历敌人坦克的集合Vector然后看情况保存
for (int i = 0; i < enemyTanks.size(); i++) {
// 取出坦克
EnemyTank enemyTank = enemyTanks.get(i);
if (enemyTank != null && enemyTank.isLive()) {
// 保存该enemyTank信息
String record = enemyTank.getX() + " " + enemyTank.getY() + " " + enemyTank.getDirection();
bufferedWriter.write(record + "\r\n");
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 保存玩家坦克的坐标和方向
public static void saveRecordPlayer() {
try {
bufferedWriterPlay = new BufferedWriter(new FileWriter(recordFilePlay));
bufferedWriterPlay.write(allPlayerTankCount + "\r\n"); // 换行
System.out.println("写入allPlayerTankCount:" + allPlayerTankCount);
//bufferedWriter.newLine();
bufferedWriterPlay.write(x_player + "\r\n");
bufferedWriterPlay.write(y_player + "\r\n");
bufferedWriterPlay.write(direction_player + "\r\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedWriterPlay.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
射击 Shot
package com.View;
/**
* @author wty
* @date 2022/10/21 15:51
* <p>
* 这个类用来记录子弹
*/
public class Shot implements Runnable {
private int x; // 子弹横坐标
private int y;// 子弹纵坐标
private int direct = 0; // 子弹方向
private int speed = 16; // 子弹速度
private boolean isLive = true; // 子弹是否存活
// 子弹的设计行为
@Override
public void run() {
while (true) {
try {
// 休眠
Thread.sleep(80); // 子弹刷新频率
} catch (Exception e) {
e.printStackTrace();
}
// 根据方向改变子弹的横纵坐标
switch (direct) {
case 0: // 子弹向上
y -= speed;
break;
case 1:// 子弹向右
x += speed;
break;
case 2:// 子弹向下
y += speed;
break;
case 3:// 子弹向左
x -= speed;
break;
}
// 调试方便输出x,y的坐标
//System.out.println("x = " + x + ",y = " + y);
// 子弹撞墙了就销毁(超出边界就销毁)
// 当子弹碰到敌人坦克的时候也应该结束线程
if (!(x > 0 && x < 1000 && y > 0 && y < 750 && isLive) || Record.getAllPlayerTankCount() <= 0) {
System.out.println("子弹线程退出");
isLive = false;
break;
}
}
}
public Shot(int x, int y, int direct) {
this.x = x;
this.y = y;
this.direct = direct;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getDirect() {
return direct;
}
public void setDirect(int direct) {
this.direct = direct;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
}