Java面向对象学习练习———潜艇游戏(飞机游戏)

潜艇游戏需求:

  • 所参与的角色:
    • 战舰、深水炸弹、侦察潜艇、鱼雷潜艇、水雷潜艇、水雷
  • 角色间的关系:
    • 战舰发射深水炸弹
    • 深水炸弹可以打潜艇(侦察潜艇、鱼雷潜艇、水雷潜艇),若打中:
      • 潜艇消失、深水炸弹消失
      • 得东西:
        • 打掉侦察潜艇,玩家得10分
        • 打掉鱼雷潜艇,玩家得40分
        • 打掉水雷潜艇,战舰得1条命
    • 水雷潜艇可以发射水雷
    • 水雷可以击打战舰,若击中:
      • 水雷消失
      • 战舰减1条命(命数为0时游戏结束)

潜艇游戏第一天:

  1. 根据参与的角色创建6个类,创建World类并测试;                                                                    

潜艇游戏第二天:

  1. 给6个类添加构造方法,并测试;(以战舰类为例)                                                                 
    /** 战舰 */
    public class Battleship {
        int width;  //宽
        int height; //高
        int x;      //x坐标
        int y;      //y坐标
        int speed;  //移动速度
        int life;   //命数
        /** 构造方法 */
        Battleship(){
            width = 66;
            height = 26;
            x = 270;
            y = 124;
            speed = 20;
            life = 5;
        }
        void move(){
            System.out.println("战舰移动啦!");
        }
    }

潜艇游戏第三天:

  1. 在World类中创建侦察潜艇数组、鱼雷潜艇数组、水雷潜艇数组,水雷数组,炸弹数组,并测试;                                                                                                                                           
    /** 整个窗口世界 */
    public class World {
        public static void main(String[] args) {
            ObserveSubmarine[] oses = new ObserveSubmarine[3];
            oses[0] = new ObserveSubmarine();
            oses[1] = new ObserveSubmarine();
            oses[2] = new ObserveSubmarine();
            for(int i=0;i<oses.length;i++){ //遍历所有侦察潜艇
                System.out.println(oses[i].x+","+oses[i].y); //输出每个侦察潜艇的x和y坐标
                oses[i].move(); //每个侦察潜艇移动
            }
    
            Mine[] ms = new Mine[2];
            ms[0] = new Mine(100,200);
            ms[1] = new Mine(125,345);
            for(int i=0;i< ms.length;i++){ //遍历所有水雷
                System.out.println(ms[i].x+","+ms[i].y+","+ms[i].speed);
                ms[i].move();
            }
    
            TorpedoSubmarine[] tses = new TorpedoSubmarine[2];
            MineSubmarine[] mses = new MineSubmarine[3];
            Bomb[] bs = new Bomb[4];
    
        }
    }
  2. 设计SeaObject超类,6个类继承超类;(以战舰类为例)
    /** 战舰 */
    public class Battleship extends SeaObject {
        int life;   //命数
        /** 构造方法 */
        Battleship(){
            super(66,26,270,124,20);
            life = 5;
        }
    }
  3. 在SeaObject中设计两个构造方法,6个派生类分别调用;    
    import java.util.Random;
    /** 海洋对象 */
    public class SeaObject {
        int width;  //宽
        int height; //高
        int x;      //x坐标
        int y;      //y坐标
        int speed;  //移动速度
        /** 专门给侦察潜艇、鱼雷潜艇、水雷潜艇提供的 */
        //因为三种潜艇的width/height的值都是不一样的,所以数据不能写死,需传参写活
        //因为三种潜艇的x/y/speed的值都是一样的,所以数据可以写死,不需要传参
        SeaObject(int width,int height){
            this.width = width;
            this.height = height;
            x = -width; //负的潜艇的宽
            Random rand = new Random(); //随机数对象
            y = rand.nextInt(479-height-150+1)+150; //150到(窗口高-潜艇高)之间的随机数
            speed = rand.nextInt(3)+1; //1到3之内的随机数
        }
        /** 专门给战舰、水雷、炸弹提供的 */
        //因为三种对象的width/height/x/y/speed都是不一样的,所以数据不能写死,需传参写活
        SeaObject(int width,int height,int x,int y,int speed){
            this.width = width;
            this.height = height;
            this.x = x;
            this.y = y;
            this.speed = speed;
        }
        void move(){
            System.out.println("海洋对象移动啦!");
        }
    }

