Java坦克大战(1)
Java实现坦克大战
主要功能
- 键盘监听,接受游戏者操作
- 坦克在游戏界面中移动,敌方随机移动
- 坦克发射子弹
- 坦克遇到墙体不能穿过
- 坦克互相不能重叠
- 坦克爆炸效果
项目结构
- AePlayWave 播放音乐类
- Bomb 爆炸特效
- EnemyTank 敌方坦克
- Hero 我方坦克
- MyPanel 绘制和各种实现,各个事件的监听
- Node 保存关闭后的坦克位置的中介
- Recorder 保存退出后的坦克的位置和玩家的成绩信息以及继续游戏时,读取各个坦克位置
- Shot 子弹
- Tank 父类
实现
Tank.java
package com.gqz.tankgame5;
/**
* @author gqz
* @version 1.0
*/
public class Tank {
private int x;//横坐标
private int y;//纵坐标
private int direct;//坦克方向 0上1右2下3左
private int speed;//坦克移动的速度
boolean isLive = true;
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
//上右下左移动
public void moveUp() {
y -= speed;
}
public void moveRight() {
x += speed;
}
public void moveLeft() {
x -= speed;
}
public void moveDown() {
y += speed;
}
public int getDirect() {
return direct;
}
public void setDirect(int direct) {
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 Tank(int x, int y) {
this.x = x;
this.y = y;
}
}
Hero.java
package com.gqz.tankgame5;
import java.util.Vector;
/**
* @author gqz
* @version 1.0
*/
public class Hero extends Tank {
Shot shot = null;//表示射击行为
//可以发射多颗子弹
Vector<Shot> shots = new Vector<>();
public Hero(int x, int y) {
super(x, y);
}
//射击
public void shotEnemyTank() {
//控制子弹数量
if (shots.size() == 100) {
return;
}
//创建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.add(shot);
//启动线程
new Thread(shot).start();
}
}
EnemyTank.java
package com.gqz.tankgame5;
import java.util.Vector;
/**
* @author gqz
* @version 1.0
*/
@SuppressWarnings({"all"})
public class EnemyTank extends Tank implements Runnable {
//最开始没有使用hero的isLive属性,故没有在Tank中设置isLive,后来设置了后EnemyTank
//的isLive属性需要注释掉,不然hitTank中的isLive属性会使用EnemyTank的导致
//敌方坦克只有爆炸效果但不会消失,因为使用的是Tank的isLive
//boolean isLive = true;
//在敌人坦克类,使用Vector保存多个Shot对象
Vector<Shot> shots = new Vector<>();
//
Vector<EnemyTank> enemyTanks = new Vector<>();
//提供一个方法,将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() + 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() + 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 (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() + 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.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()
&& 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.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() + 60
&& this.getY() + 60 >= enemyTank.getY()
&& this.getY() + 60 <= enemyTank.getY() + 40) {
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()
&& 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.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() + 60
&& this.getY() + 40 >= enemyTank.getY()
&& this.getY() + 40 <= enemyTank.getY() + 40) {
return true;
}
}
}
}
break;
}
return false;
}
// //编写方法,判断坦克是否相撞
// public void isTouch() {
// switch (this.getDirect()) {
// case 0://上
// //让当前的敌人坦克和其他所有敌人坦克比较
// for (int i = 0; i < enemyTanks.size(); i++) {
// //从Vector中取出一辆敌人坦克
// EnemyTank enemyTank = enemyTanks.get(i);
// //不和自己比较
// if (enemyTank != this) {
// //如果敌人坦克是上下
// if (enemyTank.getDirect() == 0 || enemyTank.getDirect() == 2) {
//
// }
// //如果敌人坦克是左右
// if (enemyTank.getDirect() == 1 || enemyTank.getDirect() == 3) {
//
// }
// }
// }
// break;
// case 1://右
// break;
// case 2://下
// break;
// case 3://左
// break;
// }
// }
public EnemyTank(int x, int y) {
super(x, y);
}
@Override
public void run() {
while (true) {
//如果shots.size == 0,创建一颗子弹,放入到集合中并启动
if (isLive && shots.size() < 2) {
Shot s = null;
switch (getDirect()) {
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);
case 3:
s = new Shot(getX(), getY() + 20, 3);
}
shots.add(s);
//启动
new Thread(s).start();
}
//根据坦克的方向继续移动
switch (getDirect()) {
case 0://向上
for (int i = 0; i < 30; i++) {
if (getY() > 0 && !isTouchEnemyTank()) {
moveUp();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 1://向右
for (int i = 0; i < 30; i++) {
if (getX() + 60 < 1000 && !isTouchEnemyTank()) {
moveRight();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 2://向下
for (int i = 0; i < 30; i++) {
if (getY() + 60 < 750 && !isTouchEnemyTank()) {
moveDown();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 3://向左
for (int i = 0; i < 30; i++) {
if (getX() > 0 && !isTouchEnemyTank()) {
moveLeft();
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
}
//随机改变坦克方向
setDirect((int) (Math.random() * 4));
if (!isLive) {
break;
}
}
}
}
Bomb.java
package com.gqz.tankgame5;
/**
* @author gqz
* @version 1.0
*/
public class Bomb {
int x, y;//炸弹坐标
boolean isLive = true;//炸弹是否还存活
int life = 9;//炸弹生命周期
public Bomb(int x, int y) {
this.x = x;
this.y = y;
}
public void lifeDown() {//配合出现爆炸效果
if (life > 0) {
life--;
} else {
isLive = false;
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?