坦克大战进阶--发射子弹

坦克大战进阶–发射子弹

1. 坦克大战0.3

1.1 分析

利用线程基础的知识,把坦克大战再次进阶一下:当我们按下J键,坦克就能够发射一颗子弹。

1.2 思路

  1. 当发射一颗子弹后,就相当于启动一个线程
  2. Mytank 有子弹的对象,当按下J时,我们就启动一个发射行为(线程),让子弹不停的移动,形成一个射击的效果
  3. 我们MyPanel需要不停的重绘子弹,才能出现该效果
  4. 当子弹移动到面板的边界时,就应该销毁(把启动的子弹的线程销毁)

1.3 代码实现

  • 父类 Tank
public class Tank {
   
    private int x;//坦克的横坐标
    private int y;//坦克的纵坐标

    //坦克的方向 0向上 1向右 2向下 3向左
    private int direction;
    //坦克的速度
    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;
    }
}
  • 敌人坦克 EnemyTank
public class EnemyTank extends Tank{
   

    public EnemyTank(int x, int y) {
   
        super(x, y);
    }
}
  • 我们的坦克 MyTank
public class MyTank extends Tank {
   
    //定义一个shot对象,表示一个射击行为(线程)
    Shot shot = null;
    public MyTank(int x, int y) {
   
        super(x, y);
    }

    public void shotEnemyTank(){
   
        //创建shot对象
        switch (getDirection()){
   
            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();
    }
}
  • 子弹 Shot
public class Shot implements Runnable {
   //射击子弹
    int x;//子弹x坐标
    int y;//子弹y坐标
    int direction;//子弹方向
    int speed = 2;//子弹速度
    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) {
   
            try {
   //让子弹休眠一下
                Thread.sleep(50);
            } catch (InterruptedException e) {
   
                throw new RuntimeException(e);
            }
            //根据方向来改变x,y坐标
            switch (direction) {
   
                case 0://向上
                    y -= speed;
                    break;
                case 1://向右
                    x += speed;
                    break;
                case 2://向下
                    y += speed;
                    break;
                case 3://向左
                    x -= speed;
                    break;
            }
            //这里用于调试,输入子弹坐标
            System.out.println("子弹x =" + x + " y =" + y);
            //当子弹超出边界就销毁子弹
            if (!(x > 0 && x < 1000 && y > 0 && y < 750)) {
   
                isLive = false;
                break;
            }
        }
    }
}
  • 面板显示 MyPanel
//为了监听键盘事件,实现 KeyListener
//为了让panel不停的重绘,实现 Runnable,当做一个线程使用
public class MyPanel extends JPanel implements KeyListener, Runnable {
   
    //定义我的坦克
    MyTank myTank = null;
    //定义敌人坦克,放入到 Vector 
    Vector<EnemyTank> enemyTanks = new Vector<>();
    int enemyTanksize = 3;

