day03-2-应用线程02

JavaGUI-坦克大战03-2

7.线程的应用02

7.3.坦克大战4.0版

坦克大战4.0版

增加功能:

功能1.让敌人的坦克也能够发射子弹(可以有多个子弹)

功能2.当我方坦克集中敌人坦克时,敌人的坦克就消失,如果能做出爆炸的效果更好

功能3.让敌人的坦克也可以自由随机地上下左右移动

功能4.控制我方坦克和敌人坦克在规定的范围内移动

7.3.1功能1:敌方发射子弹

功能1思路

  1. 在敌人坦克类使用Vector保存多个Shot
  2. 当每创建一个敌人坦克时,就给该敌人坦克初始化一个Shot对象,同时启动Shot线程
  3. 在绘制敌人坦克时,需要遍历敌人坦克对象Vector,绘制所有的子弹,当子弹isLive==false时,就从Vector移除

EnemyTank:

package li.TankGame.version04;
import java.util.Vector;
public class EnemyTank extends Tank {
//在敌人坦克类使用Vector保存多个Shot
Vector<Shot> shots = new Vector<>();
public EnemyTank(int x, int y) {
super(x, y);
}
}

MyPanel:在创建敌人坦克的时候,每初始化一个敌人坦克,就创建并初始化一个shot对象,将该shot对象加入到shots集合中,然后启动这个shot对象线程

package li.TankGame.version04;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;
/**
* @author
* @version 4.0
* 坦克大战的绘图区域
*/
//为了监听键盘事件,要实现 KeyListener
//为了让Panel不停地重绘子弹,需要将MyPanel实现Runnable,
// 当做一个线程使用(因为需要不停地重绘子弹的图案)
public class MyPanel extends JPanel implements KeyListener, Runnable {
//定义我的坦克
Hero hero = null;
//定义敌方坦克,放入到Vector集合中
Vector<EnemyTank> enemyTanks = new Vector<>();
int enemyTankNum = 3;//初始化坦克数量
public MyPanel() {
hero = new Hero(100, 100);//初始化自己的坦克
//hero.setSpeed(5); //改变坦克的速度
//初始化敌人的坦克
for (int i = 0; i < enemyTankNum; i++) {
//创建一个敌人的坦克
EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);
//初始化敌人坦克方向向下
enemyTank.setDirect(2);
//给该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);
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 700, 550);//填充矩形,默认为黑色
//画出自己的坦克-封装方法
drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
//画出hero发射的子弹
//如果子弹对象不为空,并且处于存活状态(即没有超出边界)
if (hero.shot != null && hero.shot.isLive) {
System.out.println("hero的子弹被绘制");
g.draw3DRect(hero.shot.x, hero.shot.y, 2, 2, false);
}
//画出敌人的坦克,遍历Vector
for (int i = 0; i < enemyTanks.size(); i++) {
//取出敌人的坦克
EnemyTank enemyTank = enemyTanks.get(i);
drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 0);
//画出enemyTank所有子弹
for (int j = 0; j < enemyTank.shots.size(); j++) {
//enemyTank.shots.size()是当前的enemy对象的shots集合的大小
//取出子弹
Shot shot = enemyTank.shots.get(j);
//绘制子弹
if (shot.isLive) {//shot.isLive==true
g.draw3DRect(shot.x, shot.y, 2, 2, false);
}else{
//从Vector移除子弹shot对象
enemyTank.shots.remove(shot);
}
}
}
}
/**
* 编写方法,画出坦克
*
* @param x 坦克的左上角横坐标
* @param 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;
}
//根据坦克坐标方向,来绘制对应方向的坦克
//direct表示方向(0:向上 1:向右 2:向下 3:向左)
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://表示向右
//注意:以坦克左上角的(x,y)坐标为参考画图案
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) {
}
//控制方向--处理 WSAD 键按下的情况
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {//按下W键-向上
//改变坦克的方向
hero.setDirect(0);
//修改坦克的坐标
hero.moveUp();
} else if (e.getKeyCode() == KeyEvent.VK_D) {//按下D键-向右
hero.setDirect(1);
hero.moveRight();
} else if (e.getKeyCode() == KeyEvent.VK_S) {//按下S键-向下
hero.setDirect(2);
hero.moveDown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {//按下A键-向左
hero.setDirect(3);
hero.moveLeft();
}
//如果用户按下j键,hero就发射子弹
if (e.getKeyCode() == KeyEvent.VK_J) {
hero.shotEnemyTank();
}
//让面板重绘
this.repaint();
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void run() {//每个100毫秒,重绘区域,刷新绘图区域,子弹就移动
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.repaint();
}
}
}
image-20220906203403094

7.3.2功能2:敌方坦克消失

功能2:当我方坦克集中敌人坦克时,敌人的坦克就消失,如果能做出爆炸的效果更好

功能2思路:

  1. 关键点在于判断子弹怎么样算击中敌人:即坦克的击中范围的坐标
  2. 在run()方法中不断地去判断是否击中敌人
  3. 然后在调用drawTank方法前也进行相应的判断,如果敌人未被击中,即enemy.isLive = true,就调用drawTank方法
  4. 关于子弹线程的退出问题:之前只是判断了子弹超出面板时会结束线程。现增加新的线程停止条件:当子弹击中敌方坦克时,该子弹的线程也应结束

更改的类:Shot、EnemyTank、MyPanel:

Shot:更改了子弹线程结束的条件

package li.TankGame.version04;
/**
* @author
* @version 4.0
* 射击子弹
*/
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) {
//休眠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;
}
//测试。输出坐标
System.out.println("x=" + x + "y=" + y);
//如果子弹移动到面板边界时,就应该销毁(把启动的子弹的线程销毁)
//当子弹碰到敌人坦克时,也应该结束线程
if (!(x >= 0 && x <= 700 && y <= 550 && y >= 0 && isLive)) {//如果不符合条件
System.out.println("子弹线程退出...");
isLive = false;
break;//线程退出
}
}
}
}

