《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>
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)!