登录/注册
小开开
2649
占位
2
占位
0
浏览量
占位
粉丝
占位
关注
韩顺平--Java坦克大战
小开开
2022-05-15 09:56:27 2022-05-15
40
0

1、说明

写了14个版本,终于完成了,项目结构如下

在这里插入图片描述

2、游戏效果

在这里插入图片描述

在这里插入图片描述

(1)击中敌人

在这里插入图片描述

(2)被敌人击中

在这里插入图片描述

3、代码如下

(1)TankGame 主方法

package cn.bloghut;
import cn.bloghut.component.MyPanel;
import cn.bloghut.service.Recorder;
import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Scanner;
/**
* @Classname TankGame
* @Description TODO
* @Date 2022/5/8 8:25
* @Created by 闲言
*/
public class TankGame extends JFrame {
private MyPanel panel;
public static void main(String[] args) {
new TankGame();
}
public TankGame(){
System.out.println("请输入选择: 1 表示新游戏,2是继续上局");
Scanner scanner = new Scanner(System.in);
//将panel放入到thread中
this.panel = new MyPanel(scanner.next());
scanner.close();
new Thread(panel).start();
//设置绑定监听器
this.addKeyListener(panel);
this.add(panel);
//设置窗体关闭
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("闲言-坦克大战");
//获取当前屏幕分辨率
int width = Toolkit.getDefaultToolkit().getScreenSize().width;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
//设置窗体大小不可变
this.setResizable(false);
//设置窗体位置
width = (width - 1300) / 2;
height = (height - 750) / 2;
this.setBounds(width,height,1300,750);
this.setBackground(Color.black);
//设置窗体显示
this.setVisible(true);
//在JFrame 中增加相关关闭窗口的处理
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
Recorder.keepRecord();
System.exit(0);
}
});
}
}

(2)MyPanel 视图