EnemyTank:增加了isLive 属性

package li.TankGame.version04;
import java.util.Vector;
public class EnemyTank extends Tank {
//在敌人坦克类使用Vector保存多个Shot
Vector<Shot> shots = new Vector<>();
boolean isLive = true;
public EnemyTank(int x, int y) {
super(x, y);
}
}

MyPanel:修改了:

  1. 在paint()方法中修改绘出敌人坦克的方法,当敌人坦克是活的(未被击中),才将其画出,同时循环取出该enemyTank对象shots集合中的所有子弹,将其子弹画出,如果该子弹超出画板边界:shot.isLive=false则从该从enemyTank对象的Vector集合shots中移除子弹shot对象

  2. 编写一个hitTank()方法,判定击中敌人的条件,判定成功则将该子弹对象的isLive 设为 false(结束子弹进程); 将击中的敌人坦克对象的isLive属性也设为false(不再绘出该坦克)

image-20220906212729273 image-20220906212829650
  1. 在run()方法中的while循环中,增加判断是否击中敌人坦克的语句,进行相应操作(因为子弹的坐标在一直变化,所以要一直判断),注意敌人坦克被击中之后要在相应集合中删除该敌人对象。
package li.TankGame.version04;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;
/**
* @author
* @version 4.0
* 坦克大战的绘图区域
*/
//为了监听键盘事件,要实现 KeyListener
//为了让Panel不停地重绘子弹,需要将MyPanel实现Runnable,
// 当做一个线程使用(因为需要不停地重绘子弹的图案)
public class MyPanel extends JPanel implements KeyListener, Runnable {
//定义我的坦克
Hero hero = null;
//定义敌方坦克,放入到Vector集合中
Vector<EnemyTank> enemyTanks = new Vector<>();
int enemyTankNum = 3;//初始化坦克数量
public MyPanel() {
hero = new Hero(100, 100);//初始化自己的坦克
//hero.setSpeed(5); //改变坦克的速度
//初始化敌人的坦克
for (int i = 0; i < enemyTankNum; i++) {
//创建一个敌人的坦克
EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);
//初始化敌人坦克方向向下
enemyTank.setDirect(2);
//给该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);
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 700, 550);//填充矩形,默认为黑色
//画出自己的坦克-封装方法
drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
//画出hero发射的子弹
//如果子弹对象不为空,并且处于存活状态(即没有超出边界)
if (hero.shot != null && hero.shot.isLive) {
System.out.println("hero的子弹被绘制");
g.draw3DRect(hero.shot.x, hero.shot.y, 2, 2, false);
}
//画出敌人的坦克,遍历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++) {
//enemyTank.shots.size()是当前的enemy对象的shots集合的大小
//取出子弹
Shot shot = enemyTank.shots.get(j);
//绘制子弹
if (shot.isLive) {//shot.isLive==true
g.draw3DRect(shot.x, shot.y, 2, 2, false);
} else {
//从Vector移除子弹shot对象
enemyTank.shots.remove(shot);
}
}
}
}
}
/**
* 编写方法,画出坦克
*
* @param x 坦克的左上角横坐标
* @param 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;
}
//根据坦克坐标方向,来绘制对应方向的坦克
//direct表示方向(0:向上 1:向右 2:向下 3:向左)
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://表示向右
//注意:以坦克左上角的(x,y)坐标为参考画图案
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 static void hitTank(Shot s, EnemyTank enemyTank) {
//判断s击中坦克
switch (enemyTank.getDirect()) {
case 0://敌人坦克向上(向上和向下的击中范围一样)
case 2://敌人坦克向下
if (s.x > enemyTank.getX() && s.y < enemyTank.getX() + 40
&& s.y > enemyTank.getY() && s.y < enemyTank.getY() + 60) {
s.isLive = false;
enemyTank.isLive = false;
//当子弹击中敌人后,将enemyTank从Vector中删除
enemyTanks.remove(enemyTank);
}
case 1://右
case 3://左
if (s.x > enemyTank.getX() && s.y < enemyTank.getX() + 60
&& s.y > enemyTank.getY() && s.y < enemyTank.getY() + 40) {
s.isLive = false;
enemyTank.isLive = false;
//当子弹击中敌人后,将enemyTank从Vector中删除
enemyTanks.remove(enemyTank);
}
break;
}
}
@Override
public void keyTyped(KeyEvent e) {
}
//控制方向--处理 WSAD 键按下的情况
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {//按下W键-向上
//改变坦克的方向
hero.setDirect(0);
//修改坦克的坐标
hero.moveUp();
} else if (e.getKeyCode() == KeyEvent.VK_D) {//按下D键-向右
hero.setDirect(1);
hero.moveRight();
} else if (e.getKeyCode() == KeyEvent.VK_S) {//按下S键-向下
hero.setDirect(2);
hero.moveDown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {//按下A键-向左
hero.setDirect(3);
hero.moveLeft();
}
//如果用户按下j键,hero就发射子弹
if (e.getKeyCode() == KeyEvent.VK_J) {
hero.shotEnemyTank();
}
//让面板重绘
this.repaint();
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void run() {//每个100毫秒,重绘区域,刷新绘图区域,子弹就移动
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//判断是否击中敌人坦克
if (hero.shot != null && hero.shot.isLive) {//如果当前我方子弹不为空且子弹还存活
//就遍历敌人所有的坦克
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
hitTank(hero.shot, enemyTank);
}
}
this.repaint();
}
}
}
image-20220906215552714

7.3.3功能2plus:坦克爆炸

功能2完善:当子弹击中坦克时,做出爆炸效果

思路:

  1. 新建一个炸弹Bomb类

  2. 在MyPanel里定义一个Vector集合,用于存放Bomb对象

  3. 在hitTank方法中判断,当子弹击中坦克时就加入一个Bomb对象到bombs集合里(这里将hitTank方法改为非静态方法)

  4. 想要显示出炸弹的效果图,就要在paint方法里面画出,如果bombs集合中有炸弹对象,就画出来

  5. 将爆炸的素材图片放到out目录的根目录下面

image-20220907155543131

Bomb:

package li.TankGame.version04;
/**
* @author
* @version 4.0
* 炸弹
*/
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;
}
}
}

