线程-应用到坦克大战
分析如何实现当用户按下J键,我们的坦克就发射一颗子弹
思路
-
1,当发射一颗子弹后,就相当于启动一个线程 Shot类
-
2,Hero类有子弹对象,当按下J时,我们就启动一个发射行为(线程),让子弹不停地移动,形成一个设射击的效果
-
3,我们MyPanel需要不停的重绘子弹,才能出现该效果
-
4,当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程毁掉)
Shot类
public class Shot implements Runnable {
int x;//子弹的横坐标
int y;//子弹的Y坐标
int direct;//子弹的方向
int speed = 10;
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){
//让线程休眠一会
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//根据方向改变x,y坐标
switch (direct){
case 0://上
y-=speed;
break;
case 1://右
x+=speed;
break;
case 2://下
y+=speed;
break;
case 3://左
x-=speed;
break;
}
//我们输除 x,y的坐标
System.out.println("子弹x="+x+"子弹y="+y);
//当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)
if(!(x>=0&&x<=1000&&y>=0&&y<=750)){
isLive = false;
break;
}
}
}
}
Hero:自己的坦克类 创建自己的坦克对象,启动线程,形成射击效果
//自己的坦克,继承坦克父类
public class Hero extends Tank {
//定义一个Shot对象,表示一个射击(线程)
Shot shot = null;
public Hero(int x, int y) {
super(x, y);
}
public void shotEnemyTank(){
//创建Shot对象,根据当前Hero对象的位置和方向来创建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线程
new Thread(shot).start();
}
}
画板类-设置J键,同时加入线程,实现子弹的重绘
//画板类
public class MyPanel extends JPanel implements KeyListener, Runnable {
//定义我的坦克
Hero hero = null;
public MyPanel() {//初始化自己的坦克
hero = new Hero(100, 100);
hero.setSpeed(5);
}
@Override
public void paint(Graphics g) {
super.paint(g);
//3,通过画笔填充一个矩形区域 g.fillRect();
g.fillRect(0, 0, 1000, 750);//填充矩形,默认为黑色
drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
// drawTank(hero.getX() +100,hero.getY(),g,hero.getDirect(),0);
// drawTank(hero.getX() +200,hero.getY(),g,hero.getDirect(),0);
// drawTank(hero.getX() +300,hero.getY(),g,hero.getDirect(),1);
}
/*
int x 坦克的横坐标
int y 坦克的纵坐标
Graphics g 画笔
int direct 坦克的方向
int type 坦克的类型
*/
public void drawTank(int x, int y, Graphics g, int direct, int type) {
//判断何时画子弹
if (hero.shot != null && hero.shot.isLive == true) {
g.setColor(Color.white);
g.draw3DRect(hero.shot.x, hero.shot.y, 1, 1, false);
}
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://表示向右
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) {
}
//当某个键按下,该方法会触发
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
//改变坦克方向
hero.setDirect(0);
//让坦克动起来
hero.moveUp();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
hero.setDirect(2);
hero.moveDown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
hero.setDirect(3);
hero.moveLeft();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
hero.setDirect(1);
hero.moveRight();
}
//如果用户按下的是J,就发射
if (e.getKeyCode() == KeyEvent.VK_J) {
System.out.println("用户按下了J,开始射击");
hero.shotEnemyTank();
}
//重绘
repaint();
}
//当某个键释放(松开),该方法会触发
@Override
public void keyReleased(KeyEvent e) {
}
//添加线程的方法,确保子弹可以重绘
@Override
public void run() {//每隔 100毫秒,重绘区域,刷新绘图区域,子弹就移动
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
this.repaint();
}
}
}
窗体类:将画板对象传入线程中,实现子弹重绘
//窗体类
public class TankGame02 extends JFrame {//窗体
public static void main(String[] args) {
new TankGame02();
}
private MyPanel mp = null;//创建画板对象
public TankGame02(){
mp = new MyPanel();//画板初试化
//将mp放入Thread对象中
Thread thread = new Thread(mp);
thread.start();
this.add(mp);//把画板传入窗体
this.setSize(1000,750);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//窗体JFrame对象可以监听键盘事件,面板实现了键盘监听器
// 即可以监听到面板发生的监听事件
this.addKeyListener(mp);
this.setVisible(true);
}
}
让敌人的坦克也能够发射子弹(可以有多颗子弹)
- 1,在敌人坦克类,使用Vector(线程安全)保存多个Shot
- 2,当每创建一个敌人坦克对象,给该敌人坦克对象初始化一个Shot对象,同时启动Shot
- 3,在绘制敌人坦克时,需要遍历敌人坦克对象Vector,绘制所有的子弹,当子弹isLive == false。就从Vector移除
画板
package oop.highclass.Tank04;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;
//画板类
public class MyPanel extends JPanel implements KeyListener, Runnable {
//定义我的坦克
Hero hero = null;
//定义敌人坦克,放入到Vector(线程安全,可以有多个)
Vector<EnemyTank> enemyTanks = new Vector<>();
int enemyTankSize = 3;
public MyPanel() {//初始化自己的坦克
hero = new Hero(100, 100);
hero.setSpeed(5);
//初始化敌人的坦克
for (int i = 0; i < enemyTankSize; 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.shots.add(shot);
//启动shot对象
new Thread(shot).start();
//把敌人的坦克加入的总的坦克对象中
enemyTanks.add(enemyTank);
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
//3,通过画笔填充一个矩形区域 g.fillRect();
g.fillRect(0, 0, 1000, 750);//填充矩形,默认为黑色
//画出自己的坦克
drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
// drawTank(hero.getX() +100,hero.getY(),g,hero.getDirect(),0);
// drawTank(hero.getX() +200,hero.getY(),g,hero.getDirect(),0);
// drawTank(hero.getX() +300,hero.getY(),g,hero.getDirect(),1);
//判断何时画子弹
if (hero.shot != null && hero.shot.isLive == true) {
g.setColor(Color.white);
g.draw3DRect(hero.shot.x, hero.shot.y, 1, 1, false);
}
//画出敌人的坦克
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++) {
//取出子弹
Shot shot = enemyTank.shots.get(j);
//绘制
if (shot.isLive){//isLive=true
g.setColor(Color.white);
g.draw3DRect(shot.x, shot.y, 1, 1, false);
}else {
//从Vector 移除
enemyTank.shots.remove(shot);
}
}
}
}
/*
int x 坦克的横坐标
int y 坦克的纵坐标
Graphics g 画笔
int direct 坦克的方向
int 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://表示向右
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) {
}
//当某个键按下,该方法会触发
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
//改变坦克方向
hero.setDirect(0);
//让坦克动起来
hero.moveUp();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
hero.setDirect(2);
hero.moveDown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
hero.setDirect(3);
hero.moveLeft();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
hero.setDirect(1);
hero.moveRight();
}
//如果用户按下的是J,就发射
if (e.getKeyCode() == KeyEvent.VK_J) {
System.out.println("用户按下了J,开始射击");
hero.shotEnemyTank();
}
//重绘
repaint();
}
//当某个键释放(松开),该方法会触发
@Override
public void keyReleased(KeyEvent e) {
}
//添加线程的方法,确保子弹可以重绘
@Override
public void run() {//每隔 100毫秒,重绘区域,刷新绘图区域,子弹就移动
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
this.repaint();
}
}
}
敌人坦克
package oop.highclass.Tank04;
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);
}
}
当我方坦克击中敌人坦克时,敌人的坦克就消失
- 1,编写方法(hitTank):判断我方子弹是否击中敌人坦克
- 2,在哪里判断? 在run方法中判断是否击中敌人坦克(判断我方子弹是否还存活)
- 3,判断当前坦克是否存活:在paint方法中判断敌当前人的坦克是否还存活,若存活,才画该坦克
画板类
package oop.highclass.Tank04;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;
//画板类
public class MyPanel extends JPanel implements KeyListener, Runnable {
//定义我的坦克
Hero hero = null;
//定义敌人坦克,放入到Vector(线程安全,可以有多个)
Vector<EnemyTank> enemyTanks = new Vector<>();
int enemyTankSize = 3;
public MyPanel() {//初始化自己的坦克
hero = new Hero(100, 100);
hero.setSpeed(5);
//初始化敌人的坦克
for (int i = 0; i < enemyTankSize; 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.shots.add(shot);
//启动shot对象
new Thread(shot).start();
//把敌人的坦克加入的总的坦克对象中
enemyTanks.add(enemyTank);
}
}
@Override
public void paint(Graphics g) {
super.paint(g);
//3,通过画笔填充一个矩形区域 g.fillRect();
g.fillRect(0, 0, 1000, 750);//填充矩形,默认为黑色
//画出自己的坦克
drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
// drawTank(hero.getX() +100,hero.getY(),g,hero.getDirect(),0);
// drawTank(hero.getX() +200,hero.getY(),g,hero.getDirect(),0);
// drawTank(hero.getX() +300,hero.getY(),g,hero.getDirect(),1);
//判断何时画子弹
if (hero.shot != null && hero.shot.isLive == true) {
g.setColor(Color.white);
g.draw3DRect(hero.shot.x, hero.shot.y, 1, 1, false);
}
//画出敌人的坦克
for (int i = 0; i < enemyTanks.size(); i++) {
//从Vector取出坦克
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++) {
//取出子弹
Shot shot = enemyTank.shots.get(j);
//绘制
if (shot.isLive) {//isLive=true
g.setColor(Color.white);
g.draw3DRect(shot.x, shot.y, 1, 1, false);
} else {
//从Vector 移除
enemyTank.shots.remove(shot);
}
}
}
}
}
/*
int x 坦克的横坐标
int y 坦克的纵坐标
Graphics g 画笔
int direct 坦克的方向
int 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://表示向右
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("暂时没有处理");
}
}
//编写方法:判断我方子弹是否击敌人坦克
//什么时候判断,我方坦克是否击中敌人坦克? run方法
public static void hitTank(Shot s, EnemyTank enemyTank){
//判断s 击中坦克
switch (enemyTank.getDirect()){
case 0://敌人坦克向上
case 2://敌人坦克向下
if (s.x>enemyTank.getX()&& s.y<enemyTank.getY()+40&&
s.y>enemyTank.getY()&& s.y<enemyTank.getY()+60){
s.isLive = false;
enemyTank.isLive = false;
}
break;
case 1://敌人坦克向右
case 3://敌人坦克向下
if (s.x>enemyTank.getX()&& s.y<enemyTank.getY()+60&&
s.y>enemyTank.getY()&& s.y<enemyTank.getY()+40){
s.isLive = false;
enemyTank.isLive = false;
}
break;
}
}
//有字符输出时,该方法就会触发
@Override
public void keyTyped(KeyEvent e) {
}
//当某个键按下,该方法会触发
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
//改变坦克方向
hero.setDirect(0);
//让坦克动起来
hero.moveUp();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
hero.setDirect(2);
hero.moveDown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
hero.setDirect(3);
hero.moveLeft();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
hero.setDirect(1);
hero.moveRight();
}
//如果用户按下的是J,就发射
if (e.getKeyCode() == KeyEvent.VK_J) {
System.out.println("用户按下了J,开始射击");
hero.shotEnemyTank();
}
//重绘
repaint();
}
//当某个键释放(松开),该方法会触发
@Override
public void keyReleased(KeyEvent e) {
}
//添加线程的方法,确保子弹可以重绘
@Override
public void run() {//每隔 100毫秒,重绘区域,刷新绘图区域,子弹就移动
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//判断是否击中了敌人坦克
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();
}
}
}
敌人坦克类: 新增 ----定义敌人坦克的存活属性
//敌人坦克
public class EnemyTank extends Tank{
//给敌人坦克类,使用Vector 保存多个Shot
Vector<Shot> shots = new Vector<>();
//定义敌人坦克的存活属性
boolean isLive = true;
public EnemyTank(int x, int y) {
super(x, y);
}
}
敌人坦克消失时,会出现爆炸效果
- 1, 创建一个爆炸类Bomb
- 2,在MyPanel类中定义Vector用于存放炸弹 (因为炸弹既不属于我方坦克也不属于地方坦克 ,所以坦克放在画板类)
- 3,定义三张炸弹图片,并在构造器中进行初始化,用于显示爆炸效果
- 4,当坦克被击中时,在hitTank方法中创建Bomb对象,加入到Vector集合中
- 5,在paint方法中画出炸弹
- 6,当我的子弹击中敌人坦克后,在hitTank方法中,将enenmyTank 从Vector 拿掉
炸弹类
//炸弹类
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;
}
}
}
画板类
package oop.highclass.Tank04;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;
//画板类
public class MyPanel extends JPanel implements KeyListener, Runnable {
//定义我的坦克
Hero hero = null;
//定义敌人坦克,放入到Vector(线程安全,可以有多个)
Vector<EnemyTank> enemyTanks = new Vector<>();
int enemyTankSize = 3;
//定义一个Vector,用于存放炸弹(炸弹既不属于我方坦克也不属于地方坦克 ,所以坦克放在画板类)
//当我们的子弹击中坦克时,就加入一个Bomb对象到bombs
Vector<Bomb> bombs = new Vector<>();
//定义三张炸弹图片,用于显示爆炸效果
Image image1 = null;
Image image2 = null;
Image image3 = null;
public MyPanel() {//初始化自己的坦克
hero = new Hero(100, 100);
hero.setSpeed(5);
//初始化敌人的坦克
for (int i = 0; i < enemyTankSize; 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.shots.add(shot);
//启动shot对象
new Thread(shot).start();
//把敌人的坦克加入的总的坦克对象中
enemyTanks.add(enemyTank);
}
// image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/1.gif"));
// image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/2.gif"));
// image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/3.gif"));
//初始化照片对象
image1 = new ImageIcon("image/1.gif").getImage();
image2 = new ImageIcon("image/2.gif").getImage();
image3 = new ImageIcon("image/3.gif").getImage();
}
@Override
public void paint(Graphics g) {
super.paint(g);
//3,通过画笔填充一个矩形区域 g.fillRect();
g.fillRect(0, 0, 1000, 750);//填充矩形,默认为黑色
//画出自己的坦克
drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
// drawTank(hero.getX() +100,hero.getY(),g,hero.getDirect(),0);
// drawTank(hero.getX() +200,hero.getY(),g,hero.getDirect(),0);
// drawTank(hero.getX() +300,hero.getY(),g,hero.getDirect(),1);
//判断何时画子弹
if (hero.shot != null && hero.shot.isLive == true) {
g.setColor(Color.white);
g.draw3DRect(hero.shot.x, hero.shot.y, 1, 1, false);
}
//如果bombs 集合中有对象,就画出
for (int i = 0; i < bombs.size(); i++) {
//取出来炸弹
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);
}
}
//画出敌人的坦克
for (int i = 0; i < enemyTanks.size(); i++) {
//从Vector取出坦克
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++) {
//取出子弹
Shot shot = enemyTank.shots.get(j);
//绘制
if (shot.isLive) {//isLive=true
g.setColor(Color.white);
g.draw3DRect(shot.x, shot.y, 1, 1, false);
} else {
//从Vector 移除
enemyTank.shots.remove(shot);
}
}
}
}
}
/*
int x 坦克的横坐标
int y 坦克的纵坐标
Graphics g 画笔
int direct 坦克的方向
int 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://表示向右
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("暂时没有处理");
}
}
//编写方法:判断我方子弹是否击敌人坦克
//什么时候判断,我方坦克是否击中敌人坦克? run方法
public void hitTank(Shot s, EnemyTank enemyTank) {
//判断s 击中坦克
switch (enemyTank.getDirect()) {
case 0://敌人坦克向上
case 2://敌人坦克向下
if (s.x > enemyTank.getX() && s.y < enemyTank.getY() + 40 &&
s.y > enemyTank.getY() && s.y < enemyTank.getY() + 60) {
s.isLive = false;
enemyTank.isLive = false;
//当我的子弹击中敌人坦克后,将enenmyTank 从Vector 拿掉
enemyTanks.remove(enemyTank);
//这里敌人坦克被击中
//创建Bomb对象,加入到bombs集合
Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
bombs.add(bomb);
}
break;
case 1://敌人坦克向右
case 3://敌人坦克向下
if (s.x > enemyTank.getX() && s.y < enemyTank.getY() + 60 &&
s.y > enemyTank.getY() && s.y < enemyTank.getY() + 40) {
s.isLive = false;
enemyTank.isLive = false;
Bomb bomb = new Bomb(enemyTank.getX(), enemyTank.getY());
bombs.add(bomb);
}
break;
}
}
//有字符输出时,该方法就会触发
@Override
public void keyTyped(KeyEvent e) {
}
//当某个键按下,该方法会触发
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {
//改变坦克方向
hero.setDirect(0);
//让坦克动起来
hero.moveUp();
} else if (e.getKeyCode() == KeyEvent.VK_S) {
hero.setDirect(2);
hero.moveDown();
} else if (e.getKeyCode() == KeyEvent.VK_A) {
hero.setDirect(3);
hero.moveLeft();
} else if (e.getKeyCode() == KeyEvent.VK_D) {
hero.setDirect(1);
hero.moveRight();
}
//如果用户按下的是J,就发射
if (e.getKeyCode() == KeyEvent.VK_J) {
System.out.println("用户按下了J,开始射击");
hero.shotEnemyTank();
}
//重绘
repaint();
}
//当某个键释放(松开),该方法会触发
@Override
public void keyReleased(KeyEvent e) {
}
//添加线程的方法,确保子弹可以重绘
@Override
public void run() {//每隔 100毫秒,重绘区域,刷新绘图区域,子弹就移动
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//判断是否击中了敌人坦克
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();
}
}
}
让敌人的坦克也可以自由随机的上下左右移动
- 1,将敌人的坦克当做线程使用,EnemyTank implements Runnable(因为要求敌人的坦克,可以自由移动,用线程中的run方法)
- 2,在EnemyTank 类继承的run方法写上我们相应的业务代码
- 3,在创建敌人坦克对象时,启动线程
EnemyTank 类
import java.util.Vector;
//敌人坦克
public class EnemyTank extends Tank implements Runnable {
//给敌人坦克类,使用Vector 保存多个Shot
Vector<Shot> shots = new Vector<>();
//定义敌人坦克的存货属性
boolean isLive = true;
public EnemyTank(int x, int y) {
super(x, y);
}
@Override
public void run() {
while (true) {
switch (getDirect()) {
//根据坦克的方向来进行移动
case 0://向上
//让坦克保持一个方向,走30步
for (int i = 0; i < 30; i++) {
moveUp();
//休眠50好眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
break;
case 1://向右
//让坦克保持一个方向,走30步
for (int i = 0; i < 30; i++) {
moveRight();
//休眠50好眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
break;
case 2://向下
//让坦克保持一个方向,走30步
for (int i = 0; i < 30; i++) {
moveDown();
//休眠50好眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
break;
case 3://向左
//让坦克保持一个方向,走30步
for (int i = 0; i < 10; i++) {
moveLeft();
//休眠50好眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
break;
}
//休眠50好眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 然后随机的改变坦克方向0-3
setDirect((int) (Math.random() * 4)); //0-3
//一旦写并发程序,一定要考虑清楚,该线程什么时候结束
if (!isLive) {
break;
}
}
}
}
在画板类的构造器中,在创建敌人坦克对象时,启动线程
public MyPanel() {//初始化自己的坦克
hero = new Hero(100, 100);
hero.setSpeed(5);
//初始化敌人的坦克
for (int i = 0; i < enemyTankSize; i++) {
//创建一个敌人的坦克
EnemyTank enemyTank = new EnemyTank(100 * (i + 1), 0);
//启动敌人坦克线程,让他动起来
new Thread(enemyTank).start();
//设置方向
enemyTank.setDirect(2);
//给该enemyTank 加入一颗子弹
Shot shot = new Shot(enemyTank.getX() + 20, enemyTank.getY() + 60, enemyTank.getDirect());
enemyTank.shots.add(shot);
//启动shot对象
new Thread(shot).start();
//把敌人的坦克加入的总的坦克对象中
enemyTanks.add(enemyTank);
}
控制我方的坦克和敌人的坦克在规定的范围移动
思路:在坦克移动时,用if 语句控制他们的移动范围
EnemyTank类中-控制敌方坦克的移动
//敌人坦克
public class EnemyTank extends Tank implements Runnable {
//给敌人坦克类,使用Vector 保存多个Shot
Vector<Shot> shots = new Vector<>();
//定义敌人坦克的存货属性
boolean isLive = true;
public EnemyTank(int x, int y) {
super(x, y);
}
@Override
public void run() {
while (true) {
switch (getDirect()) {
//根据坦克的方向来进行移动
case 0://向上
//让坦克保持一个方向,走30步
for (int i = 0; i < 30; i++) {
if (getY()>0){
moveUp();
}
//休眠50好眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
break;
case 1://向右
//让坦克保持一个方向,走30步
for (int i = 0; i < 30; i++) {
if (getX()+60<1000){
moveRight();
}
//休眠50好眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
break;
case 2://向下
//让坦克保持一个方向,走30步
for (int i = 0; i < 30; i++) {
if (getY()+60<750){
moveDown();
}
//休眠50好眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
break;
case 3://向左
//让坦克保持一个方向,走30步
for (int i = 0; i < 10; i++) {
if (getX()>0){
moveLeft();
}
//休眠50好眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
break;
}
//休眠50好眠
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 然后随机的改变坦克方向0-3
setDirect((int) (Math.random() * 4)); //0-3
//一旦写并发程序,一定要考虑清楚,该线程什么时候结束
if (!isLive) {
break;
}
}
}
}
MyPanel类-控制我方坦克移动 (keyPressed方法)
//当某个键按下,该方法会触发
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {//上
//改变坦克方向
hero.setDirect(0);
//让坦克动起来
if (hero.getY()>0){
hero.moveUp();
}
} else if (e.getKeyCode() == KeyEvent.VK_S) {//下
hero.setDirect(2);
if (hero.getY()+60<750){
hero.moveDown();
}
} else if (e.getKeyCode() == KeyEvent.VK_A) {//左
hero.setDirect(3);
if (hero.getX()>0){
hero.moveLeft();
}
} else if (e.getKeyCode() == KeyEvent.VK_D) {//右
hero.setDirect(1);
if (hero.getX()+60<1000)
hero.moveRight();
}
//如果用户按下的是J,就发射
if (e.getKeyCode() == KeyEvent.VK_J) {
System.out.println("用户按下了J,开始射击");
hero.shotEnemyTank();
}
//重绘
repaint();
}