坦克大战
实现功能
- 绘制我方与敌方坦克
- 键盘控制我方坦克移动与发射
- 敌方发射子弹
- 子弹打到坦克,坦克会消失并且爆炸
- 敌方坦克自由移动且自由发射
- 我方坦克发射多颗子弹,并且设置同时存在的子弹数量上限
- 防止敌方坦克重叠并且设置移动范围
- 记录成绩,并且按照记录的信息继续上一局游戏
本次项目使用了:面向对象 OOP IO编程 文件编程 算法 GUI 多线程 线程知识
一、编写各种类
Tank类
- 坦克类是我放坦克和敌方坦克的父类,包含了坦克的横坐标,纵坐标,方向与速度,还定义了坦克上下左右移动的方法
package Tank2.Tank;
import javax.swing.*;
public class Tank extends JFrame {
private int x;//坦克的横坐标
private int y;//坦克的纵坐标
private int diret;//坦克的方向
private int speed = 1;//控制速度
boolean islive = true;
public Tank(int x, int y ) {
this.x = x;
this.y = y;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
//上右下左移动方法
public void moveUp() {
if (y > 0){
y -= speed;
}
}
public void moveRight() {
if (x + 60 < 1000){
x += speed;
}
}
public void moveDown() {
if (y + 60 < 750){
y += speed;
}
}
public void moveLeft() {
if (x > 0){
x -= speed;
}
}
public int getDiret() {
return diret;
}
public void setDiret(int diret) {
this.diret = diret;
}
@Override
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
@Override
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
Shot类
- 子弹类,同样定义了横纵坐标还有方向与速度,但也加入了判断子弹是否还存活的布尔型,为后面子弹打中坦克会消亡做功能铺垫
- 同时定义了移动的线程,因为子弹要一直动,所以要用到线程
- 同时还加入了什么时候将子弹生命置为false的判断语句
package Tank2.Tank;
public class Shot implements Runnable{
int x; //子弹x坐标
int y; //子弹y坐标
int direct = 0; //子弹方向
int speed = 3; //子弹的速度
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) {
//休眠 50毫秒
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;
}
//当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁),
//判断子弹是否存活,当子弹打到坦克时会被置为flase,线程随之退出
if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750 && isLive) ) {
isLive = false;
break;
}
}
}
}
enemyTank类
- 敌方坦克的类,继承了Tank父类,因为要一直动所以同样加入了线程
- 本类多加了Shot集合,用来存放敌方坦克发射的子弹,也加入了判断是否死亡的布尔型
- 这里提供一个方法,可以将MyPanel 的成员 Vector enemyTanks = new Vector<>();
//设置到 enemyTank 的成员 enemyTanks - 提供了判断敌方坦克重叠的方法
- 提供了坦克发射子弹的方法可以设置子弹上限,还有坦克自己随机移动的方法
package Tank2.Tank;
import java.util.Vector;
public class enemyTank extends Tank implements Runnable{
//类里创建Shot集合
Vector<Shot> shots = new Vector<>();
//判断敌方坦克是否存在
boolean islive = true;
//增加成员,enemyTank 可以得到敌人坦克的Vector
Vector<enemyTank> enemyTanks = new Vector<>();
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.getDiret()) {
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.getDiret() == 0 || enemyTank.getDiret() == 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.getDiret() == 1 || enemyTank.getDiret() == 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.getDiret() == 0 || enemyTank.getDiret() == 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.getDiret() == 1 || enemyTank.getDiret() == 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.getDiret() == 0 || enemyTank.getDiret() == 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.getDiret() == 1 || enemyTank.getDiret() == 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.getDiret() == 0 || enemyTank.getDiret() == 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.getDiret() == 1 || enemyTank.getDiret() == 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() < 15, 创建一颗子弹,放入到
//shots集合,并启动
if (islive && shots.size() < 15) {
//一部坦克可以同时存在15颗子弹
Shot s = null;
//判断坦克的方向,创建对应的子弹
switch (getDiret()) {
case 0:
s = new Shot(getX() + 20, getY(), 0);
break;