本章目标

  • 应用炮筒来确定坦克目前的方向
  • 让坦克发射多发炮弹问题

一、画出炮筒


个别坦克初始地位是不同的,然而咱们目前的射击方向是与挪动方向统一的

这就导致比拟怪异,咱们应该是初始时有一个射击方向,比如说:左边

class Tank{    //省略其余关键性代码....        //默认设计方向为左边    private Direction ptdir = Direction.R;}

而咱们的射击方向有了,还须要与挪动时方向统一同步并且画进去

这里咱们只须要画出一条直线即可,能够应用drawLine办法

咱们须要晓得两点来确定一条直线,而在坐标中由横(X)、纵坐标(y)确定一个点。

而这drawLine办法的四参数理论就是确定两个点,要画的直线的起始点横纵坐标和起点的横纵坐标

X1,Y1是确定直线的起始点,即横坐标为x1,纵坐标为y1的点。

同理x2,y2确定直线的起点。

例:

A(x1,y1) B(x2,y2) 就能够画出直线AB了。
参数:

x1 - 第一个点的 x 坐标。

y1 - 第一个点的 y 坐标。

x2 - 第二个点的 x 坐标。

y2 - 第二个点的 y 坐标。

而咱们的坦克中,想要画出对应方向的直线,则能够应用公式计算相应的坐标

class Tank{    //省略其余关键性代码....        //增加办法实现坦克的绘画    public void draw(Graphics g) {        //省略其余关键性代码....        switch (ptdir) {            case L:                g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x,y + Tank. HEIGHT/2);                break;            case LU:                g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x,y);                break;            case U:                g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x + Tank.WIDTH/2,y);                break;            case RU:                g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x + Tank.WIDTH,y);                break;            case R:                g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x + Tank.WIDTH,y + Tank. HEIGHT/2);                break;            case RD:                g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x + Tank.WIDTH,y + Tank. HEIGHT);                break;            case D:                g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x + Tank.WIDTH/2,y + Tank. HEIGHT);                break;            case LD:                g.drawLine(x + Tank.WIDTH/2,y + Tank.HEIGHT/2,x,y + Tank. HEIGHT);                break;        }    }}

这时咱们运行起来就发现,咱们的坦克炮筒曾经进去了

然而为什么它没有随着咱们的挪动方向而扭转射击方向呢?

那么因为咱们没有依据挪动方向来进行调整,咱们当初增加调整一下看看

class Tank{    //省略其余关键性代码....        void move() {        //省略其余关键性代码....            if(this.dir !=Direction.STOP){            this.ptdir = dir;        }    }}

而之前咱们依据坦克的方向进行发射炮弹,会有一个问题不晓得大家发现没有

比如说当咱们不动的时候,是无奈发射炮弹进去的

那么当初咱们依据射击方向进行发射,就能够解决这个问题

class Tank{    //省略其余关键性代码....    //坦克发射子弹.....    public Missle fire(){        //省略其余关键性代码....        Missle missle = new Missle(x,y,ptdir);        return missle;    }}

这时即便咱们不动,也能够发射炮弹了

步骤总结

  • ✧Tank类减少新的属性ptDir
  • ✧每次move后依据Tank新的方向确定炮筒的方向
  • ✧将炮简用直线的模式体现进去

二、让坦克发射多发炮弹


目前咱们的坦克按下Ctrl键时,就会发射一发炮弹

然而当咱们再按下Ctrl键时,就会发现坦克收回的炮弹又从头开始了

这是因为咱们目前只保护了一发炮弹的发射状态

那么怎么解决这个问题呢?

咱们想想能不能将收回去的炮弹用一个容器将它装起来呢?

public class TankClient extends Frame {        //应用汇合容器治理炮弹    List<Missle> missles = new ArrayList<Missle>();        @Override    public void paint(Graphics g) {        //画出容器里的子弹        for ( int i = 0; i < missles.size();i++){            Missle m = missles.get(i);            m.draw(g);        }        //画出坦克        mytank.draw(g);    }    //省略其余关键性代码....}

同时当咱们按下Ctrl键时,咱们就将炮弹放入汇合容器中

class Tank{    //坦克发射子弹.....    public Missle fire(){        //省略其余关键性代码.......        Missle missle =new Missle(x,y,ptdir);        tc.missles.add(missle);        return missle;    }}   

这时咱们运行起来就能够发现,咱们能够间断打出多发炮弹了

然而有一个小问题:如果始终按住Ctrl键收回的炮弹就会没有距离

这样的状况咱们有两种解决形式:

  • 第一种:每一枚炮弹设置间隔时间
  • 第二种:将发射炮弹改为按下抬起开释Ctrl键发射炮弹

咱们采纳Ctrl键按下抬起发射炮弹来解决这个问题

class Tank{    //省略其余关键性代码....    //坦克键盘按下抬起监听器    public void keyReleased(KeyEvent e) {        int key = e.getKeyCode();        switch (key) {            case KeyEvent.VK_CONTROL:                fire();                break;        }        //省略其余关键性代码.......    }}

步骤总结

  • ✧应用容器装炮弹
  • ✧每当抬起Ctr键就往容器中退出新的炮弹
  • ✧逐个画出每一发炮弹

三、让炮弹沦亡


因为咱们目前采纳汇合容器的形式来治理发射的炮弹

若咱们对于这个游戏始终玩个几小时,那么就会造成很多很多的炮弹积攒在外面

咱们当初在游戏的窗口中将咱们以后的炮弹数量显示进去

public class TankClient extends Frame {        //省略其余关键性代码....        @Override    public void paint(Graphics g) {            //省略其余关键性代码....        //展现炮弹容器以后数量        g.drawString("missiles count:" + missles.size()+"",10,50);    }}

这下咱们以后容器里的子弹数量就能显示进去了

刚刚咱们说到若咱们对于这个游戏始终玩个几小时,那么就会造成很多很多的炮弹积攒在外面

那么咱们什么时候就要让子弹沦亡呢?

  • 击中敌方坦克时
  • 超出游戏边界时

咱们为Missle子弹类增加属性区别存活状态、并且当超出边界时设置为沦亡状态

class Missle{        //辨别子弹的存活    private boolean live = true;    public boolean isLive() {return live;}    void move() {        //省略其余关键性代码....        //当子弹的x、y坐标小于0 或者大于游戏窗口的宽度与高度则沦亡状态        if (x < 0 || y < 0 || x > TankClient.WIDTH || y > TankClient.HEIGHT) {            live = false;        }    }     //省略其余关键性代码....}

而在咱们的游戏界面中的绘画办法,对于沦亡的子弹咱们从容器中里去除

class Missle{    //引入TankClient治理子弹容器    private TankClient tc;    public Missle(int x, int y, Tank.Direction dir, TankClient tc) {        this.x = x;        this.y = y;        this.dir = dir;        this.tc = tc;    }        void move() {        //省略其余关键性代码....        //当子弹的x、y坐标小于0 或者大于游戏窗口的宽度与高度则沦亡状态        if (x < 0 || y < 0 || x > TankClient.GAME_WINDTH || y > TankClient.GAME_HEIGHT) {            this.live = false;            tc.missles.remove(this);        }     //省略其余关键性代码....}

同时当咱们收回炮弹的时候,将tc传给炮弹,让炮弹在沦亡的时候本人去除

class Tank{    //省略其余关键性代码....    //坦克发射子弹.....    public Missle fire(){        //省略其余关键性代码.......        Missle missle =new Missle(x,y,ptdir,tc);        tc.missles.add(missle);        return missle;    }}

步骤总结

  • ✧退出管制炮弹生死的量Live ( Missle )
  • ✧当炮弹曾经死去就不须要对其重画
  • ✧当炮弹飞出边界就死亡
  • ✧当炮弹死亡就从容器中去除

参考资料


尚学堂:坦克大战(马士兵老师)