MyPanel:

package li.TankGame.version04;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;
/**
* @author
* @version 4.0
* 坦克大战的绘图区域
*/
//为了监听键盘事件,要实现 KeyListener
//为了让Panel不停地重绘子弹,需要将MyPanel实现Runnable,
// 当做一个线程使用(因为需要不停地重绘子弹的图案)
public class MyPanel extends JPanel implements KeyListener, Runnable {
//定义我的坦克
Hero hero = null;
//定义敌方坦克,放入到Vector集合中
Vector<EnemyTank> enemyTanks = new Vector<>();
//定义一个Vector,用于存放炸弹
//说明:当子弹击中坦克时就加入一个Bomb对象到bombs集合里
Vector<Bomb> bombs = new Vector<>();
int enemyTankNum = 3;//初始化坦克数量
//定义三张炸弹图片,用于显示爆炸效果
Image image1 = null;
Image image2 = null;
Image image3 = null;
public MyPanel() {
hero = new Hero(100, 100);//初始化自己的坦克
//hero.setSpeed(5); //改变坦克的速度
//初始化敌人的坦克
for (int i = 0; i < enemyTankNum; i++) {
//创建一个敌人的坦克
EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);
//初始化敌人坦克方向向下
enemyTank.setDirect(2);
//给该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);
}
//初始化图片对象
image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb1.png"));
image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb2.png"));
image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb3.png"));
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 700, 550);//填充矩形,默认为黑色
//画出自己的坦克-封装方法
drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
//画出hero发射的子弹
//如果子弹对象不为空,并且处于存活状态(即没有超出边界)
if (hero.shot != null && hero.shot.isLive) {
System.out.println("hero的子弹被绘制");
g.draw3DRect(hero.shot.x, hero.shot.y, 2, 2, false);
}
//如果bombs集合中有炸弹对象,就画出来
for (int i = 0; i < bombs.size(); i++) {
try {
Thread.sleep(50);//先休眠50毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
//取出炸弹
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++) {
//enemyTank.shots.size()是当前的enemy对象的shots集合的大小
//取出子弹
Shot shot = enemyTank.shots.get(j);
//绘制子弹
if (shot.isLive) {//shot.isLive==true
g.draw3DRect(shot.x, shot.y, 2, 2, false);
} else {
//从Vector移除子弹shot对象
enemyTank.shots.remove(shot);
}
}
}
}
}
/**
* 编写方法,画出坦克
*
* @param x 坦克的左上角横坐标
* @param 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;
}
//根据坦克坐标方向,来绘制对应方向的坦克
//direct表示方向(0:向上 1:向右 2:向下 3:向左)
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://表示向右
//注意:以坦克左上角的(x,y)坐标为参考画图案
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 hitTank(Shot s, EnemyTank enemyTank) {
//判断s击中坦克
switch (enemyTank.getDirect()) {
case 0://敌人坦克向上(向上和向下的击中范围一样)
case 2://敌人坦克向下
if (s.x > enemyTank.getX() && s.y < enemyTank.getX() + 40
&& s.y > enemyTank.getY() && s.y < enemyTank.getY() + 60) {
s.isLive = false;
enemyTank.isLive = false;
//当子弹击中敌人后,将enemyTank从Vector中删除
enemyTanks.remove(enemyTank);
//创建一个Bomb对象,加入到bombs集合中
Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
bombs.add(bomb);
}
case 1://右
case 3://左
if (s.x > enemyTank.getX() && s.y < enemyTank.getX() + 60
&& s.y > enemyTank.getY() && s.y < enemyTank.getY() + 40) {
s.isLive = false;
enemyTank.isLive = false;
//当子弹击中敌人后,将enemyTank从Vector中删除
enemyTanks.remove(enemyTank);
//创建一个Bomb对象,加入到bombs集合中
Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
bombs.add(bomb);
}
break;
}
}
@Override
public void keyTyped(KeyEvent e) {
}
//控制方向--处理 WSAD 键按下的情况
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {//按下W键-向上
//改变坦克的方向
hero.setDirect(0);
//修改坦克的坐标
hero.moveUp();
} else if (e.getKeyCode() == KeyEvent.VK_D) {//按下D键-向右
hero.setDirect(1);
hero.moveRight();
} else if (e.getKeyCode() == KeyEvent.VK_S) {//按下S键-向下
hero.setDirect(2);
hero.moveDown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {//按下A键-向左
hero.setDirect(3);
hero.moveLeft();
}
//如果用户按下j键,hero就发射子弹
if (e.getKeyCode() == KeyEvent.VK_J) {
hero.shotEnemyTank();
}
//让面板重绘
this.repaint();
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void run() {//每个100毫秒,重绘区域,刷新绘图区域,子弹就移动
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//判断是否击中敌人坦克
if (hero.shot != null && hero.shot.isLive) {//如果当前我的子弹不为空并且子弹还存活
//就遍历敌人所有的坦克
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
hitTank(hero.shot, enemyTank);
}
}
this.repaint();
}
}
}
image-20220907160319411
posted @   一刀一个小西瓜  阅读(62)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示