潜艇游戏第四天:

  1. 将侦察潜艇数组、鱼雷潜艇数组、水雷潜艇数组统一组合为SeaObject超类数组,在World类中改写并测试;
    /** 整个窗口世界 */
    public class World extends JPanel { //2.
        public static void main(String[] args) {
            ObserveSubmarine o1 = new ObserveSubmarine();
            System.out.println("侦察艇初始数据:    x:"+o1.x+", y:"+o1.y+", speed:"+o1.speed);
            o1.move();
            System.out.println("侦察艇移动后数据: x:"+o1.x+", y:"+o1.y+", speed:"+o1.speed);
    
            Mine o2 = new Mine(100,200);
            System.out.println("水雷初始数据:   x:"+o2.x+", y:"+o2.y+", speed:"+o2.speed);
            o2.move();
            System.out.println("水雷移动后数据: x:"+o2.x+", y:"+o2.y+", speed:"+o2.speed);
    
            SeaObject[] submarines = new SeaObject[5]; //潜艇数组
            submarines[0] = new ObserveSubmarine(); //向上造型
            submarines[1] = new ObserveSubmarine();
            submarines[2] = new TorpedoSubmarine();
            submarines[3] = new TorpedoSubmarine();
            submarines[4] = new MineSubmarine();
            for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
                SeaObject s = submarines[i]; //获取每个潜艇
                System.out.println(s.x+","+s.y+","+s.speed);
                s.move();
            }
    
            Mine[] ms = new Mine[2];
            ms[0] = new Mine(100,200);
            ms[1] = new Mine(125,345);
            for(int i=0;i< ms.length;i++){ //遍历所有水雷
                Mine m = ms[i]; //获取每个水雷
                System.out.println(m.x+","+m.y);
                m.move();
            }
    
            Bomb[] bs = new Bomb[2];
            bs[0] = new Bomb(200,300);
            bs[1] = new Bomb(100,200);
            for(int i=0;i<bs.length;i++){
                Bomb b = bs[i];
                System.out.println(b.x+","+b.y);
                b.move();
            }
    
        }
    }
    
  2. 在6个类中重写move()移动,并测试;(以战舰类为例)
    /** 战舰 */
    public class Battleship extends SeaObject {
        int life;   //命数
        /** 构造方法 */
        Battleship(){
            super(66,26,270,124,20);
            life = 5;
        }
    
        /** 重写move()移动 */
        void move(){
            //暂时搁置
        }
    }
  3. 在World类中画窗口:  
    import javax.swing.JFrame;
    import javax.swing.JPanel; //1.第一步
    /** 整个窗口世界 */
    public class World extends JPanel { //2.第二步
        public static void main(String[] args) {
            JFrame frame = new JFrame(); //3.第三步
            World world = new World();
            world.setFocusable(true);
            frame.add(world);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(641+16, 479+39);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    }
    

潜艇游戏第五天:

  1. 给类中成员添加访问控制修饰符;(以战舰类为例)访问控制修饰符可看:(13条消息) Java学习日记Day11(面向对象day05)_终为尘埃的博客-CSDN博客
    /** 战舰 */
    public class Battleship extends SeaObject {
        private int life;   //命数
        /** 构造方法 */
        public Battleship(){
            super(66,26,270,124,20);
            life = 5;
        }
    
        /** 重写move()移动 */
        public void move(){
            //暂时搁置
        }
    }
  2. 设计Images图片类;
    import javax.swing.ImageIcon;
    /*
    注意:点项目右键New一个Directory,起名img,将8张图片粘贴进来
     */
    /** 图片类 */
    public class Images {
        public static ImageIcon sea;         //海洋图片
        public static ImageIcon gameover;    //游戏结束图片
        public static ImageIcon battleship;  //战舰图片
        public static ImageIcon obsersubm;   //侦察潜艇图片
        public static ImageIcon torpesubm;   //鱼雷潜艇图片
        public static ImageIcon minesubm;    //水雷潜艇图片
        public static ImageIcon mine;        //水雷图片
        public static ImageIcon bomb;        //炸弹图片
    
        static{ //初始化静态图片
            //将img中的sea.png读取到静态变量sea中
            sea = new ImageIcon("img/sea.png");
            gameover = new ImageIcon("img/gameover.png");
            battleship = new ImageIcon("img/battleship.png");
            obsersubm = new ImageIcon("img/obsersubm.png");
            torpesubm = new ImageIcon("img/torpesubm.png");
            minesubm = new ImageIcon("img/minesubm.png");
            mine = new ImageIcon("img/mine.png");
            bomb = new ImageIcon("img/bomb.png");
        }
    
        //测试图片是否读取成功
        public static void main(String[] args) {
            //返回8表示图片读取成功,返回其余数字表示图片读取失败
            System.out.println(sea.getImageLoadStatus()); //8
            System.out.println(gameover.getImageLoadStatus());
            System.out.println(battleship.getImageLoadStatus());
            System.out.println(obsersubm.getImageLoadStatus());
            System.out.println(torpesubm.getImageLoadStatus());
            System.out.println(minesubm.getImageLoadStatus());
            System.out.println(mine.getImageLoadStatus());
            System.out.println(bomb.getImageLoadStatus());
        }
    
    }
    

潜艇游戏第六天:

  1. 在World类中设计窗口的宽和高为常量,适当地方做修改,重写getImage()方法(以战舰类为例);

    import javax.swing.ImageIcon;
    /** 战舰 */
    public class Battleship extends SeaObject {
        private int life;   //命数
        /** 构造方法 */
        public Battleship(){
            super(66,26,270,124,20);
            life = 5;
        }
    
        /** 重写move()移动 */
        public void move(){
            //暂时搁置
        }
    
        /** 重写getImage()获取图片 */
        public ImageIcon getImage(){
            return Images.battleship; //返回战舰图片
        }
    }
    
  2. 画对象:

    1)想画对象需要获取对象的图片,每个对象都得获取图片,
     意味着获取图片行为为共有行为,所以设计在SeaObject超类中,
     每个对象获取图片的代码都是不一样的,所以设计为抽象方法
     ----在SeaObject中设计为抽象方法getImage()获取对象的图片
    2)在派生类中重写getImage()获取对象图片
     ----在6个类中重写getImage()返回不同的图片
    3)因为只有活着的对象才需要画到窗口中,所以需要设计对象的状态(活着还是死了),
     每个对象都有状态,意味着状态为共有属性,所以设计在SeaObject超类中,
     状态一般都设计为常量,同时再设计state变量表示当前状态
     ----在SeaObject中设计LIVE、DEAD常量,state变量表示当前状态
     在后期的业务中经常需要判断对象的状态,每个对象都得判断,
     意味着判断状态的行为为共有行为,所以设计在SeaObject超类中,
     每个对象判断状态的代码都是一样的,所以设计为普通方法
     ----在SeaObject中设计isLive()、isDead()判断对象的状态
    4)数据(状态、图片、x坐标、y坐标)都有了就可以开画了,每个对象都得画,
     意味着画对象行为为共有行为,所以设计在SeaObject超类中,
     每个对象画的代码都是一样的,所以设计为普通方法
     ----在SeaObject中设计paintImage()画对象
    5)画对象的行为做好了,在窗口World类中调用即可
     5.1)准备对象
     5.2)重写paint()方法-----在paint()中调用paintImage()画对象即可
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.*;
import java.util.Arrays;