    public MyPanel() {
   
        //初始化自己的坦克
        myTank = new MyTank(100, 100);
        //初始化敌人的坦克
        for (int i = 0; i < enemyTanksize; i++) {
   
            EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);
            enemyTank.setDirection(2);
            enemyTanks.add(enemyTank);
        }
    }

    @Override
    public void paint(Graphics g) {
   
        super.paint(g);
        //设置填充矩形,默认黑色
        g.fillRect(0, 0, 1000, 750);

        myTank.setSpeed(5);
        //画出坦克-封装方法
        //自己的坦克
        drawTank(myTank.getX(), myTank.getY(), g, myTank.getDirection(), 1);

        //画出自己的子弹
        if (myTank.shot != null && myTank.shot.isLive == true) {
   
            g.draw3DRect(myTank.shot.x, myTank.shot.y, 5, 5, true);
        }
        //敌人的坦克
        for (int i = 0; i < enemyTanksize; i++) {
   
            EnemyTank enemyTank = enemyTanks.get(i);
            drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirection(), 0);
        }
    }
    //编写方法,画出坦克

    /**
     * @param x         坦克的左上角x坐标
     * @param y         坦克的左上角y坐标
     * @param g         画笔
     * @param direction 坦克的方向
     * @param type      坦克的类型
     */
    public void drawTank(int x, int y, Graphics g, int direction, int type) {
   
        switch (type) {
   
            case 0://敌人的坦克
                g.setColor(Color.cyan);
                break;
            case 1://我们的坦克
                g.setColor(Color.yellow);
                break;
        }
        //根据坦克的方向,来绘制坦克
        switch (direction) {
   //0向上 1向右 2向下 3向左
            case 0://默认方向向上
                // 先画第一个矩形 大小 10*60
                //坦克左边轮子
                // 定点(x,y)
                g.fill3DRect(x, y, 10, 60, false);
                // 第二个矩形 大小 20*40
                //坦克身体
                // 定点(x+10,y+10)
                g.fill3DRect(x + 10, y + 10, 20, 40, false);
                // 第三个矩形 大小 10*60
                //坦克右边轮子
                // 定点(x+30,y)
                g.fill3DRect(x + 30, y, 10, 60, false);
                // 上面的圆盖子 大小 (20,20)
                // 定点(x+10,y+20)
                g.fillOval(x + 10, y + 20, 20, 20);
                // 最后的炮管
                // 定点1 (x+20,y)
                // 定点2 (x+20,y+30)
                g.drawLine(x + 20, y, x + 20, y + 30);
                // 画出子弹
                g.drawLine(x + 20, y, x + 20, y + 5);

                break;
            case 1://默认方向向右
                // 先画第一个矩形 大小 60*10
                //坦克上边轮子
                g.fill3DRect(x, y, 60, 10, false);
                // 第二个矩形 大小 40*20
                //坦克身体
                g.fill3DRect(x + 10, y + 10, 40, 20, false);
                // 第三个矩形 大小 10*60
                //坦克下边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);
                // 上面的圆盖子 大小 (20,20)
                g.fillOval(x + 20, y + 10, 20, 20);
                // 最后的炮管
                g.drawLine(x + 60, y + 20, x + 30, y + 20);
                // 画出子弹
                g.drawLine(x + 60, y + 20, x + 55, y + 20);
                break;
            case 2://默认方向向下
                // 先画第一个矩形 大小 10*60
                //坦克左边轮子
                g.fill3DRect(x, y, 10, 60, false);
                // 第二个矩形 大小 20*40
                //坦克身体
                g.fill3DRect(x + 10, y + 10, 20, 40, false);
                // 第三个矩形 大小 10*60
                //坦克右边轮子
                g.fill3DRect(x + 30, y, 10, 60, false);
                // 上面的圆盖子 大小 (20,20)
                g.fillOval(x + 10, y + 20, 20, 20);
                // 最后的炮管
                g.drawLine(x + 20, y + 60, x + 20, y + 30);
                // 画出子弹
                g.drawLine(x + 20, y + 60, x + 20, y + 55);
                break;
            case 3://默认方向向左
                // 先画第一个矩形 大小 60*10
                //坦克上边轮子
                g.fill3DRect(x, y, 60, 10, false);
                // 第二个矩形 大小 40*20
                //坦克身体
                g.fill3DRect(x + 10, y + 10, 40, 20, false);
                // 第三个矩形 大小 10*60
                //坦克下边轮子
                g.fill3DRect(x, y + 30, 60, 10, false);
                // 上面的圆盖子 大小 (20,20)
                g.fillOval(x + 20, y + 10, 20, 20);
                // 最后的炮管
                g.drawLine(x, y + 20, x + 30, y + 20);
                // 画出子弹
                g.drawLine(x, y + 20, x + 5, y + 20);
                break;
            default:
                System.out.println("暂时不作处理");
        }
    }

    @Override
    public void keyTyped(KeyEvent e) {
   

    }

    //处理 wsad 按下的情况
    @Override
    public void keyPressed(KeyEvent e) {
   
        if (e.getKeyCode() == KeyEvent.VK_W) {
   
            //改变坦克的方向
            myTank.setDirection(0);
            myTank.moveUp();
        } else if (e.getKeyCode() == KeyEvent.VK_S) {
   
            myTank.setDirection(2);
            myTank.moveDown();
        } else if (e.getKeyCode() == KeyEvent.VK_A) {
   
            myTank.setDirection(3);
            myTank.moveLeft();
        } else if (e.getKeyCode() == KeyEvent.VK_D) {
   
            myTank.setDirection(1);
            myTank.moveRight();
        }

        //如果用户按下J键,就是发射子弹
        if (e.getKeyCode() == KeyEvent.VK_J) {
   
            myTank.shotEnemyTank();//发射子弹
        }
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {
   

    }

    //让子弹不停的重绘
    @Override
    public void run() {
   
        while (true) {
   
            try {
   //每隔200毫秒,重绘
                Thread.sleep(100);
            } 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dominator945

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值