Home  >  Article  >  Java  >  "Java Mini Game Implementation": Tank Battle (continued)

"Java Mini Game Implementation": Tank Battle (continued)

黄舟
黄舟Original
2016-12-27 11:54:411144browse

The last blog post "Java Mini Game Implementation": The tank battle only introduced the ability to control a tank to move in four directions. Today, we will continue to complete small functions one by one based on this.

Completed function: control a tank to move in 8 directions according to the keyboard keys

To complete this function, we need to do a few things

1. Record The key press condition of the keyboard is to rewrite the listening events of keyboard press and lift

采用4个boolean变量来记录,按下为true,抬起为false

The specific implementation code is as follows:

    //定义四个布尔类型变量来记录按键的情况,默认状态下为false,表示没有键按下
        private boolean b_L,b_U,b_R,b_D;
 
    //记录键盘的按键情况
        public void keyMonitor(KeyEvent e){
            int key=e.getKeyCode();
            switch(key){
            case KeyEvent.VK_LEFT:
                b_L=true;
                break;
            case KeyEvent.VK_UP:
                b_U=true;
                break;
            case KeyEvent.VK_RIGHT:
                b_R=true;
                break;
            case KeyEvent.VK_DOWN:
                b_D=true;
                break;
            }
            //根据上面的按键情况,确定坦克即将要运行的方向,即第二步要完成的内容,具体实现看博文下面
            moveDirection();
        }
        //键盘按键松下时,也要进行记录
        public void keyReleased(KeyEvent e) {
            int key=e.getKeyCode();
            switch(key){
            case KeyEvent.VK_LEFT:
                b_L=false;
                break;
            case KeyEvent.VK_UP:
                b_U=false;
                break;
            case KeyEvent.VK_RIGHT:
                b_R=false;
                break;
            case KeyEvent.VK_DOWN:
                b_D=false;
                break;
            }
        }

2. According to the key press condition recorded in 1 Determine the running direction of the tank

8个运行方向采用一个枚举类型来保存。即
        private enum Direction{
            L,LU,U,RU,R,RD,D,LD,STOP
        }
    //例如:如果键盘的左键和下键被按下,则运行方向dir=Direction.LD.
 
    //定义一个变量来表示坦克要运行的方向,初始状态为STOP
        private Direction dir = Direction.STOP;
        //根据键盘的按键情况来确定坦克的运行方向
        private void moveDirection() {//L,LU,U,RU,R,RD,D,LD,STOP
            if(b_L&&!b_U&&!b_R&&!b_D){
                dir = Direction.L;
            }
            else if(b_L&&b_U&&!b_R&&!b_D){
                dir = Direction.LU;
            }
            else if(!b_L&&b_U&&!b_R&&!b_D){
                dir = Direction.U;
            }
            else if(!b_L&&b_U&&b_R&&!b_D){
                dir = Direction.RU;
            }
            else if(!b_L&&!b_U&&b_R&&!b_D){
                dir = Direction.R;
            }
            else if(!b_L&&!b_U&&b_R&&b_D){
                dir = Direction.RD;
            }
            else if(!b_L&&!b_U&&!b_R&&b_D){
                dir = Direction.D;
            }
            else if(b_L&&!b_U&&!b_R&&b_D){
                dir = Direction.LD;
            }
            else{//其它所有情况,都是不动
                dir = Direction.STOP;
            }
 
        }

3. Determine the specific running speed according to the direction of movement in 2. For example, if it moves in the lower left direction, the current position of the tank (x, y)— ->(x-XSPEED,y+YSPEED);where XSPEED and YSPEED are the running speeds of the x and y axes.

        //上面有运行方向,但是还缺少具体的运行细节,例如:假设是按下了右键,则应该横坐标x+=XSPEED;
        private void move(){
            if(dir==Direction.L){//L,LU,U,RU,R,RD,D,LD,STOP
                x -= XSPEED;
            }
            else if(dir==Direction.LU){
                x -= XSPEED;
                y -= YSPEED;
            }
            else if(dir==Direction.U){
                y -= YSPEED;
            }
            else if(dir==Direction.RU){
                x += XSPEED;
                y -= YSPEED;
            }
            else if(dir==Direction.R){
                x += XSPEED;
            }
            else if(dir==Direction.RD){
                x += XSPEED;
                y += YSPEED;
            }
            else if(dir==Direction.D){
                y += YSPEED;
            }
            else if(dir==Direction.LD){
                x -= XSPEED;
                y += YSPEED;
            }
            else if(dir==Direction.STOP){
                //... nothing
            }
 
        }

The complete code of the above three steps is as follows:

    public class Tank {
        //坦克所在的位置坐标
        private int x;
        private int y;
 
        //定义两个常量,表示运动的速度
        private static final int XSPEED = 5;
        private static final int YSPEED = 5;
 
        //定义四个布尔类型变量来记录按键的情况,默认状态下为false,表示没有键按下
        private boolean b_L,b_U,b_R,b_D;
 
        //定义一个枚举类型来表示运行的方向  
        private enum Direction{
            L,LU,U,RU,R,RD,D,LD,STOP
        }
        //定义一个变量来表示坦克要运行的方向,初始状态为STOP
        private Direction dir = Direction.STOP;
 
        public Tank(int x, int y) {
            super();
            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;
        }
 
        public void draw(Graphics g){
 
            Color c = g.getColor();
            g.setColor(Color.RED);
            g.fillOval(x, y, 30, 30);
            g.setColor(c);
 
            move();//根据键盘按键的结果改变坦克所在的位置
        }
 
        //记录键盘的按键情况
        public void keyMonitor(KeyEvent e){
            int key=e.getKeyCode();
            switch(key){
            case KeyEvent.VK_LEFT:
                b_L=true;
                break;
            case KeyEvent.VK_UP:
                b_U=true;
                break;
            case KeyEvent.VK_RIGHT:
                b_R=true;
                break;
            case KeyEvent.VK_DOWN:
                b_D=true;
                break;
            }
            //根据上面的按键情况,确定坦克即将要运行的方向
            moveDirection();
        }
 
        //键盘按键松下时,也要进行记录
        public void keyReleased(KeyEvent e) {
            int key=e.getKeyCode();
            switch(key){
            case KeyEvent.VK_LEFT:
                b_L=false;
                break;
            case KeyEvent.VK_UP:
                b_U=false;
                break;
            case KeyEvent.VK_RIGHT:
                b_R=false;
                break;
            case KeyEvent.VK_DOWN:
                b_D=false;
                break;
            }
        }
 
        //根据键盘的按键情况来确定坦克的运行方向
        private void moveDirection() {//L,LU,U,RU,R,RD,D,LD,STOP
            if(b_L&&!b_U&&!b_R&&!b_D){
                dir = Direction.L;
            }
            else if(b_L&&b_U&&!b_R&&!b_D){
                dir = Direction.LU;
            }
            else if(!b_L&&b_U&&!b_R&&!b_D){
                dir = Direction.U;
            }
            else if(!b_L&&b_U&&b_R&&!b_D){
                dir = Direction.RU;
            }
            else if(!b_L&&!b_U&&b_R&&!b_D){
                dir = Direction.R;
            }
            else if(!b_L&&!b_U&&b_R&&b_D){
                dir = Direction.RD;
            }
            else if(!b_L&&!b_U&&!b_R&&b_D){
                dir = Direction.D;
            }
            else if(b_L&&!b_U&&!b_R&&b_D){
                dir = Direction.LD;
            }
            else{//其它所有情况,都是不动
                dir = Direction.STOP;
            }
 
        }
 
        //上面有运行方向,但是还缺少具体的运行细节,例如:假设是按下了右键,则应该横坐标x+=XSPEED;
        private void move(){
            if(dir==Direction.L){//L,LU,U,RU,R,RD,D,LD,STOP
                x -= XSPEED;
            }
            else if(dir==Direction.LU){
                x -= XSPEED;
                y -= YSPEED;
            }
            else if(dir==Direction.U){
                y -= YSPEED;
            }
            else if(dir==Direction.RU){
                x += XSPEED;
                y -= YSPEED;
            }
            else if(dir==Direction.R){
                x += XSPEED;
            }
            else if(dir==Direction.RD){
                x += XSPEED;
                y += YSPEED;
            }
            else if(dir==Direction.D){
                y += YSPEED;
            }
            else if(dir==Direction.LD){
                x -= XSPEED;
                y += YSPEED;
            }
            else if(dir==Direction.STOP){
                //... nothing
            }
 
        }
 
 
    }

The main modification in the TarkClient.java file rewrites a method of raising the button.

    private class KeyMonitor extends KeyAdapter{
 
        @Override
        public void keyPressed(KeyEvent e) {
            tk.keyMonitor(e);
        }
 
        @Override
        public void keyReleased(KeyEvent e) {
            tk.keyReleased(e);
        }   
 
    }

The above completes the control of the tank running in 8 directions.

Complete function: tanks can shoot bullets

Since it is a tank battle, it must be able to shoot bullets, right? Otherwise, it would be boring.

First, we create a bullet class. The bullet class should also have position and direction attributes, as well as draw methods and move methods.

The code is as follows:

    public class Missile {
 
        //定义两个常量,表示运动的速度
        private static final int XSPEED = 20;
        private static final int YSPEED = 20;
 
        //子弹所在的位置
        private int x;
        private int y;
 
        //子弹的运行方向
        private Direction dir;
 
        public Missile(int x, int y, Direction dir) {
            this.x = x;
            this.y = y;
            this.dir = dir;
        }
        public void draw(Graphics g){
            Color c = g.getColor();
            g.setColor(Color.YELLOW);
            g.fillOval(x, y, 5, 5);
            g.setColor(c);
            move();
        }
 
        private void move() {
            if(dir==Direction.L){//L,LU,U,RU,R,RD,D,LD,STOP
                x -= XSPEED;
            }
            else if(dir==Direction.LU){
                x -= XSPEED;
                y -= YSPEED;
            }
            else if(dir==Direction.U){
                y -= YSPEED;
            }
            else if(dir==Direction.RU){
                x += XSPEED;
                y -= YSPEED;
            }
            else if(dir==Direction.R){
                x += XSPEED;
            }
            else if(dir==Direction.RD){
                x += XSPEED;
                y += YSPEED;
            }
            else if(dir==Direction.D){
                y += YSPEED;
            }
            else if(dir==Direction.LD){
                x -= XSPEED;
                y += YSPEED;
            }
        }
    }

