文章目录
只需要注意一点
需要载入一下坦克爆炸图片,不然会异常,你们自己找来复制命名吧
复制在这个位置
wav音乐文件最好也注意下路径啥的
AePlayWave类
package tankgame6;
/**
* Create By 刘鸿涛
* 2022/2/5 18:06
*/
import javax.sound.sampled.*;
import java.io.File;
//public class AePlayWave {
// public static void main(String[] args){
// AePlayWave apw = new AePlayWave("D:\\start.wav");
// apw.start();
// }
//}
class AePlayWave extends Thread{
private String filename;
//构造器,指定wav文件
public AePlayWave(String wavefile){
filename = wavefile;
}
public void run(){
File SoundFile = new File(filename);
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(SoundFile);
} catch (Exception e) {
e.printStackTrace();
return;
}
AudioFormat Format = audioInputStream.getFormat();
SourceDataLine sdl = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class,Format);
try {
sdl = (SourceDataLine)AudioSystem.getLine(info);
sdl.open(Format);
} catch (Exception e) {
e.printStackTrace();
return;
}
sdl.start();
int nBytesRead = 0;
//缓冲
byte[] abData = new byte [1024];
try {
while(nBytesRead!=-1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0) {
sdl.write(abData, 0, nBytesRead);
}
}
} catch (Exception e) {
e.printStackTrace();
return;
} finally {
sdl.drain();
sdl.close();
}
}
}
Bomb类
package tankgame6;
/**
* Create By 刘鸿涛
* 2022/1/19 4:56
*/
public class Bomb {
int x, y; //炸弹的坐标
int life = 9; //炸弹的生命周期
boolean isLive = true; //是否还存活
public Bomb(int x, int y){
this.x = x;
this.y = y;
}
//减少生命值
public void lifeDown(){
if(life > 0){
life--;
}else {
isLive = false;
}
}
}
EnemyTank类
package tankgame6;
import java.util.Vector;
/**
* Create By 刘鸿涛
* 2022/1/13 2:16
*/
public class EnemyTank extends Tank implements Runnable {
//在敌人坦克类,使用Vector 保存多个Shot
Vector<Shot> shots = new Vector<>();
//增加成员,EnemyTank 可以得到敌人坦克的Vector
Vector<EnemyTank> enemyTanks = new Vector<>();
boolean isLive = true;
public EnemyTank(int x, int y) {
super(x, y);
}
//这里提供一个方法,可以将MyPanel的成员 Vector<EnemyTank> enemyTanks = new Vector<>();
//设置到 EnemyTank 的成员 enemyTanks
public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
this.enemyTanks = enemyTanks;
}
//编写方法,判断当前的这个敌人坦克,是否和enemyTanks中的其他坦克发生了重叠或者碰撞
public boolean isTouchEnemyTank() {
//判断当前敌人坦克(this)方向
switch (this.getDirect()) {
case 0://上
//让当前的敌人坦克和其他所有的敌人坦克比较
for (int i = 0; i < enemyTanks.size(); i++) {
//从vector 中取出一个敌人坦克
EnemyTank enemyTank = enemyTanks.get(i);
//不和自己比较
if (enemyTank != this) {
//如果敌人坦克是上、下
//1.如果敌人坦克是上/下 x的范围[enemyTank.getX(),enemyTank.getX() + 40]
// y的范围 [enemyTank.getY(),enemyTank.getY() + 60]
if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
//2.当前坦克,左上角的坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX() &&
this.getX() <= enemyTank.getX() &&
this.getY() >= enemyTank.getY() &&
this.getY() <= enemyTank.getY() + 60) {
return true;
}
//3.当前坦克 右上角的坐标 [this.getX() + 40,this.getY()]
if (this.getX() + 40 >= enemyTank.getX() &&
this.getX() + 40 <= enemyTank.getX() + 40 &&
this.getY() >= enemyTank.getY() &&
this.getY() <= enemyTank.getY() + 60) {
return true;
}
}
//如果敌人坦克是右、左
//1.如果敌人坦克是上/下 x的范围[enemyTank.getX(),enemyTank.getX() + 60]
// y的范围 [enemyTank.getY(),enemyTank.getY() + 40]
if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
//2.当前坦克,左上角的坐标 [this.getX(),this.getY()]
if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
//2.当前坦克,左上角的坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX() &&
this.getX() <= enemyTank.getX() + 60 &&
this.getY() >= enemyTank.getY() &&
this.getY() <= enemyTank.getY() + 40) {
return true;
}
//3.当前坦克 右上角的坐标 [this.getX() + 40,this.getY()]
if (this.getX() + 40 >= enemyTank.getX() &&
this.getX() + 40 <= enemyTank.getX() + 60 &&
this.getY() >= enemyTank.getY() &&
this.getY() <= enemyTank.getY() + 40) {
return true;
}
}
}
}
}
break;
case 1://右
//让当前的敌人坦克和其他所有的敌人坦克比较
for (int i = 0; i < enemyTanks.size(); i++) {
//从vector 中取出一个敌人坦克
EnemyTank enemyTank = enemyTanks.get(i);
//不和自己比较
if (enemyTank != this) {
//如果敌人坦克是上、下
//1.如果敌人坦克是上/下 x的范围[enemyTank.getX(),enemyTank.getX() + 40]
// y的范围 [enemyTank.getY(),enemyTank.getY() + 60]
if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
//2.当前坦克,右上角的坐标 [this.getX() + 60,this.getY()]
if (this.getX() + 60 >= enemyTank.getX() &&
this.getX() + 60 <= enemyTank.getX() &&
this.getY() >= enemyTank.getY() &&
this.getY() <= enemyTank.getY() + 60) {
return true;
}
//3.当前坦克 右下角的坐标 [this.getX() + 60,this.getY() + 40]
if (this.getX() + 60 >= enemyTank.getX() &&
this.getX() + 60 <= enemyTank.getX() + 60 &&
this.getY() + 40 >= enemyTank.getY() &&
this.getY() + 40 <= enemyTank.getY() + 40) {
return true;
}
}
//如果敌人坦克是右、左
//1.如果敌人坦克是左/右 x的范围[enemyTank.getX(),enemyTank.getX() + 60]
// y的范围 [enemyTank.getY(),enemyTank.getY() + 40]
if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
//2.当前坦克,右上角的坐标 [this.getX() + 60,this.getY()]
if (this.getX() + 60 >= enemyTank.getX() &&
this.getX() + 60 <= enemyTank.getX() + 60 &&
this.getY() >= enemyTank.getY() &&
this.getY() <= enemyTank.getY() + 40) {
return true;
}
//3.当前坦克 右下角的坐标 [this.getX() + 60,this.getY() + 40]
if (this.getX() + 60 >= enemyTank.getX() &&
this.getX() + 60 <= enemyTank.getX() + 60 &&
this.getY() + 40 >= enemyTank.getY() &&
this.getY() + 40 <= enemyTank.getY() + 40) {
return true;
}
}
}
}
break;
case 2://下
//让当前的敌人坦克和其他所有的敌人坦克比较
for (int i = 0; i < enemyTanks.size(); i++) {
//从vector 中取出一个敌人坦克
EnemyTank enemyTank = enemyTanks.get(i);
//不和自己比较
if (enemyTank != this) {
//如果敌人坦克是上、下
//1.如果敌人坦克是上/下 x的范围[enemyTank.getX(),enemyTank.getX() + 40]
// y的范围 [enemyTank.getY(),enemyTank.getY() + 60]
if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
//2.当前坦克,左下角的坐标 [this.getX(),this.getY() + 60]
if (this.getX() >= enemyTank.getX() + 40 &&
this.getX() <= enemyTank.getX() &&
this.getY() + 60 >= enemyTank.getY() &&
this.getY() + 60 <= enemyTank.getY() + 60) {
return true;
}
//3.当前坦克 右下角的坐标 [this.getX() + 40,this.getY() + 60]
if (this.getX() + 40 >= enemyTank.getX() &&
this.getX() + 40 <= enemyTank.getX() + 40 &&
this.getY() + 60 >= enemyTank.getY() &&
this.getY() + 60 <= enemyTank.getY() + 60) {
return true;
}
}
//如果敌人坦克是右、左
//1.如果敌人坦克是左/右 x的范围[enemyTank.getX(),enemyTank.getX() + 60]
// y的范围 [enemyTank.getY(),enemyTank.getY() + 40]
if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
//2.当前坦克,左下角的坐标 [this.getX(),this.getY() + 60]
if (this.getX() >= enemyTank.getX() &&
this.getX() <= enemyTank.getX() + 60 &&
this.getY() + 60 >= enemyTank.getY() &&
this.getY() + 60 <= enemyTank.getY() + 40) {
return true;
}
//3.当前坦克 右下角的坐标 [this.getX() + 40,this.getY() + 60]
if (this.getX() + 40 >= enemyTank.getX() &&
this.getX() + 40 <= enemyTank.getX() + 40 &&
this.getY() + 60 >= enemyTank.getY() &&
this.getY() + 60 <= enemyTank.getY() + 60) {
return true;
}
}
}
}
break;
case 3://左
//让当前的敌人坦克和其他所有的敌人坦克比较
for (int i = 0; i < enemyTanks.size(); i++) {
//从vector 中取出一个敌人坦克
EnemyTank enemyTank = enemyTanks.get(i);
//不和自己比较
if (enemyTank != this) {
//如果敌人坦克是上、下
//1.如果敌人坦克是上/下 x的范围[enemyTank.getX(),enemyTank.getX() + 40]
// y的范围 [enemyTank.getY(),enemyTank.getY() + 60]
if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
//2.当前坦克,左上角的坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX() + 40 &&
this.getX() <= enemyTank.getX() &&
this.getY() >= enemyTank.getY() &&
this.getY() <= enemyTank.getY() + 60) {
return true;
}
//3.当前坦克 左下角的坐标 [this.getX() ,this.getY() + 40]
if (this.getX() >= enemyTank.getX() &&
this.getX() <= enemyTank.getX() + 40 &&
this.getY() + 40 >= enemyTank.getY() &&
this.getY() + 40 <= enemyTank.getY() + 60) {
return true;
}
}
//如果敌人坦克是右、左
//1.如果敌人坦克是左/右 x的范围[enemyTank.getX(),enemyTank.getX() + 60]
// y的范围 [enemyTank.getY(),enemyTank.getY() + 40]
if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
//2.当前坦克,左上角的坐标 [this.getX(),this.getY()]
if (this.getX() >= enemyTank.getX() &&
this.getX() <= enemyTank.getX() + 60 &&
this.getY() >= enemyTank.getY() &&
this.getY() <= enemyTank.getY() + 40) {
return true;
}
//3.当前坦克 左下角的坐标 [this.getX() ,this.getY() + 40]
if (this.getX() >= enemyTank.getX() &&
this.getX() <= enemyTank.getX() + 40 &&
this.getY() + 40 >= enemyTank.getY() &&
this.getY() + 40 <= enemyTank.getY() + 60) {
return true;
}
}
}
}
break;
}
return false;
}
@Override
public void run() {
//然后随机的改变坦克方向
while (true) {
//这里我们判断如果shots size() = 0,创建一颗子弹,放入到shots集合中,并启动
if (isLive && shots.size() < 10000) {
Shot s = null;
//判断坦克的方向,创建对应的子弹
switch (getDirect()) {
case 0:
s = new Shot(getX() + 20, getY(), 0);
break;
case 1:
s = new Shot(getX() + 60, getY(), 1);
break;
case 2:
s = new Shot(getX() + 20, getY() + 60, 2);
break;
case 3:
s = new Shot(getX() + 20, getY(), 3);
break;
}
shots.add(s);
//启动
new Thread(s).start();
}
//根据坦克的方向来继续移动
switch (getDirect()) {
case 0://向上
//让坦克保存一个方向,走30步
for (int i = 0; i < 30; i++) {
if (getY() > 0 && (!isTouchEnemyTank())) {
moveUp();
//休眠50毫秒
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
break;
case 1://右
for (int i = 0; i < 30; i++) {
// if (getX() + 60 < 1000){
if (getX() < 902 && (!isTouchEnemyTank())) {
moveRight();
//休眠50毫秒
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
break;
case 2://下
for (int i = 0; i < 30; i++) {
if (getY() < 620 && (!isTouchEnemyTank())) {
// if(getY() + 60 < 750){
moveDown();
//休眠50毫秒
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
break;
case 3://左
for (int i = 0; i < 30; i++) {
if (getX() > 0 && (!isTouchEnemyTank())) {
moveLeft();
//休眠50毫秒
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
break;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
//随机改变坦克方向0 - 3
setDirect((int) (Math.random() * 4));
//如果坦克被击中线程终止
if (!isLive) {
break;
}
}
}
}
Hero类
package tankgame6;
import java.util.Vector;
/**
* Create By 刘鸿涛
* 2022/1/12 4:40
* 自己的坦克
*/
public class Hero extends Tank {
//定义一个Shot对象,表示一个射击(线程)
Shot shot = null;
Vector<Shot> shots = new Vector<>();
public Hero(int x, int y) {
super(x, y);
}
//射击
public void shotEnemyTank() {
//发多颗子弹怎么办,控制在我们的面板上,最多只有5颗
if(shots.size() == 1000){
return;
}
//创建 Shot 对象,根据当前Hero对象的位置和方向来创建Shot
switch (getDirect()){ //得到Hero对象方向
case 0: //向上
shot = new Shot(getX() + 20,getY(),0);
break;
case 1: //向右
shot = new Shot(getX() + 60 ,getY() + 20, 1);
break;
case 2: //向下
shot = new Shot(getX() + 20, getY() + 60,2);
break;
case 3: //向左
shot = new Shot(getX(), getY() + 20,3);
break;
}
//把新创建的shot放入到shots
shots.add(shot);
//启动我们的Shot线程
new Thread(shot).start();
}
}
MyPanel类
package tankgame6;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import java.util.Vector;
/**
* Create By 刘鸿涛
* 2022/1/12 4:41
* 坦克大战的绘图区域
*/
//为了让Pannel 不停地重绘子弹,需要将 MyPanel实现 Runnable,当做一个线程使用
public class MyPanel extends JPanel implements KeyListener, Runnable {
//定义我的坦克
Hero hero = null;
//定义敌人坦克,放入到Vector集合
Vector<EnemyTank> enemyTanks = new Vector();
//定义一个存放Node 对象的Vector,用于恢复敌人坦克的坐标和方向
Vector<Node> nodes = new Vector<>();
//定义一个Vector,用于存放炸弹
//说明,当子弹击中坦克时,加入一个Bomb对象bombs
Vector<Bomb> bombs = new Vector<>();
int enemyTanksSize = 8;
//定义三张炸弹图片,用于显示爆炸效果
Image image1 = null;
Image image2 = null;
Image image3 = null;
public MyPanel(String key) {
//判断记录的文件是否存在
//不存在,只能开启新游戏
File file = new File(Recorder.getRecordFile());
if (file.exists()){
try {
nodes = Recorder.getNodesAndEnemyTankRec();
} catch (IOException e) {
e.printStackTrace();
}
} else {
System.out.println("文件不存在,只能开启新的游戏");
key = "1";
}
try {
nodes = Recorder.getNodesAndEnemyTankRec();
} catch (IOException e) {
e.printStackTrace();
}
//将MyPanel对象的 enemyTanks 设置给 Recorder 的 enemyTanks
Recorder.setEnemyTanks(enemyTanks);
hero = new Hero(500, 500); //初始化自己的坦克
hero.setSpeed(50); //初始化坦克速度
switch (key){
case "1": //新游戏
//初始化敌人坦克
for (int i = 0; i < enemyTanksSize; i++) {
//创建一个敌人的坦克
EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);
//将 enemyTanks 设置给 enemyTank
enemyTank.setEnemyTanks(enemyTanks);
//设置方向
enemyTank.setDirect(2);
//启动敌方坦克线程
new Thread(enemyTank).start();
//给该enemyTank 加入一颗子弹
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
//加入enemyTank的Vector 成员
enemyTank.shots.add(shot);
//启动 shot 对象
new Thread(shot).start();
//加入坦克
enemyTanks.add(enemyTank);
}
break;
case "2": //继续游戏
//初始化敌人坦克
for (int i = 0; i < nodes.size(); i++) {
Node node = nodes.get(i);
//创建一个敌人的坦克
EnemyTank enemyTank = new EnemyTank(node.getX(),node.getY());
//将 enemyTanks 设置给 enemyTank
enemyTank.setEnemyTanks(enemyTanks);
//设置方向
enemyTank.setDirect(node.getDirect());
//启动敌方坦克线程
new Thread(enemyTank).start();
//给该enemyTank 加入一颗子弹
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
//加入enemyTank的Vector 成员
enemyTank.shots.add(shot);
//启动 shot 对象
new Thread(shot).start();
//加入坦克
enemyTanks.add(enemyTank);
}
break;
default:
System.out.println("你的输入有误");
}
//初始化图片对象
image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/Bomb1.gif"));
image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/Bomb2.gif"));
image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/Bomb3.gif"));
//这里,播放指定的音乐
new AePlayWave("src\\111.wav").start();
}
//编写方法,显示我方击毁敌方坦克的信息
public void showInfo(Graphics g){
//画出玩家的总成绩
g.setColor(Color.black);
Font font = new Font("宋体",Font.BOLD,25);
g.setFont(font);
g.drawString("你击毁的敌方坦克",1000,30);
drawTank(1000,60,g,0,0); //画出一个敌方坦克
g.setColor(Color.BLACK); //这里需要重新设置成黑色,不然会保持青色
g.drawString(Recorder.getAllEnemyTankNum() + "",1080,100); //注意转字符串
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750); //填充矩形,默认黑色
showInfo(g);
//画出坦克 - 封装方法
//自己的坦克
if(hero.isLive)
drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1); //type坦克类型
//画出hero射击的子弹
// if (hero.shot != null && hero.shot.isLive) {
// g.draw3DRect(hero.shot.x, hero.shot.y, 2, 2, false);
// }
//将hero的子弹集合 shots,遍历取出绘制
for (int i = 0; i < hero.shots.size(); i++) {
Shot shot = hero.shots.get(i);
if (shot != null && shot.isLive) {
g.draw3DRect(shot.x, shot.y, 2, 2, false);
} else { //如果该shot对象已经无效了,就从shots集合中拿掉
hero.shots.remove(shot);
}
}
//如果bombs 集合中有对象,就画出
for (int i = 0; i < bombs.size(); i++) {
//取出炸弹
Bomb bomb = bombs.get(i);
//根据当前这个bomb对象的life值去画出对应的图片
if (bomb.life > 6) {
g.drawImage(image1, bomb.x, bomb.y, 60, 60, this);
} else if (bomb.life > 3) {
g.drawImage(image2, bomb.x, bomb.y, 60, 60, this);
} else {
g.drawImage(image3, bomb.x, bomb.y, 60, 60, this);
}
//让这个炸弹的生命值减少
bomb.lifeDown();
//如果bomb life 为0,就从bombs的集合中删除
if (bomb.life == 0) {
bombs.remove(bomb);
}
}
//画出敌人的坦克,遍历Vector
for (int i = 0; i < enemyTanks.size(); i++) {
//取出坦克
EnemyTank enemyTank = enemyTanks.get(i);
//判断当前坦克是否存活
if (enemyTank.isLive) { //当敌人坦克是存活的,才画出该坦克
drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 0);
//画出 enemyTank 所有子弹
for (int j = 0; j < enemyTank.shots.size(); j++) {
//取出子弹
Shot shot = enemyTank.shots.get(j);
//绘制
if (shot.isLive) { //isLive 为 true
g.draw3DRect(shot.x, shot.y, 2, 2, false);
} else {
//从Vector 移除
enemyTank.shots.remove(shot);
}
}
}
}
}
//编写方法,画出坦克
/**
* @param x 坦克的左上角x坐标
* @param y 坦克的左上角y坐标
* @param g 画笔
* @param direct 坦克方向(上下左右)
* @param type 坦克类型
*/
public void drawTank(int x, int y, Graphics g, int direct, int type) {
switch (type) {
case 0: //敌人的坦克
g.setColor(Color.CYAN);
break;
case 1: //我的坦克
g.setColor(Color.yellow);
break;
}
//根据坦克方向,来绘制对应形状坦克
//
switch (direct) {
case 0: //表示向上
g.fill3DRect(x, y, 10, 60, false); //左边轮子
g.fill3DRect(x + 30, y, 10, 60, false); //右边轮子
g.fill3DRect(x + 10, y + 10, 20, 40, false); //盖子
g.fillOval(x + 10, y + 20, 20, 20); //炮塔
g.drawLine(x + 20, y + 30, x + 20, y); //炮筒
break;
case 1: //向右
g.fill3DRect(x, y, 60, 10, false); //左边轮子
g.fill3DRect(x, y + 30, 60, 10, false); //右边轮子
g.fill3DRect(x + 10, y + 10, 40, 20, false); //底盘
g.fillOval(x + 20, y + 10, 20, 20); //炮塔
g.drawLine(x + 30, y + 20, x + 60, y + 20); //炮筒
break;
case 2: //向下
g.fill3DRect(x, y, 10, 60, false); //左边轮子
g.fill3DRect(x + 30, y, 10, 60, false); //右边轮子
g.fill3DRect(x + 10, y + 10, 20, 40, false); //盖子
g.fillOval(x + 10, y + 20, 20, 20); //炮塔
g.drawLine(x + 20, y + 30, x + 20, y + 60); //炮筒
break;
case 3: //向左
g.fill3DRect(x, y, 60, 10, false); //左边轮子
g.fill3DRect(x, y + 30, 60, 10, false); //右边轮子
g.fill3DRect(x + 10, y + 10, 40, 20, false); //底盘
g.fillOval(x + 20, y + 10, 20, 20); //炮塔
g.drawLine(x + 30, y + 20, x, y + 20); //炮筒
//炮筒
break;
default:
System.out.println("暂时没有处理");
}
}
//如果我们的坦克可以发射多个子弹
//在判断我方子弹是否击中敌人坦克时,就需要把我们的子弹集合中的所有子弹遍历,并进行判断
public void hitEnemyTank() {
//遍历我们的子弹
for (int j = 0; j < hero.shots.size(); j++) {
Shot shot = hero.shots.get(j);
//判断是否击中了敌人坦克
if (shot != null && shot.isLive) { //当前我的子弹存活
//遍历所有的坦克
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
hitTank(shot, enemyTank);
}
}
}
}
//编写方法,判断我方的子弹是否击中敌人坦克,这里直接换成父类Tank(多态)
public void hitTank(Shot s, Tank tank) {
//判断 s 击中坦克
switch (tank.getDirect()) {
case 0: //坦克向上
case 2: //坦克向下
if (s.x > tank.getX() && s.x < tank.getX() + 40
&& s.y > tank.getY() && s.y < tank.getY() + 60) {
s.isLive = false;
tank.isLive = false;
//把敌方坦克从集合中remove
enemyTanks.remove(tank);
//当我方击毁一个地方坦克时,就对数据allEnemyTankNum++
//注意:此时的坦克可以是hero也可以是enemyTank
if (tank instanceof EnemyTank){
Recorder.addAllEnemyTankNum();
}
//创建Bomb对象,加入到bombs集合中
Bomb bomb = new Bomb(tank.getX(), tank.getY());
bombs.add(bomb);
}
break;
case 1: //坦克向右
case 3: //坦克向左
if (s.x > tank.getX() && s.x < tank.getX() + 60
&& s.y > tank.getY() && s.y < tank.getY() + 40) {
s.isLive = false;
tank.isLive = false;
//将敌方坦克从集合中remove
enemyTanks.remove(tank);
if (tank instanceof EnemyTank){
Recorder.addAllEnemyTankNum();
}
//创建Bomb对象,加入到bombs集合中
Bomb bomb = new Bomb(tank.getX(), tank.getY());
bombs.add(bomb);
}
break;
}
}
编写方法,击中我放坦克功能
public void hitHero(){
//遍历所有的敌人坦克
for (int i = 0; i < enemyTanks.size(); i++){
//取出敌人坦克
EnemyTank enemyTank = enemyTanks.get(i);
//遍历enemyTank 对象的所有子弹
for (int j = 0; j < enemyTank.shots.size(); j++){
//取出子弹
Shot shot = enemyTank.shots.get(j);
//判断 shot 是否击中我方坦克
if (hero.isLive && shot.isLive){
hitTank(shot,hero);
}
}
}
}
@Override
public void keyTyped(KeyEvent e) {
}
//处理键位按下操作
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) { //上
//改变坦克方向
hero.setDirect(0);
if (hero.getY() > 0) {
hero.moveUp();
}
} else if (e.getKeyCode() == KeyEvent.VK_D) { //右
hero.setDirect(1);
if (hero.getX() < 901) {
hero.moveRight();
}
// hero.setX(hero.getX() + 1);
} else if (e.getKeyCode() == KeyEvent.VK_S) { //下
hero.setDirect(2);
if (hero.getY() < 620) {
hero.moveDown();
}
// hero.setY(hero.getY() + 1);
} else if (e.getKeyCode() == KeyEvent.VK_A) { //左
hero.setDirect(3);
if (hero.getX() > 0) {
hero.moveLeft();
}
// hero.setX(hero.getX() - 1);
}
if (e.getKeyCode() == KeyEvent.VK_J) { //发射子弹
//发射一发子弹情况
// if (hero.shot == null || hero.shot.isLive == false) {
// hero.shotEnemyTank();
// }
hero.shotEnemyTank();
}
repaint();
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void run() { //每隔10毫秒,重绘区域,刷新绘图区域,子弹就移动
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//判断敌人坦克是否击中我们坦克
hitHero();
hitEnemyTank();
this.repaint();
}
}
}
Node类
package tankgame6;
/**
* Create By 刘鸿涛
* 2022/2/5 16:28
* 一个Node 对象,表示一个敌人坦克的信息
*/
public class Node {
private int x;
private int y;
private int direct;
public Node(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;
}
}
Recorder类
package tankgame6;
import java.io.*;
import java.util.Vector;
/**
* Create By 刘鸿涛
* 2022/2/5 12:58
* 该类用于记录相关信息的,和文件交互
*/
public class Recorder {
//定义变量,记录我方击毁敌人坦克数
private static int allEnemyTankNum = 0;
//定义IO对象
private static FileWriter fw = null;
private static BufferedWriter bw = null;
private static BufferedReader br = null;
//把记录文件保存到src 下
//private static String recordFile = "d:\\myRecord.txt";
private static String recordFile = "src\\myRecord.txt";
//定一个Vector,指向 MyPanel 对象的 敌人坦克Vector
private static Vector<EnemyTank> enemyTanks = null;
//定义一个Node 的Vector ,用于保存敌人的信息node
private static Vector<Node> nodes = new Vector<>();
public static void setEnemyTanks(Vector<EnemyTank> enemyTanks){
Recorder.enemyTanks = enemyTanks;
}
//返回记录文件路径
public static String getRecordFile(){
return recordFile;
}
//增加一个方法,用于读取recordFile,恢复相关信息
//该方法,在继续上局游戏时调用即可
public static Vector<Node> getNodesAndEnemyTankRec() throws IOException {
br = new BufferedReader(new FileReader(recordFile));
allEnemyTankNum = Integer.parseInt(br.readLine());
//循环读取文件,生成nodes集合
String line = "";
while ((line = br.readLine()) != null){
String []xyd = line.split(" ");
Node node = new Node(Integer.parseInt(xyd[0]),
Integer.parseInt(xyd[1]), Integer.parseInt(xyd[2]));
nodes.add(node); //nodes Vector
}
if(br != null){
br.close();
}
return nodes;
}
//增加一个方法,当游戏退出时,我们将allEnemyTankNum保存到 recordFile
//对keepRecord 进行升级,保存敌人坦克的坐标和方向
public static void keepRecord() throws IOException {
bw = new BufferedWriter(new FileWriter(recordFile));
// bw.newLine();
bw.write(allEnemyTankNum + "\r\n");
//遍历敌人坦克Vector,然后根据情况保存即可
//OOP,定义一个属性,然后通过setXxx得到敌人Vector
for (int i = 0; i < enemyTanks.size(); i++){
//取出敌人坦克
EnemyTank enemyTank = enemyTanks.get(i);
//建议下面判断下(可以不判断)
if (enemyTank.isLive){
//保存该enemyTank信息
String record = enemyTank.getX() + " " + enemyTank.getY() + " " + enemyTank.getDirect();
//写入到文件
bw.write(record + "\r\n");
}
}
if (bw != null){
bw.close();
}
}
public static int getAllEnemyTankNum(){
return allEnemyTankNum;
}
public static void setAllEnemyTankNum(int allEnemyTankNum){
Recorder.allEnemyTankNum = allEnemyTankNum;
}
//当我方坦克击毁一个敌人坦克时,就应当allEnemyTankNum++
public static void addAllEnemyTankNum(){
Recorder.allEnemyTankNum++;
}
}
Shot类
package tankgame6;
/**
* Create By 刘鸿涛
* 2022/1/17 5:19
*/
public class Shot implements Runnable{
int x; //子弹x坐标
int y; //子弹y坐标
int direct = 0; //子弹方向
int speed = 2; //子弹速度
boolean isLive = true; //子弹是否存活
public Shot(int x, int y, int direct) {
this.x = x;
this.y = y;
this.direct = direct;
}
@Override
public void run() { //射击
while (true){
//子弹休眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
//根据方向来改变x,y坐标
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 = false;
break;
}
}
}
}
Tank类
package tankgame6;
/**
* Create By 刘鸿涛
* 2022/1/12 4:38
*/
public class Tank {
private int x; //坦克的横坐标
private int y; //坦克的纵坐标
private int direct; //坦克方向返回值
private int speed = 10; //坦克的速度
//给hero坦克使用的isLive属性
boolean isLive = true;
public int getDirect() {
return direct;
}
public void moveUp(){
y -= speed;
}
public void moveRight(){
x += speed;
}
public void moveDown(){
y += speed;
}
public void moveLeft(){
x -= speed;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public void setDirect(int direct) {
this.direct = direct;
}
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;
}
}
TankGame06类
package tankgame6;
import javax.swing.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.Scanner;
/**
* Create By 刘鸿涛
* 2022/1/12 4:45
*/
public class TankGame06 extends JFrame {
//定义MyPanel
MyPanel mp = null;
static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
TankGame06 taoTankGame01 = new TankGame06();
}
public TankGame06() {
System.out.println("请输入选择 1:新游戏 、 2:继续上局");
String key = sc.next();
mp = new MyPanel(key);
//将mp 放入到Thread,并启动
Thread thread = new Thread(mp);
thread.start();
this.add(mp); //把面板(就是游戏的绘图区域)
this.setSize(1300, 950);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //点击x 关闭程序
this.setVisible(true); //显示
this.setLocationRelativeTo(null);
this.addKeyListener(mp);
//在JFrame中增加相应关闭窗口的处理
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.out.println("监听到关闭窗口");
try {
Recorder.keepRecord();
} catch (IOException ex) {
ex.printStackTrace();
}
//退出
System.exit(0);
}
});
}
}