Java学习Day15 坦克大战ver0.5
新增功能 自由发射子弹 我方爆炸
Game方法
/*
1.我方坦克在发射的子弹消亡后,才能发射新的子弹.=>
扩展(发多颗子弹怎么办.控制在我们的面板上,最多只有5颗)
2.让敌人坦克发射的子弹消亡后,可以再发射子弹
3.当敌人的坦克击中我方坦克时,我方坦克消失,并出现爆炸效果.
*/
public class TankGame05 extends JFrame {
//定义一个面板
MyPanel mp = null;
public static void main(String[] args) {
TankGame05 tankGame05 = new TankGame05();
}
public TankGame05() {
mp = new MyPanel();
Thread thread = new Thread(mp);
thread.start();
//启动mp
this.add(mp);//加入游戏的绘图区域
this.setSize(1000, 750);
this.addKeyListener(mp);//增加一个监听
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
}
MyPanel 我方爆炸
只需要写一个方法判断敌方子弹是否打到我方 在run方法里调用即可
//绘图
//为了不停地重绘子弹 需要让MyPanel成为线程
public class MyPanel extends JPanel implements KeyListener, Runnable {
//定义p1 tank
P1 p1 = null;
// Bullet bullet = null;
//定义enemy tank
Vector<EnemyTank> enemyTanks = new Vector<>();
int enemyTankSize = 3;
//定义一个集合 存放炸弹
Vector<Boom> booms = new Vector<>();
Image image1 = null;
Image image2 = null;
Image image3 = null;
public MyPanel() {
p1 = new P1(100, 100);//初始化自己坦克
p1.setSpeed(4);
//初始化敌人tank
for (int i = 0; i < enemyTankSize; i++) {
// enemyTanks.add(new EnemyTank(300 * (i + 1), 0));
//也可以在这里初始化tank方向
//创建一个敌人tank
EnemyTank enemyTank = new EnemyTank((300 * (i + 1)), 0);
//设置方向
enemyTank.setDirection(2);
enemyTank.setSpeed(1);
//启动
new Thread(enemyTank).start();
//给加入的tank加入一个bullet
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 80, enemyTank.getDirection());
enemyTank.shots.add(shot);
//加入一个tank
new Thread(shot).start();
enemyTanks.add(enemyTank);
}
//初始化图形
image1 = Toolkit.getDefaultToolkit().getImage("out/production/Hello/com/yuhuw/tankwar/1.png");
image2 = Toolkit.getDefaultToolkit().getImage("out/production/Hello/com/yuhuw/tankwar/2.png");
image3 = Toolkit.getDefaultToolkit().getImage("out/production/Hello/com/yuhuw/tankwar/3.png");
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(0, 0, 1000, 750);//填充矩形 默认是黑色
//画出p1的tank
if (p1 !=null&&p1.isLive) {
drawTank(p1.getX(), p1.getY(), g, p1.getDirection(), 0);
//画出enemy的tank
}
/*
1.enemy tank可以单开一个类继承tank并且有自己的属性和方法
2.敌人tank数量多且多线程考虑安全使用vector
3.遍历取出所有集合的tank
*/
for (int i = 0; i < enemyTanks.size(); i++) {
//取出tank
EnemyTank enemyTank = enemyTanks.get(i);
//判断当前tank是否存活
if (enemyTank.isLive) {
drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 1);
for (int j = 0; j < enemyTank.shots.size(); j++) {
//取出bullet
Shot shot = enemyTank.shots.get(j);
//画出bullet
if (shot.isLive) {
g.fill3DRect(shot.x, shot.y, 2, 2, false);
} else {
//移除bullet
enemyTank.shots.remove(shot);
}
}
}
this.repaint();
}
//画出P1的bullet
for (int i = 0; i < p1.shots.size(); i++) {
if (p1.shots.get(i) != null && p1.shots.get(i).isLive) {
g.setColor(Color.yellow);
g.fill3DRect(p1.shots.get(i).x, p1.shots.get(i).y, 2, 2, false);
} else {
p1.shots.remove(i);
}
}
//画出爆炸效果
for (int i = 0; i < booms.size(); i++) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
Boom boom = booms.get(i);
//根据life画出对应图片
if (boom.life > 6) {
g.drawImage(image3, boom.x, boom.y, 50, 50, this);
} else if (boom.life > 3) {
g.drawImage(image2, boom.x, boom.y, 50, 50, this);
} else {
g.drawImage(image1, boom.x, boom.y, 50, 50, this);
}
boom.lifeDown();
if (boom.life == 0) {//若life==0,就删除
booms.remove(boom);
}
}
}
//编写画出tank的方法
/*
1.x y 左上角坐标
2.g 画笔
3.direction 方向
4.type 类型
*/
public void drawTank(int x, int y, Graphics g, int direction, int type) {
switch (type) {
case 0://我们的tank
g.setColor(Color.yellow);
break;
case 1://敌人的tank
g.setColor(Color.red);
break;
}
//根据tank的方向绘制不同的tank
switch (direction) {
case 0://表示向上
//填充当前颜色的高亮矩形 宽 高 表面色泽
g.fill3DRect(x, y, 10, 60, false);//画出tank左轮
g.fill3DRect(x + 30, y, 10, 60, false);//tank右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//tank身体
g.fillOval(x + 10, y + 20, 20, 20);//tank出口盖
g.drawLine(x + 20, y + 20, x + 20, y);
//画出tank炮筒
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 + 20, y + 20, x + 60, y + 20);
break;
case 2://向下
g.fill3DRect(x, y, 10, 60, false);//画出tank左轮
g.fill3DRect(x + 30, y, 10, 60, false);//tank右轮
g.fill3DRect(x + 10, y + 10, 20, 40, false);//tank身体
g.fillOval(x + 10, y + 20, 20, 20);//tank出口盖
g.drawLine(x + 20, y + 20, 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 + 20, y + 20, x, y + 20);
break;
default:
System.out.println("没有处理");
}
}
//子弹击中tank 判断我们子弹是否击中tank
public void hitTank(Shot s, Tank tank) {
switch (tank.getDirection()) {
case 0:
case 2:
if (s.x > tank.getX() && s.x < tank.getX() + 40 &&
s.y > tank.getY() && s.y < tank.getY() + 60) {
s.isLive = false;
tank.isLive = false;
//从集合中移除这个tank
enemyTanks.remove(tank);
//创建Boom对象 加入到booms集合
Boom boom = new Boom(tank.getX(), tank.getY());
booms.add(boom);
}
break;
case 1:
case 3:
if (s.x > tank.getX() && s.x < tank.getX() + 60 &&
s.y > tank.getY() && s.y < tank.getY() + 40) {
s.isLive = false;
tank.isLive = false;
enemyTanks.remove(tank);
Boom boom = new Boom(tank.getX(), tank.getY());
booms.add(boom);
}
break;
}
}
//编写方法判断敌人子弹是否打到p1
public void hitP1() {
for (int i = 0; i < enemyTankSize; i++) {
EnemyTank enemyTank = enemyTanks.get(i);
for (int j = 0; j < enemyTank.shots.size(); j++) {
Shot shot = enemyTank.shots.get(j);
if (p1.isLive && shot.isLive) {
hitTank(shot, p1);
}
}
}
}
@Override
public void keyTyped(KeyEvent e) {
}
//读取键盘的wasd改变tank的方向
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
//键盘按键 0w 2s 3a 1d
p1.setDirection(0);
//p1.setY(getY()-1);不优雅
if (p1.getY() > 0) {
p1.moveUp();
}
} else if (e.getKeyCode() == KeyEvent.VK_S) {
p1.setDirection(2);
if (p1.getY() < 650) {
p1.moveDown();
}
} else if (e.getKeyCode() == KeyEvent.VK_A) {
p1.setDirection(3);
if (p1.getX() > 0) {
p1.moveLeft();
}
} else if (e.getKeyCode() == KeyEvent.VK_D) {
p1.setDirection(1);
if (p1.getX() < 920) {
p1.moveRight();
}
}
if (e.getKeyCode() == KeyEvent.VK_J) {
//控制tank只能发射一颗子弹
// if (p1.shot == null || p1.shot.isLive == false) {
// p1.shotEnemyTank();
// }
//发射多颗子弹
p1.shotEnemyTank();
}
this.repaint();
}
@Override
public void keyReleased(KeyEvent e) {
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//判断p1是否击中enemytank
for (int j = 0; j < p1.shots.size(); j++) {
//遍历p1所有的子弹
if (p1.shots.get(j) != null && p1.shots.get(j).isLive) {
//遍历敌人所有的tank 因为不知道子弹击中了敌人的哪一个tank
for (int i = 0; i < enemyTanks.size(); i++) {
EnemyTank enemyTank = enemyTanks.get(i);
hitTank(p1.shots.get(j), enemyTank);
}
}
}
//判断enemy tank是否击中p1
hitP1();
this.repaint();
}
}
}
P1类 发射多颗子弹
给shot创建一个集合每个shot启动一个线程 用集合大小控制子弹个数
public class P1 extends Tank {
//定义一个shot对象 我们只有一个子弹
Shot shot = null;
Vector<Shot> shots =new Vector<>();
public P1(int x, int y) {
super(x, y);
}
public void shotEnemyTank() {
//创建shot对象 根据P1的位置确定
switch (getDirection()) {
case 0:
shot = new Shot(getX() + 20, getY() - 20, 0);
break;
case 1:
shot = new Shot(getX() + 80, getY() +20, 1);
break;
case 2:
shot = new Shot(getX() + 20, getY() + 80, 2);
break;
case 3:
shot = new Shot(getX() - 20, getY() + 20, 3);
break;
}
//控制p1可发出子弹的个数
if (shots.size() == 5) {
return;
}
//把新创建的shot放入集合中
shots.add(shot);
//启动shot
Thread thread = new Thread(shot);
thread.start();
}
}
Shot类
public class Shot implements Runnable {
int x;
int y;
int direction = 0;
int speed = 10;
boolean isLive = true;//子弹是否存活
public Shot(int x, int y, int direction) {
this.x = x;
this.y = y;
this.direction = direction;
}
@Override
public void run() {
while (true) {
switch (direction) {
case 0:
y -= speed;
break;
case 1:
x += speed;
break;
case 2:
y += speed;
break;
case 3:
x -= speed;
break;
}
//离开面板就退出
if (!(x >= 0 && x <= 1000 && y >= 0 && y <= 750&&isLive)) {
isLive = false;
break;
}
//当子弹碰到敌人tank也要退出
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
EnemyTank类 敌人发射多颗子弹
让敌人发射的子弹也成为一个集合 每一个子弹也启动一个线程
public class EnemyTank extends Tank implements Runnable {
public EnemyTank(int x, int y) {
super(x, y);
}
private int direction = 2;
boolean isLive = true;
Vector<Shot> shots = new Vector<Shot>();
private void enemyShot() {
}
//重写enemy tank的方向
@Override
public int getDirection() {
return direction;
}
@Override
public void setDirection(int direction) {
this.direction = direction;
}
@Override
public void run() {
while (true) {
//当enemy tank没有子弹创建一个子弹
if (isLive && shots.size() < 10){
//判断tank的方向
Shot s =null;
switch (getDirection()){
case 0:
s = new Shot(getX() + 20, getY() - 20, 0);
break;
case 1:
s = new Shot(getX() + 80, getY() +20, 1);
break;
case 2:
s = new Shot(getX() + 20, getY() + 80, 2);
break;
case 3:
s = new Shot(getX() - 20, getY() + 20, 3);
break;
}
shots.add(s);
new Thread(s).start();
}
int moveSpeed = 30;
int sleepTime = 300;
switch (getDirection()) {
case 0:
for (int i = 0; i < moveSpeed; i++) {
if (getY() > 0) {
moveUp();
}
}
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case 1:
for (int i = 0; i < moveSpeed; i++) {
if (getX() < 920) {
moveRight();
}
}
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case 2:
for (int i = 0; i < moveSpeed; i++) {
if (getY() < 650) {
moveDown();
}
}
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
case 3:
for (int i = 0; i < moveSpeed; i++) {
if (getX() > 0) {
moveLeft();
}
}
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
// try {
// Thread.sleep(2000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
setDirection(new Random().nextInt(4));
if (isLive == false) {
break;
}
}
}
}
其余类
Boom
public class Boom {
int x, y;
int life = 9;
boolean isLive = true;
public Boom(int x, int y) {
this.x = x;
this.y = y;
}
//减少生命值
public void lifeDown() {
if (life > 0) {
life--;
} else {
isLive = false;
}
}
}
Tank类
public class Tank {
private int x;//横纵坐标
private int y;
boolean isLive =true;
private int direction = 0;//坦克方向
private int speed = 1;
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
//移动方法
public void moveUp(){
y-=speed;
}
public void moveDown(){
y+=speed;
}
public void moveLeft(){
x-=speed;
}
public void moveRight(){
x+=speed;
}
public int getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
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;
}
}