Java-坦克攻击(敌方坦克消失)
实现过程
- 子弹类(Bullet)
/**
* 子弹类
* @author: SEA
* @date: 2023/3/18
*/
public class Bullet {
//子弹坐标和发射方向
int x;
int y;
int direction;
int speed = 5;//子弹初始速度为 5
boolean isLive = false;//子弹是否有效
public Bullet(int x, int y, int direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
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;
}
}
- 普通坦克类(Tank)
- 新增属性:
- (1)坦克是否存活isLive;
- 新增方法:
- (1)setLive() 和 isLive();
- 新增属性:
import java.util.Vector;
/**
* 坦克
* @author: SEA
* @date: 2023/3/2
*/
public class Tank{
private int x;//坦克的横坐标
private int y;//坦克的纵坐标
private int direction;//坦克的朝向:0 => 向上 ,1 => 向下 ,2 => 向左 , 3 => 向右
private int speed = 5;//坦克速度
private Bullet bullet;//坦克子弹
private boolean isLive = true;//坦克是否有效(是否被子弹击中)
private Vector<Bullet> bullets = new Vector<Bullet>();//子弹集合,使坦克可以发射多颗子弹并在panel绘制
public Tank(int x, int y) {
this.x = x;
this.y = y;
}
......
public boolean isLive() {
return isLive;
}
public void setLive(boolean live) {
isLive = live;
}
public void attack(){//坦克攻击
......
}
public void attack(Vector<EnemyTank> enemyTanks){//坦克攻击
......
}
}
-
子弹发射:
- 修改:
- (1)增加子弹击中时销毁子弹的判断;
- (2)考虑到是否击中敌方坦克判断属于玩家坦克特有,因此将判断代码放到了GamePanel类中;
import java.util.Vector; /** * 子弹发射(多线程) * @author: SEA * @date: 2023/3/18 */ public class TankAttackThread implements Runnable{ Bullet bullet; Vector<EnemyTank> enemyTanks = new Vector<EnemyTank>(); public TankAttackThread(Bullet bullet) { this.bullet = bullet; } public TankAttackThread(Bullet bullet, Vector<EnemyTank> enemyTanks) { this.bullet = bullet; this.enemyTanks = enemyTanks; } @Override public void run() { while(true){ try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } switch (this.bullet.direction){ case 0: this.bullet.y -= this.bullet.speed; break; case 1: this.bullet.y += this.bullet.speed; break; case 2: this.bullet.x -= this.bullet.speed; break; case 3: this.bullet.x += this.bullet.speed; break; } System.out.println("==== [" + this.bullet.x + ", " + this.bullet.y + "] ===="); //到达边界以及子弹击中,销毁子弹 if((!this.bullet.isLive()) || this.bullet.x < -3 || this.bullet.y < -3 || this.bullet.x > 1003 || this.bullet.y > 803 ){ this.bullet.setLive(false); break; } } } }
- 修改:
-
坦克大战绘图区域:
-
修改:
- (1)为了测试子弹是否击中敌方坦克,将敌方坦克的方向修改为各个方向都有;
- (2)绘制玩家坦克的子弹时,增加子弹是否存活判断;
- (3)绘制敌方坦克时,增加敌方坦克是否存活判断;
-
新增:
- (1)增加玩家坦克子弹是否击中敌方坦克的判断函数EnemyTank isHitted(Bullet bullet, Vector enemyTanks);
- (2)在每次重绘前遍历玩家子弹集合和敌方坦克集合,判断玩家坦克是否击中任意敌方坦克;(双重遍历)
-
删除:
- (1)标题的绘制改为设置游戏窗口标题
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;
/**
* 坦克大战绘图区域
* @author: SEA
* @date: 2023/3/2
*/
class GamePanel extends JPanel implements KeyListener, Runnable{//画板
//定义玩家的坦克
HeroTank heroTank = null;
//考虑多线程问题,使用Vector来保存敌方坦克
Vector<EnemyTank> enemyTanks = null;
int enemyTankSize = 5;
public GamePanel() {
heroTank = new HeroTank(250, 400);//初始化玩家坦克
enemyTanks = new Vector<EnemyTank>();
for (int i = 0; i < enemyTankSize; i++) {
EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 100);
enemyTank.setDirection(i % 4);
//让敌方坦克也能攻击
enemyTank.attack();
enemyTanks.add(enemyTank);
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
//游戏窗口背景
g.setColor(Color.BLACK);
g.fillRect(0, 0, 1000, 800);
//画出坦克-封装成方法
drawTank(heroTank.getX(), heroTank.getY(), g, heroTank.getDirection(), 0);
//绘制玩家坦克的子弹
for (int i = 0; i < heroTank.getBullets().size(); i++) {
Bullet bullet = heroTank.getBullets().get(i);//取出子弹
if(bullet!=null && bullet.isLive())
drawBullet(bullet.x, bullet.y, g, 0);//绘制
else
heroTank.getBullets().remove(bullet);//子弹超出边界,移除
}
//绘制敌方坦克以及子弹
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
if(enemyTank.isLive())
drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 1);
for (int j = 0; j < enemyTank.getBullets().size(); j++) {//这里应使用for遍历,不然会爆并发错误
Bullet bullet = enemyTank.getBullets().get(j);//取出子弹
if(bullet != null && bullet.isLive)
drawBullet(bullet.x, bullet.y, g, 1);//绘制
else
enemyTank.getBullets().remove(bullet);//子弹超出边界,移除
}
}
}
/**
*
* @param x 坦克左上方x轴坐标
* @param y 坦克左上方y轴坐标
* @param g 画笔
* @param direction 坦克的朝向:0 => 向上 ,1 => 向下 ,2 => 向左 , 3 => 向右
* @param type 坦克类型:0 => 玩家坦克,1 => 敌方坦克
*/
public void drawTank(int x, int y, Graphics g, int direction, int type){
......
}
public void drawBullet(int x, int y, Graphics g, int type){
......
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
......
}
@Override
public void keyReleased(KeyEvent e) {
}
private EnemyTank isHitted(Bullet bullet, Vector<EnemyTank> enemyTanks) {
int enemyTank_x_left;//敌方坦克的左边缘x坐标
int enemyTank_x_right;//敌方坦克的右边缘x坐标
int enemyTank_y_top;//敌方坦克的上边缘y坐标
int enemyTank_y_bottom;//敌方坦克的下边缘y坐标
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank cur_enemyTank = enemyTanks.get(i);
if(cur_enemyTank.getDirection() == 0 || cur_enemyTank.getDirection() == 1){
enemyTank_y_bottom = cur_enemyTank.getY() + 60;
enemyTank_x_right = cur_enemyTank.getX() + 44;
}
else {
enemyTank_y_bottom = cur_enemyTank.getY() + 44;
enemyTank_x_right = cur_enemyTank.getX() + 60;
}
enemyTank_x_left = cur_enemyTank.getX();
enemyTank_y_top = cur_enemyTank.getY();
switch (bullet.direction){//发射子弹的方向
case 0://向上
if(bullet.x+6 >= enemyTank_x_left && bullet.x + 6 <= enemyTank_x_right && bullet.y <= enemyTank_y_bottom)
return cur_enemyTank;
break;
case 1://向下
if(bullet.x+6 >= enemyTank_x_left && bullet.x + 6 <= enemyTank_x_right && bullet.y+6 >= enemyTank_y_top)
return cur_enemyTank;
break;
case 2://向左
if(bullet.y+6 <= enemyTank_y_bottom && bullet.y+6 >= enemyTank_y_top && bullet.x+6 <= enemyTank_x_right)
return cur_enemyTank;
break;
case 3://向右
if(bullet.y+6 <= enemyTank_y_bottom && bullet.y+6 >= enemyTank_y_top && bullet.x <= enemyTank_x_left)
return cur_enemyTank;
break;
}
}
return null;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(heroTank.getBullets() != null){
for (int i = 0; i < heroTank.getBullets().size(); i++) {
Bullet cur_bullet = heroTank.getBullets().get(i);
if (cur_bullet != null && cur_bullet.isLive()){
//是否击中敌方坦克判断
EnemyTank hittedTank = isHitted(cur_bullet, enemyTanks);
if (cur_bullet.isLive() && hittedTank != null) {
System.out.println("======击中了["+ hittedTank.getX() + ", " + hittedTank.getY() +"]=======");
//销毁被击中的坦克以及该子弹
hittedTank.setLive(false);
cur_bullet.setLive(false);
enemyTanks.remove(hittedTank);
heroTank.getBullets().remove(cur_bullet);
}
}
}
}
this.repaint();
}
}
}
实现效果
待优化
- 子弹击中敌方坦克后:
- 1.爆炸效果;
- 敌方坦克需要能够随机移动;
- 坦克移动范围未限制,可能移动至边界外;