坦克大战学习笔记

坦克大战(Java)

本文通过坦克大战的项目开发,来学习Java的绘图技术、事件监听、事件处理、线程、IO流等知识,项目功能还未完善,日后再补:

  • 绘制我的坦克和敌人坦克
  • 我的坦克能自由移动
  • 我的坦克能发射子弹
  • 敌人坦克中弹爆炸
  • 敌人坦克也能自由移动
  • 敌人坦克也能发射子弹
  • 我的坦克中弹也爆炸

代码块

建立一个坦克类:

class Tank {
    // 坦克的横坐标
    int x = 0;
    // 坦克的纵坐标 修改x、y的值就可以使坦克移动
    int y = 0;
    // 坦克的方向
    int direct;
    // 坦克的速度
    int speed = 1;
    // 坦克的颜色,以区分是我的坦克还是敌人的坦克
    int color;

    public int getColor() {
        return color;
    }

    public void setColor(int color) {
        this.color = color;
    }

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    public int getDirect() {
        return direct;
    }

    public void setDirect(int direct) {
        this.direct = direct;
    }

    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;
    }
}

我的坦克

class Hero extends Tank {

    // 子弹是坦克发射出来的,认为它是坦克的一个属性
    Shot myShot = null;
    Vector<Shot> myShots = new Vector<Shot>();

    public Hero(int x, int y) {
        // 利用父类的构造函数来传递子类的变量
        super(x, y);
    }

    // 开火 (坦克的一种动作)
    public void shotEnemy() {

        // 子弹的坐标取决于坦克的位置、方向
        switch (direct) {
        case 0:
            // 创建一颗子弹
            myShot = new Shot(x + 12, y - 7, 0);
            // 把子弹加入到向量中
            myShots.add(myShot);
            break;
        case 1:
            myShot = new Shot(x + 45, y + 18, 1);
            myShots.add(myShot);
            break;
        case 2:
            myShot = new Shot(x + 12, y + 45, 2);
            myShots.add(myShot);
            break;
        case 3:
            myShot = new Shot(x - 10, y + 18, 3);
            myShots.add(myShot);
            break;
        }

        // 启动子弹线程
        Thread t = new Thread(myShot);
        t.start();
    }

    //子弹向上移动
    public void moveUp() {
        y -= speed * 10;
    }

    //向右
    public void moveRight() {
        x += speed * 10;
    }

    //向下
    public void moveDown() {
        y += speed * 10;
    }

    //向左
    public void moveLeft() {
        x -= speed * 10;
    }
}

敌人坦克

class EnemyTank extends Tank implements Runnable {

    //坦克存活
    boolean islive = true;
    //敌人子弹
    Shot enemyShot = null;
    //敌人子弹组
    Vector<Shot> enemyShots = new Vector<Shot>();

    public EnemyTank(int x, int y) {
        super(x, y);
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 坦克往哪个方向,根据惯性就让它往该方向再走几步
            switch (this.direct) {
            case 0:
                //for循环是为了让坦克方向不要变化太快
                for (int i = 0; i < 30; i++) {
                    if (y > 0) {
                        y -= speed;
                    }
                    try {
                        //休眠50ms
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                break;
            case 1:
                for (int i = 0; i < 30; i++) {
                    if (x < 600) {
                        x += speed;
                    }
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                break;
            case 2:
                for (int i = 0; i < 30; i++) {
                    if (y < 500) {
                        y += speed;
                    }
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                break;
            case 3:
                for (int i = 0; i < 30; i++) {
                    if (x > 0) {
                        x -= speed;
                    }
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                break;
            }

            // 让坦克随机产生一个新的方向
            this.direct = (int) (Math.random() * 4);
            // 让坦克死亡后,退出线程
            if (this.islive == false) {
                break;
            }
        }
    }
}

子弹

class Shot implements Runnable {
    int x;
    int y;
    int direct;
    int speed = 20;
    // 是否还活着
    boolean islive = true;

    public Shot(int x, int y, int direct) {
        this.x = x;
        this.y = y;
        this.direct = direct;
    }

    // run函数是构造函数调用的
    @Override
    public void run() {

        while (true) {
            // 让子弹休息一下,避免内存消耗太大
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            switch (direct) {
            case 0:
                y -= speed;
                break;
            case 1:
                x += speed;
                break;
            case 2:
                y += speed;
                break;
            case 3:
                x -= speed;
                break;
            }

            // 判断子弹是否碰到边缘
            if (x < 0 || x > 600 || y < 0 || y > 500) {
                islive = false;
                break;
            }
        }
    }
}

炸弹

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;
        }
    }
}

功能实现类

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;
import javax.swing.*;

public class MyTankGame_2 extends JFrame {

    MyTankPanel mtp = null;
    public int x = 100;
    public int y = 100;

