• 技术文章 >Java >java教程

    《Java小游戏实现》:坦克大战(续一)

    黄舟黄舟2016-12-27 11:54:41原创592
    上篇博文《Java小游戏实现》:坦克大战只介绍到了能够控制一个坦克在4个方向上移动就结束了,今天就在此基础上继续完成一个一个的小功能。

    完成的功能:根据键盘的按键控制一个坦克在8个方向上移动

    要完成这个功能,我们要做一下几个事情

    1、记录下键盘的按键情况,即要重写键盘按下和抬起的监听事件

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

    具体实现的代码如下:

    <code class="hljs java">    //定义四个布尔类型变量来记录按键的情况,默认状态下为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;
                }
            }</code>

    2、根据1中所记录的按键情况来确定坦克的运行方向

    <code class="hljs dos">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;
                }
     
            }
    </code>

    3、根据2中的运动方向来确定具体的运行快慢等情况,例如,如果是像左下方向运动,则坦克目前所在的位置(x,y)—->(x-XSPEED,y+YSPEED);其中XSPEED、YSPEED为x、y轴的运行速度。

    <code class="hljs rust">        //上面有运行方向,但是还缺少具体的运行细节,例如:假设是按下了右键,则应该横坐标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
                }
     
            }</code>

    上面三步完整代码代码如下:

    <code class="hljs java">    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
                }
     
            }
     
     
        }</code>

    而在TarkClient.java文件中主要修改的地方重写了一个按键抬起的方法。

    <code class="hljs java">    private class KeyMonitor extends KeyAdapter{
     
            @Override
            public void keyPressed(KeyEvent e) {
                tk.keyMonitor(e);
            }
     
            @Override
            public void keyReleased(KeyEvent e) {
                tk.keyReleased(e);
            }   
     
        }</code>

    以上就完成了控制坦克在8个方向上的运行。

    完成功能:坦克可以打出子弹

    既然是坦克大战,必须要可以打出子弹,是吧,否则,多没意思呀。

    首先,我们建立一个子弹类,子弹类中也应该有位置和方向属性,以及draw方法和move方法。

    代码如下:

    <code class="hljs java">    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;
                }
            }
        }
    </code>

    然后,我们来测试下,在界面中画出一颗不受控制的子弹出来,

    在TankClient类中,有一个Missile对象,然后在paint中调用Missile的draw画出来即可。

    <code class="hljs java">    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);
                }       
     
            }
     
            //....无关代码没有显示
     
        }</code>

    现在我们来实现子弹是按下Ctrl键由坦克发射出来。既然是坦克发出一颗子弹,那么在坦克类中就应该有一个发子弹的方法,取名为fire(),返回值为一个子弹对象。子弹对象有坦克当前的位置以及方向来进行初始化。

    <code class="hljs cs">        public Missile fire(){
     
                Missile ms = new Missile(x,y,dir);
                return ms;
            }
    </code>

    我们要按下Ctrl键时,发射一颗子弹。

    因此,在坦克类中的keyPressed方法中,添加键值是ctrl的情况。由于fire()返回的Missile对象需要用来初始化TankClient类中的Missile引用。因此,在Tank类中,需要持有一个TankClient的引用,借此访问TankClient中的Missile引用。

    <code class="hljs cs">        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();

    而TankClient.java类中的代码如下:

    <code class="hljs java">    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);
                }   
     
            }
     
        }
    </code>

    以上就实现了一个坦克按下Ctrl键就发射一颗子弹。

    未完!!!

    以上就是《Java小游戏实现》:坦克大战(续一)的内容,更多相关内容请关注PHP中文网(m.sbmmt.com)!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:Java
    上一篇:Java高级教程:javadoc输出什么 下一篇:《Java小游戏实现》:坦克大战(续2)
    20期PHP线上班

    相关文章推荐

    • 【活动】充值PHP中文网VIP即送云服务器• JAVA接口与抽象类详细解析• Java基础之volatile详解• Java实现多线程的四种方式• Java中super关键字的用法详解• 归纳整理Java线程面试题
    1/1

    PHP中文网