"Java 미니 게임 구현": 탱크 배틀
"Java 미니 게임 구현": 탱크 배틀(계속 1)
블로그 게시물 "Java 미니 게임 구현": 탱크 배틀(계속) 1) ) 탱크에서 총알을 발사할 수 있도록 구현되었습니다. 이 블로그 게시물은 이를 기반으로 계속해서 더 많은 기능을 구현합니다.
전체 기능: 탱크가 여러 개의 총알을 발사합니다
탱크가 총알 하나를 발사하는 것을 기본으로 여러 총알을 발사하는 것은 매우 간단합니다. TankClien 클래스에 컨테이너를 추가하기만 하면 됩니다. .. 총알이 여러 개뿐입니다. 용기의 용량도 제한되어 있기 때문에 계속 채울 수는 없습니다. 따라서 bullet 클래스에서는 총알이 아직 살아 있는지 확인하기 위해 bullet 객체에 대한 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 클래스를 생성하는 것이고,
두 번째는 원래 탱크에 추가하는 것입니다. class 이 탱크의 유형을 나타내는 속성입니다.
이미 탱크 클래스가 있으므로 편의상 두 번째 방법이 있습니다. 원래 탱크 클래스에 속성을 추가하여 탱크 유형을 나타냅니다.
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 클래스에는 변화가 없습니다.
General Manager TankClient.java에 추가해야 할 내용은 다음과 같습니다.
1. 두 개의 새로운 탱크 객체를 생성합니다.
<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. 페인트 방식 탱크
<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. 총알이 적 탱크를 죽였기 때문에 객체지향적 아이디어에 따라 bullet 클래스에 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>
총알이 사라지는지 여부는 이전 버전에서는 처리되었으나 이번 버전에서는 탱크가 사라집니다. 현재 처리 방법은 그리지 않고, 즉 그리기 방법에서는 먼저 객체가 살아 있는지 확인하여 그린다.
코드는 다음과 같습니다.
<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>
위로 탱크의 기능이 완성됩니다. 적의 탱크를 공격하기 위해 총알을 발사합니다.
아직 완성되지 않았으니 남은 기능은 다음 블로그 포스팅을 참고하세요
위 내용은 "자바 미니게임 구현"의 내용입니다: 탱크 배틀(계속 2) PHP 중국어 홈페이지(www.php.cn)를 주목해주세요!