首页 Java java教程 《Java小游戏实现》:坦克大战(续2)

《Java小游戏实现》:坦克大战(续2)

Dec 27, 2016 am 11:59 AM
java

《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>
登录后复制

377.png

<喎�"/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类

代码如下

<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>
登录后复制

以上就完成了坦克发射子弹可以击打敌对坦克的功能。

未完,剩余功能见下篇博文

 以上就是《Java小游戏实现》:坦克大战(续2)的内容,更多相关内容请关注PHP中文网(www.php.cn)!


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Java 中的平方根 Java 中的平方根 Aug 30, 2024 pm 04:26 PM

Java 中的平方根指南。下面我们分别通过例子和代码实现来讨论平方根在Java中的工作原理。

Java 中的完美数 Java 中的完美数 Aug 30, 2024 pm 04:28 PM

Java 完美数指南。这里我们讨论定义,如何在 Java 中检查完美数?,示例和代码实现。

Java 中的阿姆斯特朗数 Java 中的阿姆斯特朗数 Aug 30, 2024 pm 04:26 PM

Java 中的阿姆斯特朗数指南。这里我们讨论一下java中阿姆斯特朗数的介绍以及一些代码。

Java 中的随机数生成器 Java 中的随机数生成器 Aug 30, 2024 pm 04:27 PM

Java 随机数生成器指南。在这里,我们通过示例讨论 Java 中的函数,并通过示例讨论两个不同的生成器。

Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

Java 版 Weka 指南。这里我们通过示例讨论简介、如何使用weka java、平台类型和优点。

Java 中的史密斯数 Java 中的史密斯数 Aug 30, 2024 pm 04:28 PM

Java 史密斯数指南。这里我们讨论定义,如何在Java中检查史密斯号?带有代码实现的示例。

Java Spring 面试题 Java Spring 面试题 Aug 30, 2024 pm 04:29 PM

在本文中,我们保留了最常被问到的 Java Spring 面试问题及其详细答案。这样你就可以顺利通过面试。

突破或从Java 8流返回? 突破或从Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一种强大且表达力丰富的处理数据集合的方式。然而,使用Stream时,一个常见问题是:如何从forEach操作中中断或返回? 传统循环允许提前中断或返回,但Stream的forEach方法并不直接支持这种方式。本文将解释原因,并探讨在Stream处理系统中实现提前终止的替代方法。 延伸阅读: Java Stream API改进 理解Stream forEach forEach方法是一个终端操作,它对Stream中的每个元素执行一个操作。它的设计意图是处

See all articles