首頁 > Java > java教程 > 主體

《Java小遊戲實現》:坦克大戰(續2)

黄舟
發布: 2016-12-27 11:59:49
原創
1440 人瀏覽過

《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>
登入後複製

《Java小遊戲實現》:坦克大戰(續2)

< 喎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類

完成了坦克發射子彈可以擊打敵對坦克的功能。

未完,剩餘功能見下篇博文

 以上就是《Java小遊戲實現》:坦克大戰(續2)的內容,更多相關內容請關注PHP中文網(www.php.cn)!


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!