乐趣区

关于java:我所知道坦克大战单机版之画出炮筒让坦克发射多发炮弹让炮弹消亡

本章目标

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

一、画出炮筒


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

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

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)
  • ✧当炮弹曾经死去就不须要对其重画
  • ✧当炮弹飞出边界就死亡
  • ✧当炮弹死亡就从容器中去除

参考资料


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

退出移动版