Then, let’s test it by drawing an uncontrolled bullet in the interface.

In the TankClient class, there is Missile object, and then call Missile's draw in paint to draw it.

    public class TankClient extends Frame{
 
        //....无关代码没有显示
        private Missile ms =new Missile(50,50,Direction.D);//一个子弹对象
 
 
        @Override
        public void paint(Graphics g) {
            //直接调用坦克至圣的draw方法
            tk.draw(g); 
            if(ms!=null){
                ms.draw(g);
            }       
 
        }
 
        //....无关代码没有显示
 
    }

Now we have to realize that bullets are fired by the tank by pressing the Ctrl key. Since a tank fires a bullet, there should be a method for firing bullets in the tank class, named fire(), and the return value is a bullet object. The bullet object is initialized with the tank's current position and direction.

        public Missile fire(){
 
            Missile ms = new Missile(x,y,dir);
            return ms;
        }

We want to fire a bullet when the Ctrl key is pressed.

Therefore, in the keyPressed method in the tank class, add the case where the key value is ctrl. Because the Missile object returned by fire() needs to be used to initialize the Missile reference in the TankClient class. Therefore, in the Tank class, you need to hold a reference to TankClient to access the Missile reference in TankClient.

        private TankClient tc;
 
        public Tank(int x, int y) {
            this.x = x;
            this.y = y;
        }
 
        public Tank(int x, int y, TankClient tc) {
            this(x,y);
            this.tc = tc;
        }
    //记录键盘的按键情况
        public void keyPressed(KeyEvent e){
            int key=e.getKeyCode();
            //System.out.println(key);
            switch(key){
            case 17:  //按下Ctrl键时的处理情况,tc是一个TankClient对象,里面有一个子弹的引用
                tc.setMs(fire());
                break;
            case KeyEvent.VK_LEFT:
                b_L=true;
                break;
            case KeyEvent.VK_UP:
                b_U=true;
                break;
            case KeyEvent.VK_RIGHT:
                b_R=true;
                break;
            case KeyEvent.VK_DOWN:
                b_D=true;
                break;
            }
            //根据上面的按键情况,确定坦克即将要运行的方向
            moveDirection();

The code in the TankClient.java class is as follows:

    public class TankClient extends Frame{
 
        private final static int GAME_WIDTH=600;
        private final static int GAME_HEIGHT=600;
 
 
        private Tank tk=new Tank(50,50,this);//将this穿进去初始化TankClient
 
        private Missile ms ;//持有一个Missile的引用
 
        public Missile getMs() {
            return ms;
        }
 
        public void setMs(Missile ms) {
            this.ms = ms;
        }
 
        private Image offScreenImage = null;
        public static void main(String[] args) {
            new TankClient().launchFrame();
        }
 
        @Override
        public void update(Graphics g) {
            if (offScreenImage == null) {
                offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);
            }
            Graphics goffScreen = offScreenImage.getGraphics();// 重新定义一个画虚拟桌布的画笔//
            Color c = goffScreen.getColor();
            goffScreen.setColor(Color.darkGray);
            goffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
            goffScreen.setColor(c);
            paint(goffScreen);
            g.drawImage(offScreenImage, 0, 0, null);
        }
 
        @Override
        public void paint(Graphics g) {
            //直接调用坦克至圣的draw方法
            tk.draw(g); 
            if(ms!=null){
                ms.draw(g);
            }       
 
        }
 
        public void launchFrame(){
 
            this.setTitle("坦克大战");
            this.setLocation(300, 400);
            this.setSize(GAME_WIDTH, GAME_HEIGHT);
            this.setBackground(Color.GRAY);
            //为关闭窗口添加响应
            this.addWindowListener(new WindowAdapter(){
 
                @Override
                public void windowClosing(WindowEvent e) {
                    System.exit(0);
                }
 
            });
            //设置是否允许用户改变窗口的大小,这里限制下,不允许
            this.setResizable(false);
            this.setVisible(true);
 
            new Thread(new MyRepaint()).start();
            this.addKeyListener(new KeyMonitor());
 
        }
 
        private class MyRepaint implements Runnable{
 
            @Override
            public void run() {
                while(true){
                    //每50ms重画一次
                    repaint();
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
 
        }
 
        private class KeyMonitor extends KeyAdapter{
 
            @Override
            public void keyPressed(KeyEvent e) {
                tk.keyPressed(e);
            }
 
            @Override
            public void keyReleased(KeyEvent e) {
                tk.keyReleased(e);
            }   
 
        }
 
    }

The above implements a tank that fires a bullet by pressing the Ctrl key.

Not finished yet! ! !

The above is the content of "Java Mini Game Implementation": Tank Battle (continued). For more related content, please pay attention to the PHP Chinese website (m.sbmmt.com)!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn