首頁  >  文章  >  Java  >  《Java小遊戲實現》:坦克大戰(續一)

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

黄舟
黄舟原創
2016-12-27 11:54:411202瀏覽

上篇博文《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中文網(www.php.cn)!


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn