04.坦克大战项目-让坦克动起来

04.坦克大战项目-让坦克动起来

01.让自己的坦克动起来

​ 通过前面学习了java事件处理机制和java绘图技术,请试试看如何让自己的坦克可以通过按键控制上右下左(wdsa表示)的移动。

02. 思路和做法

1. 思路

  1. 首先我们要个设计的思路,在前面的章节的准备工作和绘制坦克中,我们创建了四个类。
  2. 在那四个类中我们有专门用于绘画坦克的类
  3. 在绘画坦克的类中,我们需要画出:坦克在处于不同方向(上右下左)时的绘画。
  4. 然后结合我们上一个章节,java事件处理机制来监听键盘,实现坦克的移动

2. 做法

  1. 在MyPanel类中进行坦克处于不同方向上的绘画
  2. 在Tank类中加入两个个新的变量,四个新的方法,名称分别是direct(坦克的方向), speed(坦克移动速度), 四个move方法 (坦克的移动)
  3. 使用键盘来实现坦克的移动
  4. 注意:在这个项目中三个类需要修改.
1. MyPanel类
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

//2. 为了监听键盘事件,实现KeyListener
public class MyPanel extends JPanel implements KeyListener {
    //定义我的坦克
    Hero hero = null;
    public MyPanel() {
        hero = new Hero(100, 100);//初始化自己坦克
//        hero.setSpeed(5); 可以在构造器中修改速度
    }

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

        //画出坦克-封装方法
        drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);
    }
    //编写方法,画出坦克

    /**
     *
     * @param x 坦克的左上角x坐标
     * @param y 坦克的左上角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.yellow);
                break;
        }
        //1. 根据坦克的方向来绘制对应形状的坦克
        //1.1 direct 表示方向(0:向上,1:向右,2:向下,3:向左)
        switch (direct) {
            case 0: //表示向上
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边的轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边的轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克主体
                g.fillOval(x + 10, y + 20, 20,20);//画出坦克盖子
                g.drawLine(x + 20, y + 30, x + 20, y);
                break;
            case 1: //表示向右
                g.fill3DRect(x, y, 60, 10, false);//画出坦克左边的轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克右边的轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克主体
                g.fillOval(x + 20, y + 10, 20,20);//画出坦克盖子
                g.drawLine(x + 30, y + 20, x + 60 , y + 20);//炮筒
                break;
            case 2: //表示向下
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边的轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边的轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克主体
                g.fillOval(x + 10, y + 20, 20,20);//画出坦克盖子
                g.drawLine(x + 20, y + 30, x + 20, y + 60);
                break;
            case 3: //表示向左
                g.fill3DRect(x, y, 60, 10, false);//画出坦克左边的轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克右边的轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克主体
                g.fillOval(x + 20, y + 10, 20,20);//画出坦克盖子
                g.drawLine(x + 30, y + 20, x , y + 20);//炮筒
                break;
        }

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }
    //2.1 处理 wdsa 键按下的情况
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) { //按下w键
            //2.2 改变坦克方向
            hero.setDirect(0);
            //3 修改坦克的坐标,让坦克动起来
            //在此处修改坦克的坐标会使问题变得麻烦
            //我们可以采用封装的方式,在Tank类中编写一个move方法,在此处调用来实现坦克的移动
            hero.moveUp();
        } else if (e.getKeyCode() == KeyEvent.VK_D) {//D键
            hero.setDirect(1);
            hero.moveRight();
        } else if (e.getKeyCode() == KeyEvent.VK_S) {//S键
            hero.setDirect(2);
            hero.moveDown();
        } else if (e.getKeyCode() == KeyEvent.VK_A) {//A键
            hero.setDirect(3);
            hero.moveLeft();
        }
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
}

​ 这个类的主要修改是: 首先在drawTank中Switch新增了坦克在不同方向上的绘画. 然后是实现了KeyListener接口, 来监听键盘事件, wdsa按下的时候 改变方向加移动. 切记:当你的坦克不显示移动时,可能是忘了添加repaint()方法, repaint()方法会重绘画板。

2. Tank类
public class Tank {
    private int x;//坦克的横坐标
    private int y;//坦克的纵坐标
    private int direct;//坦克方向 w上 d右 s下 a左
    private int speed = 1;//速度 快慢(数字大小)

    public int getSpeed() {
        return speed;
    }

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

    public void moveUp() {
        y -= speed;
    }
    public void moveRight() {
        x += speed;
    }
    public void moveDown() {
        y += speed;
    }
    public void moveLeft() {
        x -= speed;
    }

    public int getDirect() {
        return direct;
    }

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

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

    public Tank(int x, int y) {
        this.x = x;
        this.y = y;

    }

}

​ 这个类,我们新增了两个变量direct和speed。然后增加了四个move方法。这几个move方法(修改x和y坐标实现tank移动),在MYPanel中利用这几个方法会更加方便

3. YzjTankGame02
import javax.swing.*;


public class YzjTankGame02 extends JFrame {
    //定义MyPanel
    MyPanel mp = null;
    public static void main(String[] args) {
        YzjTankGame02 yzjTankGame01 = new YzjTankGame02();
    }
    public YzjTankGame02() {
        mp = new MyPanel();
        this.add(mp);//把面板(就是游戏的绘图区域)
        this.setSize(1000, 750);
        this.addKeyListener(mp);//让JFrame 监听mp的键盘事件
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}

修改只有一点:is.addKeyListener(mp);//让JFrame 监听mp的键盘事件

03. 创建三个敌人坦克

1. 分析:

  1. 因为敌人的坦克,是在MyPanel上,所以我们的代码在MyPanel
  2. 因为敌人的坦克,后面有自己特殊的属性和方法,可以单开一个EnemyTank
  3. 敌人坦克数量多,可以放入到集合 Vector,因为考虑多线程问题
1. MyPanel类
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Vector;

//2. 为了监听键盘事件,实现KeyListener
public class MyPanel extends JPanel implements KeyListener {
    //定义我的坦克
    Hero hero = null;
    //4. 定义敌人坦克,放入Vector中
    Vector<EnemyTank> enemyTanks = new Vector<>();
    int enemyTankSize = 3;
    public MyPanel() {
        hero = new Hero(100, 100);//初始化自己坦克
//        hero.setSpeed(5); 可以在构造器中修改速度
        //4.1 初始化敌人的坦克,方向朝下
        for (int i = 0; i < enemyTankSize; i++) {
            //创建一个敌人的坦克
            EnemyTank enemyTank = new EnemyTank((100 * (i + 1)), 0);
            //设置方法
            enemyTank.setDirect(2);
            //加入Vector
            enemyTanks.add(enemyTank);
        }
    }

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

        //画出自己的坦克-封装方法
        drawTank(hero.getX(), hero.getY(), g, hero.getDirect(), 1);

        //4.2 画出敌人的坦克, 遍历Vector
        for (int i = 0; i < enemyTankSize; i++) {
            //4.3 取出坦克
            EnemyTank enemyTank = enemyTanks.get(i);
            drawTank(enemyTank.getX(), enemyTank.getY(), g, enemyTank.getDirect(), 0);
        }

    }
    //编写方法,画出坦克

    /**
     *
     * @param x 坦克的左上角x坐标
     * @param y 坦克的左上角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.yellow);
                break;
        }
        //1. 根据坦克的方向来绘制对应形状的坦克
        //1.1 direct 表示方向(0:向上,1:向右,2:向下,3:向左)
        switch (direct) {
            case 0: //表示向上
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边的轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边的轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克主体
                g.fillOval(x + 10, y + 20, 20,20);//画出坦克盖子
                g.drawLine(x + 20, y + 30, x + 20, y);
                break;
            case 1: //表示向右
                g.fill3DRect(x, y, 60, 10, false);//画出坦克左边的轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克右边的轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克主体
                g.fillOval(x + 20, y + 10, 20,20);//画出坦克盖子
                g.drawLine(x + 30, y + 20, x + 60 , y + 20);//炮筒
                break;
            case 2: //表示向下
                g.fill3DRect(x, y, 10, 60, false);//画出坦克左边的轮子
                g.fill3DRect(x + 30, y, 10, 60, false);//画出坦克右边的轮子
                g.fill3DRect(x + 10, y + 10, 20, 40, false);//画出坦克主体
                g.fillOval(x + 10, y + 20, 20,20);//画出坦克盖子
                g.drawLine(x + 20, y + 30, x + 20, y + 60);
                break;
            case 3: //表示向左
                g.fill3DRect(x, y, 60, 10, false);//画出坦克左边的轮子
                g.fill3DRect(x, y + 30, 60, 10, false);//画出坦克右边的轮子
                g.fill3DRect(x + 10, y + 10, 40, 20, false);//画出坦克主体
                g.fillOval(x + 20, y + 10, 20,20);//画出坦克盖子
                g.drawLine(x + 30, y + 20, x , y + 20);//炮筒
                break;
        }

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }
    //2.1 处理 wdsa 键按下的情况
    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_W) { //按下w键
            //2.2 改变坦克方向
            hero.setDirect(0);
            //3 修改坦克的坐标,让坦克动起来
            //在此处修改坦克的坐标会使问题变得麻烦
            //我们可以采用封装的方式,在Tank类中编写一个move方法,在此处调用来实现坦克的移动
            hero.moveUp();
        } else if (e.getKeyCode() == KeyEvent.VK_D) {//D键
            hero.setDirect(1);
            hero.moveRight();
        } else if (e.getKeyCode() == KeyEvent.VK_S) {//S键
            hero.setDirect(2);
            hero.moveDown();
        } else if (e.getKeyCode() == KeyEvent.VK_A) {//A键
            hero.setDirect(3);
            hero.moveLeft();
        }
        this.repaint();
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
}

主要添加的内容是:注释为4的所有

2. EnemyTank类
public class EnemyTank extends Tank{
    public EnemyTank(int x, int y) {
        super(x, y);
    }
}

你可能感兴趣的:(java,前端,开发语言)