    public MyTankGame_2() {
        mtp = new MyTankPanel(x, y);
        // 启动mtp线程
        Thread thread = new Thread(mtp);
        thread.start();
        this.add(mtp);
        this.addKeyListener(mtp);
        this.setBounds(300, 200, 600, 500);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    public static void main(String[] args) {
        MyTankGame_2 mtg = new MyTankGame_2();
    }

    /**
     * 我的面板
     * 
     * @author PC
     *
     */
    class MyTankPanel extends JPanel implements KeyListener, Runnable {

        // 定义一个我的坦克
        Hero hero = null;

        // 定义敌人的坦克组(采用Vector集合,线程安全)
        Vector<EnemyTank> enemys = new Vector<EnemyTank>();

        // 定义炸弹组
        Vector<Bomb> bombs = new Vector<Bomb>();

        // 敌人的坦克数量
        int enemySize = 3;

        // 定义3张图片,3张图片瞬间切换组成一颗炸弹
        Image image1 = null;
        Image image2 = null;
        Image image3 = null;

        // 构造方法各种初始化
        public MyTankPanel(int x, int y) {
            hero = new Hero(x, y);

            // 初始化敌人的坦克
            for (int i = 0; i < enemySize; i++) {
                // 创建一个敌人坦克对象
                EnemyTank et = new EnemyTank((i + 1) * 50, 0);
                // 启动敌人坦克
                Thread thread = new Thread(et);
                thread.start();
                // 创建敌人的子弹
                Shot enemyShot = new Shot(et.x + 15, et.y + 40, 2);
                Thread threadShot = new Thread(enemyShot);
                threadShot.start();
                // 敌人的坦克颜色
                et.setColor(0);
                // 敌人的坦克方向
                et.setDirect(2);
                // 将敌人对象添加到Vector集合中
                enemys.add(et);
            }

            // 初始化图片
            image1 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_1.gif"));
            image2 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_2.gif"));
            image3 = Toolkit.getDefaultToolkit().getImage(Panel.class.getResource("/bomb_3.gif"));

        }

        /**
         * 重写paint
         */
        public void paint(Graphics g) {

            super.paint(g);
            g.fillRect(0, 0, 600, 500);

            // 画出自己的坦克
            this.drawTank(hero.getX(), hero.getY(), g, this.hero.getDirect(), 0);

            // 从向量中取出每颗子弹,并画出
            for (int i = 0; i < hero.myShots.size(); i++) {
                Shot myShot = hero.myShots.get(i);
                // 画出一颗子弹
                if (myShot != null && myShot.islive == true) {
                    g.draw3DRect(myShot.x, myShot.y, 1, 1, false);
                }

                if (myShot.islive == false) {
                    hero.myShots.remove(myShot);
                }
            }

            // 画出敌人的坦克
            for (int i = 0; i < enemys.size(); i++) {
                EnemyTank et = enemys.get(i);
                if (et.islive) {
                    this.drawTank(et.getX(), et.getY(), g, et.getDirect(), 1);
                    // 再画出敌人的子弹
                    for (int j = 0; j < et.enemyShots.size(); j++) {
                        // 取出子弹
                        Shot es = et.enemyShots.get(j);
                        // 判断子弹有没有效
                        if (es.islive) {
                            g.draw3DRect(es.x, es.y, 1, 1, false);
                        } else {
                            et.enemyShots.remove(es);
                        }
                    }
                } else {
                    enemys.remove(et);
                }
            }

            // 画出炸弹
            for (int i = 0; i < bombs.size(); i++) {
                System.out.println("击中了");
                Bomb b = bombs.get(i);
                if (b.life > 6) {
                    g.drawImage(image1, b.x, b.y, 40, 40, this);
                } else if (b.life > 3) {
                    g.drawImage(image2, b.x, b.y, 40, 40, this);
                } else {
                    g.drawImage(image3, b.x, b.y, 40, 40, this);
                }

                // 让b的生命值减小
                b.lifeDown();
                if (b.life == 0) {
                    bombs.remove(b);
                }
            }
        }

        // 判断子弹是否击中敌人坦克
        public void isHitTank(Shot s, EnemyTank et) {
            switch (et.direct) {
            // 向上、向下
            case 0:
            case 2:
                // 击中
                if (s.x > et.x && s.x < et.x + 30 && s.y > et.y && s.y < et.y + 40) {
                    // 子弹死亡
                    s.islive = false;
                    // 敌人坦克死亡
                    et.islive = false;
                    // 创建一颗炸弹,放入Vector
                    Bomb b = new Bomb(et.x, et.y);
                    bombs.add(b);
                }
            case 1:
            case 3:
                // 击中
                if (s.x > et.x && s.x < et.x + 40 && s.y > et.y && s.y < et.y + 30) {
                    s.islive = false;
                    et.islive = false;
                    // 创建一颗炸弹,放入Vector
                    Bomb b = new Bomb(et.x, et.y);
                    bombs.add(b);
                }
            }
        }

        /**
         * 画出坦克的函数 (坦克的位置,画笔,坦克的方向,坦克的类型)
         * 
         * @param x
         * @param y
         * @param g
         * @param direct
         * @param 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.RED);
                break;
            }

            // 判断方向
            switch (direct) {
            // 向上
            case 0:
                // 画出左边的矩形
                g.fillRect(x, y, 5, 40);
                // 画出右边的矩形
                g.fillRect(x + 20, y, 5, 40);
                // 画出中间的矩形
                g.fillRect(x + 5, y + 5, 20, 30);
                // 画出圆形
                g.setColor(Color.YELLOW);
                g.fillOval(x + 2, y + 9, 19, 19);
                // 画出中间直线
                g.drawLine(x + 12, y - 5, x + 12, y + 20);
                break;
            // 向右
            case 1:
                // 画出上面的矩形
                g.fillRect(x, y + 7, 40, 5);
                // 画出下面的矩形
                g.fillRect(x, y + 32, 40, 5);
                // 画出中间的矩形
                g.fillRect(x + 5, y + 12, 30, 20);
                // 画出圆形
                g.setColor(Color.YELLOW);
                g.fillOval(x + 10, y + 10, 19, 19);
                // 画出中间直线
                g.drawLine(x + 20, y + 20, x + 45, y + 20);
                break;
            // 向下
            case 2:
                // 画出左边的矩形
                g.fillRect(x, y, 5, 40);
                // 画出右边的矩形
                g.fillRect(x + 20, y, 5, 40);
                // 画出中间的矩形
                g.fillRect(x + 5, y + 5, 20, 30);
                // 画出圆形
                g.setColor(Color.YELLOW);
                g.fillOval(x + 2, y + 9, 19, 19);
                // 画出中间直线
                g.drawLine(x + 12, y + 20, x + 12, y + 45);
                break;
            // 向左
            case 3:
                // 画出上面的矩形
                g.fillRect(x, y + 7, 40, 5);
                // 画出下面的矩形
                g.fillRect(x, y + 32, 40, 5);
                // 画出中间的矩形
                g.fillRect(x + 5, y + 12, 30, 20);
                // 画出圆形
                g.setColor(Color.YELLOW);
                g.fillOval(x + 10, y + 10, 19, 19);
                // 画出中间直线
                g.drawLine(x - 10, y + 20, x + 20, y + 20);
                break;
            }
        }

        /**
         * 键盘按下事件
         */
        @Override
        public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_UP) {
                this.hero.setDirect(0);
                this.hero.moveUp();
            } else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
                this.hero.setDirect(1);
                this.hero.moveRight();
            } else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
                this.hero.setDirect(2);
                this.hero.moveDown();
            } else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
                this.hero.setDirect(3);
                this.hero.moveLeft();
            }

            // 判断玩家是否按下J键
            if (e.getKeyCode() == KeyEvent.VK_J) {
                // 开火
                if (hero.myShots.size() < 5) {
                    this.hero.shotEnemy();
                }
            }

            this.repaint();

        }

        @Override
        public void keyReleased(KeyEvent e) {

        }

        @Override
        public void keyTyped(KeyEvent e) {

        }

        @Override
        public void run() {
            // 每隔100ms去重绘
            while (true) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 判断是否击中
                for (int i = 0; i < hero.myShots.size(); i++) {
                    // 取出子弹
                    Shot shot = hero.myShots.get(i);
                    // 子弹存在
                    if (shot.islive) {
                        // 取出坦克
                        for (int j = 0; j < enemys.size(); j++) {
                            EnemyTank et = enemys.get(j);
                            // 判断坦克是否被子弹击中
                            if (et.islive) {
                                this.isHitTank(shot, et);
                            }
                        }
                    }
                }

                // 判断是否需要为敌人坦克添加子弹
                for (int i = 0; i < enemys.size(); i++) {
                    EnemyTank et = enemys.get(i);
                    if (et.islive) {
                        for (int j = 0; j < et.enemyShots.size(); j++) {
                            Shot es = et.enemyShots.get(j);
                            // 没有子弹了
                            if (et.enemyShots.size() < 1) {
                                // 根据坦克方向添加子弹
                                Shot enemyShot = null;
                                switch (et.direct) {
                                case 0:
                                    // 创建一颗子弹
                                    enemyShot = new Shot(et.x + 12, et.y - 7, 0);
                                    // 把子弹加入到向量中
                                    et.enemyShots.add(enemyShot);
                                    break;
                                case 1:
                                    enemyShot = new Shot(et.x + 45, et.y + 18, 1);
                                    et.enemyShots.add(enemyShot);
                                    break;
                                case 2:
                                    enemyShot = new Shot(et.x + 12, et.y + 45, 2);
                                    et.enemyShots.add(enemyShot);
                                    break;
                                case 3:
                                    enemyShot = new Shot(et.x - 10, et.y + 18, 3);
                                    et.enemyShots.add(enemyShot);
                                    break;
                                }
                                // 启动子弹线程
                                Thread t = new Thread(enemyShot);
                                t.start();
                            }
                        }
                    }
                }
                // 重绘
                this.repaint();
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值