/** 整个窗口世界 */
public class World extends JPanel {
    public static final int WIDTH = 641;  //窗口的宽
    public static final int HEIGHT = 479; //窗口的高

    //如下这一堆对象就是窗口中你所看到的对象了
    private Battleship ship = new Battleship(); //战舰对象
    private SeaObject[] submarines = {
            new ObserveSubmarine(),
            new TorpedoSubmarine(),
            new MineSubmarine()
    }; //潜艇数组
    private Mine[] mines = {
            new Mine(280,300)
    }; //水雷数组
    private Bomb[] bombs = {
            new Bomb(200,250)
    }; //炸弹数组

    /** 重写paint()画  g:系统自带的画笔 */
    public void paint(Graphics g){
        Images.sea.paintIcon(null,g,0,0); //画海洋图
        ship.paintImage(g); //画战舰
        for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
            submarines[1].paintImage(g); //画潜艇
        }
        for(int i=0;i<mines.length;i++){ //遍历所有水雷
            mines[i].paintImage(g); //画水雷
        }
        for(int i=0;i<bombs.length;i++){ //遍历所有炸弹
            bombs[i].paintImage(g); //画炸弹
        }
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame(); 
        World world = new World(); //会创建窗口中的那一堆对象
        world.setFocusable(true);
        frame.add(world);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(WIDTH+16, HEIGHT+39);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true); //系统自动调用paint()方法
    }
}

潜艇游戏第七天:

  1. 潜艇入场:

    • 潜艇是由窗口产生的,所以在窗口World类中设计nextSubmarine()生成潜艇对象;

      /** 生成潜艇(侦察潜艇、鱼雷潜艇、水雷潜艇)对象 */
      private SeaObject nextSubmarine(){
          Random rand = new Random(); //随机数对象
          int type = rand.nextInt(20); //0到19之间的随机数
          if(type<10){ //0到9时,返回侦察潜艇对象
              return new ObserveSubmarine();
          }else if(type<16){ //10到15时,返回鱼雷潜艇对象
              return new TorpedoSubmarine();
          }else{ //16到19时,返回水雷潜艇对象
              return new MineSubmarine();
          }
      }
    • 潜艇入场为定时发生的,所以在run()中调用submarineEnterAction()实现潜艇入场

      在submarineEnterAction()中:

      ​ 每400毫秒,获取潜艇对象obj,submarines扩容,将obj添加到最后一个元素上 ;

      private int subEnterIndex = 0; //潜艇入场计数
      /** 潜艇(侦察潜艇、鱼雷潜艇、水雷入场)入场 */
      private void submarineEnterAction(){ //每10毫秒走一次
          subEnterIndex++; //每10毫秒增1
          if(subEnterIndex%40==0){ //每400(40*10)毫秒走一次
              SeaObject obj = nextSubmarine(); //获取潜艇对象
              submarines = Arrays.copyOf(submarines,submarines.length+1); //扩容
              submarines[submarines.length-1] = obj; //将obj添加到submarines的最后一个元素上
          }
      }
      /** 启动程序的执行 */
      private void action(){
          Timer timer = new Timer(); //定时器对象
          int interval = 10; //定时间隔(以毫秒为单位)
          timer.schedule(new TimerTask() {
              public void run() { //定时干的事---每10毫秒自动调用
                  submarineEnterAction(); //潜艇(侦察潜艇、鱼雷潜艇、水雷入场)入场
                  repaint(); //重画---系统自动调用paint()方法
              }
          }, interval, interval); //定时日程表
      }

      注意:在run()中调用submarineEnterAction()之后,一定要调用repaint()来重画

  2. 水雷入场:

    • 水雷是由水雷潜艇发射出来的,所以在MineSubmarine中设计shootMine()生成水雷对象

    • 水雷入场为定时发生的,所以在run()中调用mineEnterAction()实现水雷入场

      在mineEnterAction()中:

      ​ 每1000毫秒,

      private int mineEnterIndex = 0; //水雷入场计数
      /** 水雷入场 */
      private void mineEnterAction(){ //每10毫秒走一次
          mineEnterIndex++; //每10毫秒增1
          if(mineEnterIndex%100==0) { //每1000毫秒走一次
              //暂时搁置
          }
      }
  3. 海洋对象移动:

    • 海洋对象移动为共有行为,所以在SeaObject中设计抽象方法move()实现移动,派生类中重写

    • 海洋对象移动为定时发生的,所以在run()中调用moveAction()实现海洋对象移动

      在moveAction()中:

      ​ 遍历所有潜艇--潜艇动,遍历所有水雷--水雷动,遍历所有炸弹--炸弹动 

      /** 海洋对象移动 */
      private void moveAction(){ //每10毫秒走一次
          for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
              submarines[i].move(); //潜艇移动
          }
          for(int i=0;i<mines.length;i++){ //遍历所有水雷
              mines[i].move(); //水雷移动
          }
          for(int i=0;i<bombs.length;i++){ //遍历所有炸弹
              bombs[i].move(); //炸弹移动
          }
      }

潜艇游戏第八天:

  1. 炸弹入场:

    • 炸弹是由战舰发射出来的,所以在Battleship类中设计shootBomb()生成炸弹对象;

      /** 发射炸弹---生成炸弹对象 */
      public Bomb shootBomb(){
          return new Bomb(this.x,this.y); //炸弹的初始坐标就是战舰的坐标
      }
    • 炸弹入场为按空格键事件触发的,所以在侦听器中重写keyReleased()按键抬起事件,在抬起事件中:

      • 判断若抬起的是空格键,则:

        ​ 获取炸弹对象obj,bombs扩容,将obj添加到bombs的最后一个元素上

  2. 战舰移动:

    • 战舰移动为战舰的行为,所以在Battleship中设计moveLeft()左移、moveRight()右移
    • 战舰移动为事件触发的,所以在侦听器的重写keyReleased()按键抬起事件中:
      • 判断若抬起的是左箭头,则战舰左移
      • 判断若抬起的是右箭头,则战舰右移 
        //键盘侦听器
        KeyAdapter k = new KeyAdapter() {
            /** 重写keyReleased按键抬起事件 keyPressed()键盘按下事件 */
            public void keyReleased(KeyEvent e) { //当按键抬起时会自动触发
                if(e.getKeyCode()==KeyEvent.VK_SPACE){ //若抬起的是空格键
                    Bomb obj = ship.shootBomb(); //获取炸弹对象
                    bombs = Arrays.copyOf(bombs,bombs.length+1); //扩容
                    bombs[bombs.length-1] = obj; //将obj添加到最后一个元素上
                }
                if(e.getKeyCode()==KeyEvent.VK_LEFT){ //若抬起的是左箭头
                    ship.moveLeft(); //战舰左移
                }
                if(e.getKeyCode()==KeyEvent.VK_RIGHT) { //若抬起的是右箭头
                    ship.moveRight(); //战舰右移
                }
            }
        };
        this.addKeyListener(k); //添加侦听
  3. 删除越界的海洋对象:

    • 在SeaObject中设计isOutOfBounds()检测潜艇是否越界,在Bomb和Mine中重写isOutOfBounds()检测炸弹和水雷是否越界;

    • 删除越界海洋对象为定时发生的,所以在run()中调用outOfBoundsAction()删除越界海洋对象

      在outOfBoundsAction()中:

      ​ 遍历所有潜艇/水雷/炸弹,判断若越界了:

      ​ 将越界元素替换为数组的最后一个元素,缩容;

      /** 删除越界的海洋对象 */
      private void outOfBoundsAction(){ //每10毫秒走一次
          for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
              if(submarines[i].isOutOfBounds()){ //若出界了
                  submarines[i] = submarines[submarines.length-1]; //将越界元素替换为最后一个元素
                  submarines = Arrays.copyOf(submarines,submarines.length-1); //缩容
              }
          }
      
          for(int i=0;i<mines.length;i++){ //遍历所有水雷
              if(mines[i].isOutOfBounds()){ //若出界了
                  mines[i] = mines[mines.length-1]; //将越界元素替换为最后一个元素
                  mines = Arrays.copyOf(mines,mines.length-1); //缩容
              }
          }
      
          for(int i=0;i<bombs.length;i++){ //遍历所有炸弹
              if(bombs[i].isOutOfBounds()){ //若出界了
                  bombs[i] = bombs[bombs.length-1]; //将越界元素替换为最后一个元素
                  bombs = Arrays.copyOf(bombs,bombs.length-1); //缩容
              }
          }
      }
      
  4. 设计EnemyScore得分接口,ObserveSubmarine和TorpedoSubmarine实现得分接口;

    /** 得分接口 */
    public interface EnemyScore {
        /** 得分 */
        public int getScore();
    }

    设计EnemyLife得命接口,MineSubmarine实现得命接口;

    /** 得命接口 */
    public interface EnemyLife {
        /** 得命 */
        public int getLife();
    }

潜艇游戏第九天:

  1. 水雷入场:--------------后半段

    • 水雷是由水雷潜艇发射出来的,所以在MineSubmarine中设计shootMine()生成水雷对象;

      /** 发射水雷---生成水雷对象 */
      public Mine shootMine(){
          //水雷的x:水雷潜艇的x+水雷潜艇的width
          //水雷的y:水雷潜艇的y-水雷的高(11)
          return new Mine(this.x+this.width,this.y-11); //this指水雷潜艇对象
      }
    • 水雷入场为定时发生的,所以在run()中调用mineEnterAction()实现水雷入场

      在mineEnterAction()中:

      ​ 每1000毫秒,遍历所有潜艇,判断若为水雷潜艇,则强转为水雷潜艇类型,

      ​ 获取水雷对象obj,mines扩容,将obj装到最后一个元素上;

      private int mineEnterIndex = 0; //水雷入场计数
      /** 水雷入场 */
      private void mineEnterAction(){ //每10毫秒走一次
          mineEnterIndex++; //每10毫秒增1
          if(mineEnterIndex%100==0) { //每1000毫秒走一次
              for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
                  if(submarines[i] instanceof MineSubmarine){ //若潜艇为水雷潜艇
                      MineSubmarine ms = (MineSubmarine)submarines[i]; //将潜艇转换为水雷潜艇类型
                      Mine obj = ms.shootMine(); //获取水雷对象
                      mines = Arrays.copyOf(mines,mines.length+1); //扩容
                      mines[mines.length-1] = obj; //将obj添加到mines最后一个元素上
                  }
              }
          }
      }
  2. 炸弹与潜艇的碰撞:

    • 在SeaObject中设计isHit()检测碰撞、goDead()去死; 

      /** 检测碰撞 this:一个对象 other:另一个对象 */
      public boolean isHit(SeaObject other){
          //假设:this表示潜艇 other表示炸弹
          int x1 = this.x-other.width;  //x1:潜艇的x-炸弹的宽
          int x2 = this.x+this.width;   //x2:潜艇的x+潜艇的宽
          int y1 = this.y-other.height; //y1:潜艇的y-炸弹的高
          int y2 = this.y+this.height;  //y2:潜艇的y+潜艇的高
          int x = other.x; //x:炸弹的x
          int y = other.y; //y:炸弹的y
          return x>=x1 && x<=x2 && y>=y1 && y<=y2; //x在x1与x2之间,并且,y在y1与y2之间,即为撞上了
      }
      
      /** 海洋对象去死 */
      public void goDead(){
          state = DEAD; //将当前状态修改为DEAD死了的
      }
    • 在Battleship中设计addLife()增命;

      /** 战舰增命 */
      public void addLife(int num){
          life += num; //命数增num
      }
    • 炸弹与潜艇的碰撞为定时发生的,所以在run()中设计bombBangAction()实现炸弹与潜艇碰撞

      在bombBangAction()中:

      ​ 遍历所有炸弹得炸弹,遍历所有潜艇得潜艇,判断若都活着并且还撞上了:

      ​ 炸弹去死、潜艇去死;

      ​ 判断若是分,则强转为得分接口,玩家得分;

      ​ 判断若是命,则强转为得命接口,获取命数,战舰得命;

      private int score = 0 ; //玩家得分
      /** 炸弹与潜艇的碰撞 */
      private void bombBangAction(){ //每10毫秒走一次
          for(int i=0;i<bombs.length;i++){ //遍历所有炸弹
              Bomb b = bombs[i]; //获取每一个炸弹
              for(int j=0;j<submarines.length;j++){ //遍历所有潜艇
                  SeaObject s = submarines[j]; //获取每一个潜艇
                  if(b.isLive() && s.isLive() && s.isHit(b)){ //若都活着并且还撞上了
                      s.goDead(); //潜艇去死
                      b.goDead(); //炸弹去死
                      if(s instanceof EnemyScore){ //若被撞潜艇为分
                          EnemyScore es = (EnemyScore)s; //将被撞潜艇强转为得分接口
                          score += es.getScore(); //玩家得分
                      }
                      if(s instanceof EnemyLife){ //若被撞潜艇为命
                          EnemyLife el = (EnemyLife)s; //将被撞潜艇强转为得命接口
                          int num = el.getLife(); //获取命数
                          ship.addLife(num); //战舰增命
                      }
                  }
              }
          }
      }
  3. 画分和画命:

    • 在Battleship中设计getLife()获取命数;                                                                                  
      /** 获取命数 */
      public int getLife(){
          return life; //返回命数
      }
    • 在World的paint()中:画分和画命;                                                                                     
      /** 重写paint()画  g:系统自带的画笔 */
      public void paint(Graphics g){ //每10毫秒走一次
          Images.sea.paintIcon(null,g,0,0); //画海洋图
          ship.paintImage(g); //画战舰
          for(int i=0;i<submarines.length;i++){ //遍历所有潜艇
              submarines[i].paintImage(g); //画潜艇
          }
          for(int i=0;i<mines.length;i++){ //遍历所有水雷
              mines[i].paintImage(g); //画水雷
          }
          for(int i=0;i<bombs.length;i++){ //遍历所有炸弹
              bombs[i].paintImage(g); //画炸弹
          }
          g.drawString("SCORE: "+score,200,50); //画分
          g.drawString("LIFE: "+ship.getLife(),400,50); //画命
      }

潜艇游戏第十天:

  1. 水雷与战舰的碰撞:

    • 在Battleship中设计subtractLife()减命;

      /** 战舰减命 */
      public void subtractLife(){
          life--; //命数减1
      }
    • 水雷与战舰碰撞为定时发生的,所以在run()中调用mineBangAction()实现水雷与战舰的碰撞;

      在mineBangAction()中:

      ​ 遍历所有水雷,得水雷,判断若都活着并且还撞上了:

      ​ 水雷去死、战舰减命; 

      /** 水雷与战舰的碰撞 */
      private void mineBangAction(){ //每10毫秒走一次
          for(int i=0;i<mines.length;i++){ //遍历所有水雷
              Mine m = mines[i]; //获取每一个水雷
              if(m.isLive() && ship.isLive() && m.isHit(ship)){ //若都活着,并且还撞上了
                  m.goDead(); //水雷去死
                  ship.subtractLife(); //战舰减命
              }
          }
      }
  2. 检测游戏结束:

    • 借用Battleship的getLife()获取命数;

    • 检测游戏结束为定时发生的,所以在run()中调checkGameOverAction()检测游戏结束

      在checkGameOverAction()中:

      ​ 判断若战舰的命数<=0,表示游戏结束了;

      /** 检测游戏结束 */
      private void checkGameOverAction(){ //每10毫秒走一次
          if(ship.getLife()<=0){ //若战舰的命数<=0,表示游戏结束了
              state = GAME_OVER; //则将当前状态修改为GAME_OVER游戏结束状态
          }
      }
  3. 画状态:

    • 在World类中设计RUNNING、PAUSE、GAME_OVER状态常量,state变量表示当前状态;

    • 在checkGameOverAction()中,若游戏结束, 则将当前状态修改为GAME_OVER游戏结束状态;

    • 在paint()中设计:若为游戏结束状态则画游戏结束图;

    • 设计run()中那一堆代码,为仅在运行状态下执行;

    • 设计键盘抬起时,按下空格键、左移键、右移键,也为仅在运行状态下执行;

    • 在键盘抬起时,设计若按的是P键,则运行状态变暂停状态,暂停状态变运行状态。       

      另外还实现一个飞机小游戏,过程相似。结果如图:

      如有需要,可评论区留下邮箱,后会发送。 

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
潜艇游戏是一款基于VC编程语言开发的游戏游戏的主要目标是控制潜艇进行海底探险,并通过躲避障碍物,收集宝藏等方式获得分数。 首先,我们需要创建一个窗口以及各种游戏所需的元素,如潜艇、障碍物和宝藏。可以使用VC的图形库来实现窗口的创建,以及对各元素进行绘制。 接下来,我们需要对潜艇的控制进行编码。可以根据用户的输入来控制潜艇的运动,如绘制键盘事件的处理函数,使得当用户按下上、下、左、右键时,潜艇可以分别向上、下、左、右移动。我们还可以添加一些限制条件,如潜艇不能超过窗口的边界等。 然后,我们需要生成障碍物和宝藏,并设置它们的初始位置。可以使用随机函数来生成随机位置,并利用时间函数来生成不同的障碍物和宝藏。 接着,我们需要编写碰撞检测的代码。当潜艇与障碍物相撞时,游戏会结束,可以显示游戏结束的界面,并计算并显示玩家的得分。而当潜艇与宝藏相撞时,玩家会获得一定分数,可以通过计分板实时显示玩家的得分。 最后,我们需要让游戏循环进行。可以使用循环结构来不断检测用户的输入、元素的移动和碰撞的发生,以保证游戏的正常运行。 总体而言,潜艇游戏的编程代码是通过VC编程语言来实现游戏窗口的创建、元素的绘制、用户输入的处理、碰撞检测以及游戏循环的控制。通过编写这些代码,可以让玩家体验到潜艇探险的乐趣,并且不断挑战自己的得分记录。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

专注摸鱼的汪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值