package cn.bloghut.component;
import cn.bloghut.pojo.*;
import cn.bloghut.service.PlayAudio;
import cn.bloghut.service.Recorder;
import cn.bloghut.service.Shot;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.util.Vector;
/**
* @Classname MyPanel
* @Description 坦克大战绘图区域
* 为了让panel 不停的重绘子弹,需要将MyPanel
* @Date 2022/5/8 8:44
* @Created by 闲言
*/
public class MyPanel extends JPanel implements KeyListener, Runnable {
//定义我的坦克
Hero hero = null;
//定义敌人坦克
Vector<EnemyTank> enemyTanks = new Vector<>();
//用于存放炸弹
//当子弹击中坦克时,就加入一个bomb 对象
Vector<Bomb> bombs = new Vector<>();
//定义三种图片,用于显示炸弹
Image img1 = null;
Image img2 = null;
Image img3 = null;
//定义一个存放Node 对象的Vector,用于恢复敌人坦克的坐标和放向
Vector<Node> nodes = null;
//敌人坦克数量
int enemyTankSize = 3;
public MyPanel(String type) {
//判断记录文件是否存在
//如果存在就正常执行,如果文件不存在,提示只能开启新的游戏
File file = new File(Recorder.getRecordFile());
if (!file.exists()){
type = "1";
System.out.println("文件不存在只能开启新游戏");
}else {
nodes = Recorder.getNodesAndTanks();
}
//初始化我的坦克
hero = new Hero(150, 150);
//设置坦克速度
hero.setSpeed(5);
switch (type) {
case "1":
//初始化敌人坦克
for (int i = 0; i < enemyTankSize; i++) {
EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);
enemyTank.setDirection(2);
//启动敌人坦克线程
new Thread(enemyTank).start();
//给该enemyTank 加入一颗子弹
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());
//加入到
enemyTank.getShots().add(shot);
//为每个坦克,放入所有的敌人对象
enemyTank.setEnemyTanks(enemyTanks);
//启动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());
enemyTank.setDirection(node.getDirection());
//启动敌人坦克线程
new Thread(enemyTank).start();
//给该enemyTank 加入一颗子弹
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirection());
//加入到
enemyTank.getShots().add(shot);
//为每个坦克,放入所有的敌人对象
enemyTank.setEnemyTanks(enemyTanks);
//启动shot
new Thread(shot).start();
enemyTanks.add(enemyTank);
}
break;
default:
System.out.println("你的输入有误");
}
//获取项目路径
//1.获取图片资源
String parent = System.getProperty("user.dir");
parent += "\\";
//2.初始化图片
img1 = Toolkit.getDefaultToolkit().getImage(parent + "bomb_1.gif");
img2 = Toolkit.getDefaultToolkit().getImage(parent + "bomb_2.gif");
img3 = Toolkit.getDefaultToolkit().getImage(parent + "bomb_3.gif");
//存放敌人坦克信息
Recorder.setEnemyTanks(enemyTanks);
//播放指定的音乐
new PlayAudio("bg.wav").start();
}
@Override
public void paint(Graphics g) {
super.paint(g);
//填充矩形,默认黑色
g.fillRect(0, 0, 1000, 750);
//画出游戏信息
showInfo(g);
//画自己坦克
if (hero != null && hero.isLive()) {
drawTank(hero.getX(), hero.getY(), g, hero.getDirection(), 1);
}
//画出自己射击的子弹
//不为空,且处于发射状态
if (hero.getShot() != null && hero.getShot().isLive()) {
g.draw3DRect(hero.getShot().getX(), hero.getShot().getY(), 2, 2, false);
}
if (hero.getShots().size() > 0) {
for (int i = 0; i < hero.getShots().size(); i++) {
Shot shot = hero.getShots().get(i);
if (shot != null && shot.isLive()) {
g.draw3DRect(shot.getX(), shot.getY(), 2, 2, false);
} else {
//如果shot对象已经无效,就从子弹集合中移除
hero.getShots().remove(shot);
}
}
}
//画敌人坦克
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
//判断当前坦克是否还存活,只有存活的时候才去画
if (enemyTank.isLive()) {
drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 0);
//绘制敌人坦克子弹
Vector<Shot> shots = enemyTank.getShots();
for (int j = 0; j < shots.size(); j++) {
Shot shot = shots.get(j);
//子弹存活的时候才绘制
if (shot.isLive()) {
g.draw3DRect(shot.getX(), shot.getY(), 1, 1, false);
} else {
//子弹出边界了,移除子弹
enemyTank.getShots().remove(shot);
}
}
}
}
//如果bombs 集合中有对象,就画出
for (int i = 0; i < bombs.size(); i++) {
Bomb bomb = bombs.get(i);
//根据当前炸弹的life值画出对应的图片
if (bomb.getLife() > 6) {
g.drawImage(img1, bomb.getX(), bomb.getY(), 60, 60, this);
} else if (bomb.getLife() > 3) {
g.drawImage(img1, bomb.getX(), bomb.getY(), 60, 60, this);
} else {
g.drawImage(img1, bomb.getX(), bomb.getY(), 60, 60, this);
}
//让这个炸弹的生命值减少
bomb.lifeDown();
//如果bomb 生命值为0,就从集合中删除
if (bomb.getLife() == 0) {
bombs.remove(bomb);
}
}
}
/**
* 显示 击毁敌方的坦克信息
*
* @param g 画图
*/
public void showInfo(Graphics g) {
g.setColor(Color.BLACK);
Font font = new Font("宋体", Font.BOLD, 25);
g.setFont(font);
g.drawString("您累计击毁敌方坦克", 1020, 30);
drawTank(1020, 60, g, 0, 0);
g.setColor(Color.BLACK);
g.drawString(Recorder.getAllEnemyTankTotal() + "", 1080, 100);
}
/**
* 绘制坦克
*
* @param x 坦克的左上角x坐标
* @param y 坦克的左上角y坐标
* @param g 画笔
* @param direction 坦克方向(上下左右)
* @param type 坦克类型
*/
public void drawTank(int x, int y, Graphics g, int direction, int type) {
//根据不同类型的坦克设置不同颜色
switch (type) {
case 0://0 敌人的坦克
g.setColor(Color.cyan);
break;
//
case 1://1 我们的坦克
g.setColor(Color.yellow);
break;
}
//根据坦克的方向来绘制坦克
//direction 0-向上,1-向右,2-向下,3-向左
switch (direction) {
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("暂时没有处理");
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
//判断用户按下的按键
if (KeyEvent.VK_W == code) { //向上
//移动时判断不能重叠
hero.setDirection(0);
hero.moveUp();
} else if (KeyEvent.VK_D == code) { //向右
hero.setDirection(1);
hero.moveRight();
} else if (KeyEvent.VK_S == code) { //向下
hero.setDirection(2);
hero.moveDown();
} else if (KeyEvent.VK_A == code) { //向左
hero.setDirection(3);
hero.moveLeft();
}
//判断是否是射击
if (KeyEvent.VK_J == code) {
//如果为空,说明是第一次发射
//发送一颗子弹
// if (hero.getShot() == null || !(hero.getShot().isLive())){
// hero.shotEnemyTank();
// }
//发射多颗子弹
hero.shotEnemyTank();
}
//重绘
this.repaint();
}
//如果我们的坦克可以发射多发子弹
//在判断我方子弹是否击中敌人坦克时,就需要把我们的子弹集合所有的子弹取出,都取出和敌人的所有坦克进行判断
//编写方法,判断我方的子弹是否击中敌人坦克
/**
* 判断子弹和坦克
*
* @param shots 子弹集合
* @param tank 坦克
*/
public void hitTank(Vector<Shot> shots, Tank tank) {
for (int i = 0; i < shots.size(); i++) {
hitTank(shots.get(i), tank);
}
}
/**
* 判断子弹和坦克
*
* @param s 子弹
* @param tank 坦克
*/
public void hitTank(Shot s, Tank tank) {
switch (tank.getDirection()) {
case 0://坦克向上
case 2://坦克向下
if (s.getX() > tank.getX() && s.getX() < tank.getX() + 40 &&
s.getY() > tank.getY() && s.getY() < tank.getY() + 60) {
s.setLive(false);
tank.setLive(false);
//当我的子弹击中敌人坦克后,将enemyTank 坦克从集合中去掉
enemyTanks.remove(tank);
//当我方击毁一辆敌方坦克时,就对一个值++(前提不是我放坦克)
if (!(tank instanceof Hero)) {
Recorder.addlEnemyTankTotal();
}
//创建bomb对象,加入到bombs集合
Bomb bomb = new Bomb(tank.getX(), tank.getY());
bombs.add(bomb);
}
break;
case 1://坦克向右
case 3://坦克向左
if (s.getX() > tank.getX() && s.getX() < tank.getX() + 60 &&
s.getY() > tank.getY() && s.getY() < tank.getY() + 40) {
s.setLive(false);
tank.setLive(false);
//打我的子弹击中敌人坦克后,将enemyTank 坦克从集合中去掉
enemyTanks.remove(tank);
//当我方击毁一辆敌方坦克时,就对一个值++(前提不是我放坦克)
if (!(tank instanceof Hero)) {
Recorder.addlEnemyTankTotal();
}
//创建bomb对象,加入到bombs集合
Bomb bomb = new Bomb(tank.getX(), tank.getY());
bombs.add(bomb);
}
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void run() {
//每隔100毫秒,重绘区域
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//判断是否击中敌人坦克
hitEnemy();
//判断敌人坦克是否击中我们
hitHero();
this.repaint();
}
}
/**
* 判断是否击中敌人坦克
*/
public void hitEnemy() {
if (hero.getShot() != null && hero.getShot().isLive()) {
//遍历敌人所有的坦克
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
//发射单个子弹
// hitTank(hero.getShot(),enemyTank);
//发射多颗子弹
hitTank(hero.getShots(), enemyTank);
}
}
}
/**
* 判断敌人坦克是否击中
*/
public void hitHero() {
if (enemyTanks.size() > 0) {
//拿到所有敌人的坦克-下的子弹,判断是否重合如果重合则显示爆炸
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
//判断是否击中
//敌人的子弹
Vector<Shot> shots = enemyTank.getShots();
if (shots.size() > 0) {
for (int j = 0; j < shots.size(); j++) {
Shot shot = shots.get(j);
if (hero.isLive() && shot.isLive()) {
//判断子弹和坦克是否重合
hitTank(shots, hero);
}
}
}
}
}
}
}

(3)Bomb 爆炸类

package cn.bloghut.pojo;
/**
* @Classname Bomb
* @Description TODO
* @Date 2022/5/8 16:18
* @Created by 闲言
*/
public class Bomb {
private int x,y;//炸弹坐标
private int life = 9;//炸弹生命周期
private 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;
}
}
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;
}
}

(4)EnemyTank 敌方坦克类

package cn.bloghut.pojo;
import cn.bloghut.service.Shot;
import java.util.Vector;
/**
* @Classname EnemyTank
* @Description TODO
* @Date 2022/5/8 11:06
* @Created by 闲言
*/
@SuppressWarnings("All")
public class EnemyTank extends Tank implements Runnable {
//在敌人坦克类,保存多个shot
private Vector<Shot> shots = new Vector<>();
//敌人坦克 可以得到敌人坦克的Vector
//1.EnemyTank 在mypanel里面
private Vector<EnemyTank> enemyTanks = new Vector<>();
public EnemyTank(int x, int y) {
super(x, y);
}
public Vector<Shot> getShots() {
return shots;
}
public void setShots(Vector<Shot> shots) {
this.shots = shots;
}
public Vector<EnemyTank> getEnemyTanks() {
return enemyTanks;
}
/**
* 提供一个方法,可以将mypanel 的成员 Vector<EnemyTank> enemyTanks = new Vector<>();
* 设置到 private Vector<EnemyTank> enemyTanks = new Vector<>();
* @param enemyTanks 敌人坦克集合
*/
public void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
this.enemyTanks = enemyTanks;
}
//编写方法,判断当前的敌人坦克,是否和 enemyTanks 中2的 其他坦克发生了重叠 或者是碰撞
public boolean isTouchEnemyTank(){
//判断当前敌人坦克(this) 方向
switch (this.getDirection()){
case 0: //上
//让当前的this 敌人坦克 和 其他所有的敌人坦克比较
for (int i = 0;i< enemyTanks.size();i++){
//从vector中取出一辆敌人的坦克
EnemyTank enemyTank = enemyTanks.get(i);
//不和自己比较
if (this != enemyTank){
/*
1.如果敌人坦克是上/下方向 x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】
y的范围是什么【enemyTank.getY() ,enemyTank.getY() + 60】
*/
if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){
//2.当前坦克的左上角坐标【this.getX(),this.getY()】
if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 40 &&
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() + 60 &&
this.getY() >= enemyTank.getY() && this.getY() <= enemyTank.getY() + 40){
return true;
}
}
/*
1.如果敌人坦克是左/右方向 x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 60】
y的范围是什么【enemyTank.getY() ,enemyTank.getY() + 40】
*/
//如果敌人坦克是左/右方向
if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 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() + 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: //右
//让当前的this 敌人坦克 和 其他所有的敌人坦克比较
for (int i = 0;i< enemyTanks.size();i++){
//从vector中取出一辆敌人的坦克
EnemyTank enemyTank = enemyTanks.get(i);
//不和自己比较
if (this != enemyTank){
/*
1.如果敌人坦克是上/下方向 x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】
y的范围是什么【enemyTank.getY(),enemyTank.getY() + 40】
*/
if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){
//2.当前坦克的右上角坐标【this.getX() + 60,this.getY()】
if (this.getX() + 60 >= enemyTank.getX() && this.getX() + 60 <= enemyTank.getX() + 40 &&
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() + 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.getX() + 40】
*/
//如果敌人坦克是左/右方向
if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 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: //下
//让当前的this 敌人坦克 和 其他所有的敌人坦克比较
for (int i = 0;i< enemyTanks.size();i++){
//从vector中取出一辆敌人的坦克
EnemyTank enemyTank = enemyTanks.get(i);
//不和自己比较
if (this != enemyTank){
/*
1.如果敌人坦克是上/下方向 x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】
y的范围是什么【enemyTank.getY(),enemyTank.getY() + 60】
*/
if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){
//2.当前坦克的左下角坐标【this.getX(),this.getY() + 60】
if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 40 &&
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.getX() + 40】
*/
//如果敌人坦克是左/右方向
if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 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() + 60 &&
this.getY() + 60 >= enemyTank.getY() && this.getY() + 60 <= enemyTank.getY() + 40){
return true;
}
}
}
}
break;
case 3: //左
//让当前的this 敌人坦克 和 其他所有的敌人坦克比较
for (int i = 0;i< enemyTanks.size();i++){
//从vector中取出一辆敌人的坦克
EnemyTank enemyTank = enemyTanks.get(i);
//不和自己比较
if (this != enemyTank){
/*
1.如果敌人坦克是上/下方向 x的范围是什么【enemyTank.getX() ,enemyTank.getX() + 40】
y的范围是什么【enemyTank.getY(),enemyTank.getY() + 60】
*/
if (enemyTank.getDirection() == 0 || enemyTank.getDirection() == 2){
//2.当前坦克的左上角坐标【this.getX(),this.getY()】
if (this.getX() >= enemyTank.getX() && this.getX() <= enemyTank.getX() + 40 &&
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.getX() + 40】
*/
//如果敌人坦克是左/右方向
if (enemyTank.getDirection() == 1 || enemyTank.getDirection() == 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() + 60 &&
this.getY() + 40 >= enemyTank.getY() && this.getY() + 40 <= enemyTank.getY() + 40){
return true;
}
}
}
}
break;
}
return false;
}
@Override
public void run() {
while (true) {
//这里我们判断如果shots size() == 0,创建一颗子弹,放入到shots集合,并启动
if (isLive() && shots.size() < 3) {
Shot s = null;
//判断坦克的方向,创建对应的子弹
switch (getDirection()) {
case 0:
s = new Shot(getX() + 20, getY(), 0);
break;
case 1:
s = new Shot(getX() + 60, getY() + 20, 1);
break;
case 2:
s = new Shot(getX() + 20, getY() + 60, 2);
break;
case 3:
s = new Shot(getX(), getY() + 20, 3);
break;
}
//添加到容器
shots.add(s);
//启动线程
new Thread(s).start();
}
//当前坦克的方向来继续移动
for (int i = 0; i < 30; i++) {
switch (getDirection()) {
case 0://向上
if (getY() > 0 && !isTouchEnemyTank()){
moveUp();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case 1://向右
if (getX() + 60 < 1000 && !isTouchEnemyTank()){
moveRight();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case 2://向下
if (getY() + 60 < 722 && !isTouchEnemyTank()){
moveDown();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case 3://向左
if (getX() > 0 && !isTouchEnemyTank()){
moveLeft();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
//然后随机的改变方向
int direction = (int) (Math.random() * 4);
setDirection(direction);
//一旦写并发程序,一定要考虑清楚该线程什么时候结束
//被子弹打中了,结束线程
if (!isLive()) {
break;
}
}
}
}

(5)Hero 我方坦克类

package cn.bloghut.pojo;
import cn.bloghut.service.Shot;
import java.util.Vector;
/**
* @Classname Hero
* @Description 自己坦克
* @Date 2022/5/8 8:43
* @Created by 闲言
*/
public class Hero extends Tank{
//定义一个shot对象,表示射击行为
private Shot shot = null;
//可以发射多颗子弹
private Vector<Shot> shots = new Vector<>();
public Hero(int x, int y) {
super(x, y);
}
//射击
public void shotEnemyTank(){
//控制面板上子弹数量
if (shots.size() >= 5){
return;
}
//创建short对象,根据当前hero对象的位置方向来创建shot对象
switch (getDirection()){
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;
}
//把进创建的short放到集合中
shots.add(shot);
//启动shot线程
new Thread(shot).start();
}
public Vector<Shot> getShots() {
return shots;
}
public void setShots(Vector<Shot> shots) {
this.shots = shots;
}
public Shot getShot() {
return shot;
}
public void setShot(Shot shot) {
this.shot = shot;
}
}

(6)Node 记录敌方坦克类(继续上局游戏用)

package cn.bloghut.pojo;
/**
* @Classname Node
* @Description 一个node 对象,表示一个敌人坦克的信息
* @Date 2022/5/9 10:47
* @Created by 闲言
*/
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;
}
}

(7)Tank 坦克父类

package cn.bloghut.pojo;
/**
* @Classname Tank
* @Description 坦克实体
* @Date 2022/5/8 8:43
* @Created by 闲言
*/
public class Tank {
private int x;
private int y;
private int direction;///坦克方向0-上 1-右 2-下 3-左
private int speed = 1;//坦克速度
private boolean isLive = true;
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 getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
//上下左右移动方法
public void moveUp(){
//坦克不能出边界
if (y > 0){
y-=speed;
}
}
public void moveRight(){
if (x + 60 < 1000){
x+=speed;
}
}
public void moveDown(){
if (y + 60 < 722){
y+=speed;
}
}
public void moveLeft(){
if (x > 0){
x-=speed;
}
}
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
}

(8)PlayAudio 播放背景音乐类

package cn.bloghut.service;
import javax.sound.sampled.*;
import java.io.*;
/**
* @author ajun
* Date 2021/7/16
* @version 1.0
* 播放音乐
*/
public class PlayAudio extends Thread {
private String filename;
public PlayAudio(String wavfile) {
String path = System.getProperty("user.dir");
filename = path+"\\"+wavfile;
}
@Override
public void run() {
// 从项目资源目录下加载背景音乐
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(filename)));
} 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();
}
}
}

(9)Recorder 记录游戏数据类

package cn.bloghut.service;
import cn.bloghut.pojo.EnemyTank;
import cn.bloghut.pojo.Node;
import java.io.*;
import java.util.Vector;
/**
* @Classname Recorder
* @Description 用于记录
* @Date 2022/5/9 10:00
* @Created by 闲言
*/
public class Recorder {
//定义变量,记录我方击毁敌人坦克数量
private static int allEnemyTankTotal = 0;
//定义IO 对象,准备写数据到文件中
private static BufferedWriter bufferedWriter = null;
private static BufferedReader bufferedReader = null;
private static String recordFile;
//存储敌人坦克
private static Vector<EnemyTank> enemyTanks = null;
//定义一个Node 的Vector ,用于保存敌人的信息node
private static Vector<Node> nodes = new Vector<>();
static {
String parentPath = System.getProperty("user.dir");
recordFile = parentPath + "\\record.txt";
}
/**
* 该方法在继续上局时调用
* 用于读取record.txt 文件,恢复相关信息
* @return 敌人坦克信息
*/
public static Vector<Node> getNodesAndTanks(){
try {
bufferedReader = new BufferedReader(new FileReader(recordFile));
//击毁数量
allEnemyTankTotal = Integer.parseInt(bufferedReader.readLine());
//获取敌人坦克信息
String dataLine = "";
while ((dataLine = bufferedReader.readLine()) != null){
String[] split = dataLine.split(" ");
if (split.length == 3){
Node node = new Node(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]));
nodes.add(node);
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (bufferedReader != null){
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return nodes;
}
public static void setEnemyTanks(Vector<EnemyTank> enemyTanks) {
Recorder.enemyTanks = enemyTanks;
}
public static int getAllEnemyTankTotal() {
return allEnemyTankTotal;
}
public static void setAllEnemyTankTotal(int allEnemyTankTotal) {
Recorder.allEnemyTankTotal = allEnemyTankTotal;
}
/**
* 当我方坦克击毁一辆敌人坦克,就应当对这个值++
*/
public static void addlEnemyTankTotal(){
allEnemyTankTotal++ ;
}
/**
* 当游戏退出时,我们将 allEnemyTankTotal 保存到
*/
public static void keepRecord(){
try {
bufferedWriter = new BufferedWriter(new FileWriter(recordFile));
bufferedWriter.write(allEnemyTankTotal+"\r\n");
//变量敌人坦克集合,然后根据情况保存
//OOP 编程思想,定义一个属性,通过SET 方法得到敌人的坦克集合
if (enemyTanks.size() > 0){
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
//为了保险,判断一下是否存活
if (enemyTank.isLive()){
//保存enemy坦克信息
String record = enemyTank.getX() + " " + enemyTank.getY() + " " + enemyTank.getDirection();
bufferedWriter.write(record);
bufferedWriter.newLine();
}
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (bufferedWriter != null){
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static String getRecordFile() {
return recordFile;
}
public static void setRecordFile(String recordFile) {
Recorder.recordFile = recordFile;
}
}

(10)Shot 子弹类

package cn.bloghut.service;
/**
* @Classname Shot
* @Description TODO
* @Date 2022/5/8 14:15
* @Created by 闲言
*/
public class Shot implements Runnable{
private int x;//子弹x坐标
private int y;//子弹x坐标
private int direction = 0;//子弹方向
private int speed = 2;//子弹速度
private boolean isLive = true; //子弹是否还存活
@Override
public void run() {//射击行为
while (true){
//线程休眠 50 毫秒
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
//根据方向来改变x ,y坐标
switch (direction){
case 0: //向上
y -= speed;
break;
case 1: //向右
x += speed;
break;
case 2://向下
y += speed;
break;
case 3://向左
x -= speed;
break;
}
System.out.println("x==>"+x+" y===>"+y);
//当子弹碰到敌人坦克时,也应该结束线程
//当子弹移动到面板的边界时,销毁子弹
if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && isLive)){
//设置子弹是否存活状态
isLive = false;
System.out.println("子弹线程退出");
break;
}
}
}
//构造子弹
public Shot(int x, int y, int direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
public int getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
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;
}
@Override
public String toString() {
return "Shot{" +
"x=" + x +
", y=" + y +
", direction=" + direction +
", speed=" + speed +
", isLive=" + isLive +
'}';
}
}

注意:本工程是模块化进行开发的,所以一些文件( 图片、存档路径、音乐)的路径需要改成自己对应。

暂无评论