• 技术文章 >Java >java教程

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

    黄舟黄舟2016-12-27 11:59:49原创732
    《Java小游戏实现》:坦克大战

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

    博文《Java小游戏实现》:坦克大战(续1)中已经实现到了坦克可以发射一颗子弹了。这篇博文在此基础上继续实现更多的功能。

    完成功能:坦克发射多颗子弹

    有了坦克发射一颗子弹的基础,发射多颗子弹就相当简单的,只需要在TankClien类中加入一个容器来存放多枚子弹即可。由于容器的容量也是有限的,我们不能一直往里面装。因此,在子弹类中,我们为子弹对象引入了一个live属性,用来判断这个子弹是否还存活。判断子弹是否还存活是根据子弹的位置是否出界。

    下面只贴出完成这个功能相关代码

    TankClient.java

    <code class="hljs cs">    private List<missile> missiles = new ArrayList<missile> ();
     
        public List<missile> getMissiles() {
            return missiles;
        }
        @Override
        public void paint(Graphics g) {
            //直接调用坦克类的draw方法
            tk.draw(g); 
            //画子弹
            for(int i=0;i<missiles.size();i++){ code="" missile="" ms="missiles.get(i);"></missiles.size();i++){></missile></missile></missile></code>

    Missile.java类

    在move方法中根据子弹所在的位置判断子弹是否还存活。

    <code class="hljs cs"><code class="hljs cs">    public class Missile {
     
            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;
                }
     
                //根据子弹所在的位置x,y来判断子弹是否还存活在
                if(x<0||x>TankClient.GAME_WIDTH||y<0||y>TankClient.GAME_HEIGHT){
                    live = false;
                }
            }
            public boolean isLive() {   
                return live;
            }
        }
    </code></code>

    Tank.java文件内容如下:

    在坦克类中,在keyPressed方法中,每按一次Ctrl键,就发射一颗子弹。

    <code class="hljs cs"><code class="hljs cs">    public class Tank {
     
            //记录键盘的按键情况
            public void keyPressed(KeyEvent e){
                int key=e.getKeyCode();
                //System.out.println(key);
                switch(key){
                case 17:
                    tc.getMissiles().add(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();
            }
     
        }
    </code></code>

    完整代码下载链接:http://download.csdn.net/detail/u010412719/9555292

    完成功能:解决坦克越界问题

    坦克越界问题比较简单,只需要判断坦克所在的位置是否越界,如果越界,则将其位置设置为边界位置即可。

    实现代码如下:

    <code class="hljs cs"><code class="hljs cs">        /*
             * 函数功能:处理坦克越界问题
             * */
            private void dealTankBorder() {
                if(x<0){
                    x = 0;
                } 
                else if(x > TankClient.GAME_WIDTH-this.WIDTH){
                    x = TankClient.GAME_WIDTH-this.WIDTH ;
                } 
                if(y<0){
                     y = 0;
                }
                else if(y>TankClient.GAME_WIDTH - this.HEIGHT){
                     y = TankClient.GAME_WIDTH - this.HEIGHT;
                }
            }</code></code>

    上面函数在move()方法最后进行调用即可。

    完成功能:加入敌人的坦克

    前面实现的所用功能是自己一个坦克在界面上面运动呀、发子弹呀等等。

    下面我们完成在界面上加入一个敌人坦克。

    实现敌人坦克有两种方式

    1、第一种是再新建一个EnemyTank类,

    2、第二种是在原来的Tank类中加入一个属性来表示此坦克的类型。

    由于我们有一个坦克类了,为方便起见,这里采用第二种方式:在原来的Tank类中加入一个属性来表示此坦克的类型。

    Tank.java中新增加的内容主要有

    <code class="hljs cs"><code class="hljs java">    //添加一个属性,表示此坦克是好还是坏
            private boolean good;
     
        //更改下构造方法
     
            public Tank(int x, int y,boolean good) {
                this.x = x;
                this.y = y;
                this.good = good;
            }
     
            public Tank(int x, int y,boolean good, TankClient tc) {
                this(x,y,good);
                this.tc = tc;
            }
        //根据坦克的类型给出不同的颜色
            public void draw(Graphics g){
     
                Color c = g.getColor();
                if(good){
                    g.setColor(Color.RED);
                }
                else{
                    g.setColor(Color.BLUE);
                }
     
                g.fillOval(x, y, WIDTH, HEIGHT);
                g.setColor(c);
                //画一个炮筒
                drawGunBarrel(g);
     
                move();//根据键盘按键的结果改变坦克所在的位置
            }

    Missile类没有任何变动。

    总管家TankClient.java中需要添加的内容有:

    1、new 出两个坦克对象

    <code class="hljs cs"><code class="hljs cs">private Tank tk=new Tank(50,50,true,this);
     
    private Tank enemy = new Tank(100,100,false,this);</code></code>

    2、在paint方法中画出两个坦克

    <code class="hljs cs"><code class="hljs cs">    @Override
        public void paint(Graphics g) {
            //直接调用坦克类的draw方法
            tk.draw(g); 
     
            enemy.draw(g);
            //画子弹
            for(int i=0;i<missiles.size();i++){ code="" missile="" ms="missiles.get(i);"></missiles.size();i++){></code></code>

    377.png

    <喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxjb2RlIGNsYXNzPQ=="hljs cs">以上就实现了添加敌对坦克这一功能,但是还没有对其添加随机运动。

    完成的功能:子弹打死敌人坦克

    经过上面的实现,我们有了一个不会动且不会发子弹的傻傻的敌对坦克,但是我们也不能打死它,下面我们就来实现打死坦克。哈哈,是不是稍微变得有趣一点了。

    分析:

    1、由于是子弹打死敌人坦克,根据面向对象的思想,在子弹类中,加入一个hitTank方法

    <code class="hljs cs"><code class="hljs cs"><code>public boolean hitTank(Tank t){
     
    }
    </code></code></code>

    2、那么hitTank这个方法应该如何来判断是否子弹打中了该坦克呢??这就涉及到一个碰撞的问题。由于我们的子弹和坦克都是矩形,因此碰撞问题就得到了很好的简化,只是判断两个矩形是否有重叠的部分。如果有,则就判断发生了碰撞,子弹就打中了坦克。

    因此,在Missile类和Tank类中,,均添加一个getRect()方法,返回子弹和坦克所在的矩形区域对象。

    <code class="hljs cs"><code class="hljs cs"><code>public Rectangle getRect(){
            return new Rectangle(x, y, WIDTH, HEIGHT);
    }
    </code></code></code>

    3、当子弹打中了坦克,则子弹和坦克就应该都消失。因此,在坦克中需要引入一个布尔变量来判断坦克是否存活

    <code class="hljs cs"><code class="hljs cs"><code class="hljs java">    public boolean hitTank(Tank t){
            //首先判断此坦克是否是存活的,如果是死的,就不打了
            if(!t.isLive()){
                return false;
            }
            if(this.getRect().intersects(t.getRect())){//判断是否有碰撞
                //碰撞之后,子弹和该坦克就应该都死了
                this.live = false;//子弹死了
                t.setLive(false);//坦克死了
                return true;
            }
            else{
                return false;
            }
        }</code></code></code>

    无论是子弹消失,在前面的版本中有处理,但是本版本上的坦克消失,目前的处理方法就是不绘画出来,即在draw方法中,首先判断一下,看此对象是否存活,如果存活,则绘画出来。

    代码如下:

    <code class="hljs cs"><code class="hljs cs"><code class="hljs cs">        public void draw(Graphics g){
                if(!live){      //判断坦克是否存活,如果死了,则不绘画出来,直接返回     
                    return ;
                }
                Color c = g.getColor();
                if(good){
                    g.setColor(Color.RED);
                }
                else{
                    g.setColor(Color.BLUE);
                }
     
                g.fillOval(x, y, WIDTH, HEIGHT);
                g.setColor(c);
                //画一个炮筒
                drawGunBarrel(g);
     
                move();//根据键盘按键的结果改变坦克所在的位置
            }
    </code></code></code>

    最后,贴下Tank类、Missile类、TankClient类的完整代码:

    Tank类

    <code class="hljs cs"><code class="hljs cs"><code class="hljs java">    public class Tank {
            //坦克所在的位置坐标
            private int x;
            private int y;
     
            //坦克的高度和宽度
            private static final int WIDTH = 30;
            private static final int HEIGHT = 30;
     
            //定义两个常量,表示运动的速度
            private static final int XSPEED = 5;
            private static final int YSPEED = 5;
     
            //定义四个布尔类型变量来记录按键的情况,默认状态下为false,表示没有键按下
            private boolean b_L,b_U,b_R,b_D;
     
            //添加一个属性,表示此坦克是好还是坏
            private boolean good;
     
            public boolean isGood() {
                return good;
            }
     
            //用来标识此坦克对象是否存活
            private boolean live =true;
     
            public boolean isLive() {
                return live;
            }
     
            public void setLive(boolean live) {
                this.live = live;
            }
            //定义一个枚举类型来表示运行的方向  
            public enum Direction{
                L,LU,U,RU,R,RD,D,LD,STOP
            }
            //定义一个变量来表示坦克要运行的方向,初始状态为STOP
            private Direction dir = Direction.STOP;
     
            //炮筒方向
            private Direction ptDir = Direction.D;
     
            private TankClient tc;
     
            public Tank(int x, int y,boolean good) {
                this.x = x;
                this.y = y;
                this.good = good;
            }
     
            public Tank(int x, int y,boolean good, TankClient tc) {
                this(x,y,good);
                this.tc = tc;
            }
     
            public void draw(Graphics g){
                if(!live){      //判断坦克是否存活,如果死了,则不绘画出来,直接返回     
                    return ;
                }
                Color c = g.getColor();
                if(good){
                    g.setColor(Color.RED);
                }
                else{
                    g.setColor(Color.BLUE);
                }
     
                g.fillOval(x, y, WIDTH, HEIGHT);
                g.setColor(c);
                //画一个炮筒
                drawGunBarrel(g);
     
                move();//根据键盘按键的结果改变坦克所在的位置
            }
     
            private void drawGunBarrel(Graphics g) {
                int centerX = this.x + this.WIDTH/2;
                int centerY = this.y + this.HEIGHT/2;
     
                if(ptDir==Direction.L){//L,LU,U,RU,R,RD,D,LD,STOP
                    g.drawLine(centerX, centerY, x, y + HEIGHT/2);
                }
                else if(ptDir==Direction.LU){
                    g.drawLine(centerX, centerY, x, y );
                }
                else if(ptDir==Direction.U){
                    g.drawLine(centerX, centerY, x+ WIDTH/2, y );
                }
                else if(ptDir==Direction.RU){
                    g.drawLine(centerX, centerY, x + WIDTH, y );
                }
                else if(ptDir==Direction.R){
                    g.drawLine(centerX, centerY, x+ WIDTH, y + HEIGHT/2);
                }
                else if(ptDir==Direction.RD){
                    g.drawLine(centerX, centerY, x+ WIDTH, y + HEIGHT);
                }
                else if(ptDir==Direction.D){
                    g.drawLine(centerX, centerY, x+ WIDTH/2, y + HEIGHT);
                }
                else if(ptDir==Direction.LD){
                    g.drawLine(centerX, centerY, x, y + HEIGHT);
                }
     
            }
     
            //记录键盘的按键情况
            public void keyPressed(KeyEvent e){
                int key=e.getKeyCode();
                //System.out.println(key);
                switch(key){
    //          case 17://避免因Ctrl一直按下,一直发射子弹,因此将这一功能放入keyReleased方法中了
    //              tc.getMissiles().add(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();
            }
     
            //键盘按键松下时,也要进行记录
            public void keyReleased(KeyEvent e) {
                int key=e.getKeyCode();
                switch(key){
                case 17:
                    tc.getMissiles().add(fire());
                    break;
                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;
                }
                //将坦克方向赋值给炮筒方向
                if(dir!=Direction.STOP){
                    ptDir = dir;
                }
     
            }
     
            //上面有运行方向,但是还缺少具体的运行细节,例如:假设是按下了右键,则应该横坐标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
                }
     
                //处理坦克越界问题
                dealTankBorder();       
            }
            /*
             * 函数功能:处理坦克越界问题
             * */
            private void dealTankBorder() {
                if(x<0){
                    x = 0;
                } 
                else if(x > TankClient.GAME_WIDTH-this.WIDTH){
                    x = TankClient.GAME_WIDTH-this.WIDTH ;
                } 
                if(y<0){
                     y = 0;
                }
                else if(y>TankClient.GAME_WIDTH - this.HEIGHT){
                     y = TankClient.GAME_WIDTH - this.HEIGHT;
                }
            }
     
            public Missile fire(){
                //计算子弹的位置,并利用炮筒的方向来new一个子弹对象
                int x = this.x +(this.WIDTH)/2 - (Missile.WIDTH)/2;
                int y = this.y + (this.HEIGHT)/2 -(Missile.HEIGHT)/2;
                Missile ms = new Missile(x,y,this.ptDir);
                return ms;
            }
            /*
             * 函数功能:得到坦克所在位置的矩形框
             * */
            public Rectangle getRect(){
                return new Rectangle(x, y, WIDTH, HEIGHT);
            }
     
        }</code></code></code>

    Missile类

    代码如下

    <code class="hljs cs"><code class="hljs cs"><code class="hljs java">    public class Missile {
     
            //定义两个常量,表示运动的速度
            private static final int XSPEED = 10;
            private static final int YSPEED = 10;
     
            //子弹所在的位置
            private int x;
            private int y;
     
            //坦克的高度和宽度
            public static final int WIDTH = 10;
            public static final int HEIGHT = 10;
     
            //子弹的运行方向
            private Direction dir;
     
            private boolean live = true;
     
            public Missile(int x, int y, Direction dir) {
                this.x = x;
                this.y = y;
                this.dir = dir;
            }
            public void draw(Graphics g){
                //如果该子弹不是存活的,则不进行绘图
                if(!live){
                    return ;
                }
                Color c = g.getColor();
                g.setColor(Color.YELLOW);
                g.fillOval(x, y, WIDTH, HEIGHT);
                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;
                }
     
                //根据子弹所在的位置x,y来判断子弹是否还存活在
                if(x<0||x>TankClient.GAME_WIDTH||y<0||y>TankClient.GAME_HEIGHT){
                    live = false;
                }
            }
            public boolean isLive() {   
                return live;
            }
     
            public Rectangle getRect(){
                return new Rectangle(x, y, WIDTH, HEIGHT);
            }
     
            public boolean hitTank(Tank t){
                //首先判断此坦克是否是存活的,如果是死的,就不打了
                if(!t.isLive()){
                    return false;
                }
                if(this.getRect().intersects(t.getRect())){//判断是否有碰撞
                    //碰撞之后,子弹和该坦克就应该都死了
                    this.live = false;//子弹死了
                    t.setLive(false);//坦克死了
                    return true;
                }
                else{
                    return false;
                }
            }
    </code></code></code>

    TankClient类代码如下:

    <code class="hljs cs"><code class="hljs cs"><code class="hljs java">    /*
         * 此版本添加了子弹打死敌对坦克
         * */
        public class TankClient extends Frame{
     
            public final static int GAME_WIDTH=600;
            public final static int GAME_HEIGHT=600;
     
     
            private Tank tk=new Tank(50,50,true,this);
     
            private Tank enemy = new Tank(100,100,false,this);
     
            private List<missile> missiles = new ArrayList<missile> ();
     
            public List<missile> getMissiles() {
                return missiles;
            }
     
            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);         
                enemy.draw(g);
                //画子弹
                for(int i=0;i<missiles.size();i++){ 
                catch="" code="" extends="" implements="" interruptedexception="" keyevent="" keymonitor="" missile="" ms="missiles.get(i);" myrepaint="" new="" 
                override="" private="" public="" try="" void="" windowevent=""></missiles.size();i++){></missile></missile></missile></code></code></code>

    以上就完成了坦克发射子弹可以击打敌对坦克的功能。

    未完,剩余功能见下篇博文

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

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

    相关文章推荐

    • 【活动】充值PHP中文网VIP即送云服务器• 一文带你认识Java栈和队列• 一文掌握Java8新特性Stream流的概念和使用• Java线程学习之并发编程知识点• 完全掌握Java中的抽象类和接口• Java中的set集合如何理解
    1/1

    PHP中文网