陆游曾说:纸上得来终觉浅,绝知此事要躬行。前面已经了解Java线程基础知识,现在我们来实际运用一下。
在坦克大战游戏(0.2版)基础上添加如下功能:当玩家按一下j键,就发射一颗子弹。
为了能射出子弹,需要把每个子弹做成一个线程,并根据KeyListener事件判断用户输入,之后循环判断子弹位置,repaint()子弹,并要根据坦克的每个方向调整x,y轴 新建Shot类 package tankgame3;/** * Create By 刘鸿涛 * 2022/1/17 5:19 */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;}@Overridepublic void run() { //射击while (true){//子弹休眠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;}//测试,这里我们输出x,y坐标System.out.println("子弹 x = " + x + " y= " + y);//当子弹移动到面板if (!(x >= 0 && x = 0 && y hero = new Hero(500,500);//初始化自己的坦克hero.setSpeed(50);//初始化坦克速度//初始化敌人坦克for (int i = 0; i super.paint(g);g.fillRect(0,0,1000,750);//填充矩形,默认黑色//画出坦克 - 封装方法//自己的坦克drawTank(hero.getX(),hero.getY(),g,hero.getDirect(),1);//type坦克类型//画出hero射击的子弹if (hero.shot != null && hero.shot.isLive == true){g.draw3DRect(hero.shot.x,hero.shot.y,5 ,5,false);}//画出敌人的坦克,遍历Vectorfor (int i = 0; i //取出子弹Shot shot = enemyTank.shots.get(j);//绘制if (shot.isLive){//isLive 为 trueg.draw3DRect(shot.x,shot.y,2,2,false);}else {//从Vector 移除enemyTank.shots.remove(shot);}}}} 2.当我方坦克击中敌人坦克时,敌人的坦克就消失实现子弹击中敌方坦克消失,我们需要写一个方法,判断我方子弹是否碰到敌方坦克,需要考虑敌方坦克面向问题。我们在paint方法中也加入判断语句,如果上面条件为真,则返回敌方坦克isLive属性为false,根据情况paint敌方坦克是否执行。而我们的线程集合每隔100毫秒遍历一次敌方坦克集合,刷新整个游戏区域,实现敌方坦克被击中后消失
hitTank()方法
public static void hitTank(Shot s, EnemyTank enemyTank){//判断 s 击中坦克switch (enemyTank.getDirect()){case 0: //坦克向上case 2: //坦克向下if(s.x > enemyTank.getX() && s.x enemyTank.getY() && s.y s.isLive = false;enemyTank.isLive = false;}break;}} 3.实现敌人坦克爆炸后消失当敌方坦克被击中后出现爆炸效果,我们新建一个爆炸效果类,这个类需要有x,y大小,需要一个生命周期的方法,来让爆炸效果动态化。当然了,我们的爆炸效果也在一个集合中,也有自己的isLive属性,判断存活时间,我们用Image来初始化三张图片,并路径赋值,在坦克被击中方法里,我们添加执行效果-> 坦克被击中消失后,我们开始执行爆炸类的“生命周期方法”,按条件执行图片放映顺序
新建Bomb类
package tankgame4;/** * Create By 刘鸿涛 * 2022/1/19 4:56 */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;}}} 注意图片位置当敌方坦克被击中后出现爆炸效果,我们新建一个爆炸效果类,这个类需要有x,y大小,需要一个生命周期的方法,来让爆炸效果动态化。当然了,我们的爆炸效果也在一个集合中,也有自己的isLive属性,判断存活时间,我们用Image来初始化三张图片,并路径赋值,在坦克被击中方法里,我们添加执行效果-> 坦克被击中消失后,我们开始执行爆炸类的“生命周期方法”,按条件执行图片放映顺序
4.实现敌人坦克自由移动 因为要求敌人的坦克,可以自由移动,因此需要将敌人坦克当做线程使用因此,我们需要EnemyTank implements Runnable在run方法写上我们相应的业务代码在创建敌人坦克对象时,启动线程为了使敌方坦克自由活动,我们需要为敌方每个坦克做成一个线程,因此,我们的敌人坦克类要实现Runnable接口,我们的run实现逻辑,通过setDirect封装方法,我们用switch循环加上Math.Random随机生成数,随机生成坦克方向,并按for循环来进行移动,每次朝一个方向移动后休眠50毫秒,体现缓冲效果,当然了,如果此线程坦克被击中,那么我们让此线程while循环break,不再执行
5.实现坦克站规定范围内移动为了能使敌方坦克在游戏范围内移动,我们只需要在敌方坦克随机循环移动时,加入一个if条件即可,当超过范围,则不执行此次循环
package tankgame4;import java.util.Vector;/** * Create By 刘鸿涛 * 2022/1/13 2:16 */public class EnemyTank extends Tank implements Runnable {//在敌人坦克类,使用Vector 保存多个ShotVector shots = new Vector();boolean isLive = true;public EnemyTank(int x, int y) {super(x, y);}@Overridepublic void run() {//然后随机的改变坦克方向while (true) {//根据坦克的方向来继续移动switch (getDirect()) {case 0://向上//让坦克保存一个方向,走30步for (int i = 0; i moveUp();//休眠50毫秒try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}break;case 1://右for (int i = 0; i moveRight();//休眠50毫秒try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}break;case 2://下for (int i = 0; i moveDown();//休眠50毫秒try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}break;case 3://左for (int i = 0; i moveLeft();//休眠50毫秒try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}break;}try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}//随机改变坦克方向0 - 3setDirect((int) (Math.random() * 4));//如果坦克被击中线程终止if (!isLive) {break;}}}}