Home  >  Article  >  Java  >  "Java Mini Game Implementation": Tank Battle (Continued 2)

"Java Mini Game Implementation": Tank Battle (Continued 2)

黄舟
黄舟Original
2016-12-27 11:59:491398browse

"Java Mini Game Implementation": Tank Battle

"Java Mini Game Implementation": Tank Battle (Continued 1)

Blog post "Java Mini Game Implementation": Tank Battle (Continued 1) ) has been implemented so that the tank can fire a bullet. This blog post continues to implement more functions on this basis.

Complete function: tank fires multiple bullets

With the foundation of a tank firing a bullet, firing multiple bullets is quite simple. You only need to add a container to the TankClien class to store it. Just multiple bullets. Since the capacity of the container is also limited, we cannot keep filling it. Therefore, in the bullet class, we introduced a live attribute for the bullet object to determine whether the bullet is still alive. Determining whether the bullet is still alive is based on whether the bullet's position is out of bounds.

Only the code related to completing this function is posted below

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 class

In the move method, according to the location of the bullet Determine if the bullet is still alive.

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

The content of the Tank.java file is as follows:

In the tank class, in the keyPressed method, each time the Ctrl key is pressed, a bullet is fired.

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

Full code download link: http://download.csdn.net/detail/u010412719/9555292

Complete function: solve the tank cross-border problem

Comparison of tank cross-border problem Simple, you only need to determine whether the tank's position crosses the boundary. If it crosses the boundary, set its position to the boundary position.

The implementation code is as follows:

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

The above function can be called at the end of the move() method.

Complete function: add enemy tanks

The functions implemented earlier are to move a tank on the interface, fire bullets, etc.

Now we finish adding an enemy tank to the interface.

There are two ways to implement enemy tanks

1. The first is to create a new EnemyTank class,

2. The second is to add it to the original Tank class A property indicating the type of this tank.

Since we have a tank class, for the sake of convenience, here is the second method: add an attribute to the original Tank class to represent the type of this tank.

The newly added content in Tank.java mainly includes the

<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 class without any changes.

The contents that need to be added to the general housekeeper's TankClient.java are:

1. New creates two tank objects

<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. Draw two tanks in the paint method

<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 Mini Game Implementation: Tank Battle (Continued 2)

vcD4NCjxwPjxjb2RlIGNsYXNzPQ=="hljs cs"> ;The above has implemented the function of adding enemy tanks, but has not yet added random movement to them.

Completed function: bullets kill enemy tanks

After the above implementation, we have a silly enemy tank that cannot move and cannot fire bullets, but we cannot fight it either. Kill it, let's kill the tank next. Haha, isn’t it a little more interesting?

Analysis:

1. Since the bullet killed the enemy tank, according to the object-oriented idea, add a hitTank method to the bullet class

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

2. Then hitTank How should this method be used to determine whether the bullet hit the tank? ? This involves a collision problem. Since our bullets and tanks are both rectangles, the collision problem is greatly simplified. We only need to determine whether the two rectangles overlap. If so, it is judged that a collision occurred and the bullet hit the tank.

Therefore, in the Missile class and the Tank class, add a getRect() method to return the rectangular area object where the bullet and tank are located.

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

3. When the bullet hits the tank, both the bullet and the tank should disappear. Therefore, a Boolean variable needs to be introduced in the tank to determine whether the tank is alive

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

Whether the bullet disappears, it was dealt with in the previous version, but the tank disappears in this version. The current method is not to draw Come out, that is, in the draw method, first check to see if the object is alive. If it is alive, draw it.

The code is as follows:

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

Finally, post the complete code of the Tank class, Missile class, and TankClient class:

Tank class

<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 class

The code is as follows

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

The TankClient class code is as follows:

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

The above completes the function of the tank firing bullets to hit enemy tanks.

Not finished, see the next blog post for the remaining functions

The above is the content of "Java Mini Game Implementation": Tank Battle (continued 2). For more related content, please pay attention to the PHP Chinese website (www. php.cn)!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn