• Java新手小白入门篇 项目 - 深海杀手



    潜艇游戏需求:

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

    一、day01

    二、day02

    三、day03

    四、day04

    五、day05

    今日目标
    在这里插入图片描述

    • 设计窗口的宽和高为常量,在适当的地方做修改

      • World 类中设计宽WIDTH = 641,高WEIGHT = 479
      • main方法里内容删除
    • 画窗口

      • World类 继承 JPanel
      • main方法里内容复制
        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(WIDTH+16, HEIGHT+40);
                frame.setLocationRelativeTo(null);
                frame.setResizable(false);
                frame.setVisible(true); //自动调用paint()方法
            }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
    • 画海洋图、至少准备6个对象并画出来

      • SeaObject

        • 修改 SeaObject 为抽象类
        • 修改 move 为抽象方法
        • 创建 getImage 抽象方法
          • 返回值类型为 ImageIcon 类型
        • 定义两个状态常量(LIVE,DEAD)和一个变量 表示当前状态(state)
          • LIVE = 0 表示活着
          • DEAD = 1 表示死了
          • state = LIVE 表示默认为活着
        • 创建 isLive 方法
          • 返回值类型:boolean 类型
          • 业务:判断当前状态是否为活着
        • 创建 isDead 方法
          • 返回值类型:boolean 类型
          • 业务:判断当前状态是否为死了
        • 创建 paintImage 方法
          • 返回值类型 void

          • 参数 Graphics g

          • 业务:如果当前状态为活着,画图片

            /** 画对象 g:画笔 */
            public void paintImage(Graphics g){
                if(this.isLive()){ //若活着的
                    this.getImage().paintIcon(null,g,this.x,this.y); //----不要求掌握
                }
            }
            
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
      • Battleship

        • 重写 getImage 方法,返回对应的 ImageIcon 对象
      • ObserveSubmarine

        • 重写 getImage 方法,返回对应的 ImageIcon 对象
      • TorpedoSubmarine

        • 重写 getImage 方法,返回对应的 ImageIcon 对象
      • MineSubmarine

        • 重写 getImage 方法,返回对应的 ImageIcon 对象
      • Bomb

        • 重写 getImage 方法,返回对应的 ImageIcon 对象
      • Mine

        • 重写 getImage 方法,返回对应的 ImageIcon 对象
      • World

        • 创建战舰(Battleship对象,SeaObject数组对象,Mine数组对象,Bomb数组对象),并赋值

        • 重画

          /** 重写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[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); //画炸弹
                  }
              }
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
          • 13
          • 14
          • 15
    • 测试

      • 修改 SeaObject 类,2个参数的构造方法,将负号去掉,为了能在屏幕上显示已经画好的对象
        在这里插入图片描述

      • 运行测试(海洋,战舰,潜艇[侦查潜艇,鱼雷潜艇,水雷潜艇],水雷,炸弹等对象是否显示在窗口里)

    六、day06

    今日目标:

    深海杀手_day06效果视频

    • 清空成员变量数组中的元素
      • 潜艇数组 submarines
      • 水雷数组 mines
      • 炸弹数组 bombs
    • 定时做某件事
      • 定义 action 方法,作为游戏的启动执行方法
        • 由于游戏是要求定时做某件事,所以创建定时器对象 Timer,util 包下的 Timer
        • 调用 Timer对象中 schedule 方法 - 3个参数的方法
        • 在方法中将定时器中调用需要定时执行的方法,定时间隔,每10毫秒走一次
          • 潜艇入场
          • 水雷入场
          • 海洋对象移动
          • 重画
      • 在 main 方法中调用 action 方法
    • 潜艇入场
      • 生成潜艇对象方法(侦察潜艇、鱼雷潜艇、水雷潜艇)
        • 方法名 nextSubmarine
        • 返回值类型 SeaObject
          • 要求随机返回某一潜艇对象,为了统一返回的类型,所以使用父类 SeaObject 作为返回值类型
        • 方法具体实现
          • 业务:按照一定比例随机生成潜艇对象
            • 侦查潜艇:50%
            • 鱼雷潜艇:30%
            • 水雷潜艇:20%
          • 思路
            • 通过随机数的形式,加上if…else,返回对应的潜艇对象
      • 潜艇入场方法
        • 方法名 submarineEnterAction
        • 返回值类型 void
        • 方法具体实现
          • 业务:每400毫秒调用nextSubmarine方法生成一个潜艇对象
            • 每10豪秒走一次方法submarineEnterAction,现在想每400毫秒走一次/调用一个 nextSubmarine 生成潜艇对象
            • 之前我们已经清空了潜艇数组(为的就是想让潜艇对象从无到有)
            • 将生成的潜艇对象添加到World类中,成员变量(submarines)的潜艇数组中
          • 思路:添加一个计数的变量subEnterIndex,通过整除的方式(计数变量自增,取余),if判断等方式达到目的
    • 水雷入场(上)
      • 水雷入场方法
        • 方法名:mineEnterAction
        • 返回值类型:void
        • 方法具体实现
          • 业务:
            • 每1000毫秒方法生成一个水雷对象
            • 每10豪秒走一次方法mineEnterAction,现在想每1000毫秒走一次/调用一个 xxx方法(当日未实现) 生成潜艇对象
          • 思路:添加一个计数的变量mineEnterIndex,通过整除的方式(计数变量自增,取余),if判断等方式达到目的
    • 海洋对象移动
      • 方法名:moveAction
      • 返回值类型:void
      • 方法具体实现:
        • 业务:
          • 每10豪秒走一次方法moveAction
          • 分别循环遍历海洋对象(潜艇对象,水雷对象,炸弹)
          • 循环中调用每个子类中的重写的move方法

    七、day07

    • 深水炸弹入场:

      • 业务:
        • 深水炸弹是由战舰发出的
        • 我们深水炸弹是通过键盘进行触发的
        • 将深水炸弹存放进炸弹数组
      • 思路:
        • 通过监听键盘,去调用创建深水炸弹的方法
        • 将深水炸弹存放进炸弹数组
        • 由于深水炸弹是由战舰发出的,坐标点为战舰的坐标点,所以这个生成深水炸弹对象的方法需要写在战舰类上(Battleship)
          // 可以参考,不需要必须会写
          KeyAdapter k = new KeyAdapter(){
              public void keyPressed(KeyEvent e) {
                  if(e.getKeyCode() == KeyEvent.VK_SPACE){
                  	// 深水炸弹入场
                  }
              }
          };
          this.addKeyListener(k);
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
    • 战舰移动:

      • 业务:
        • 通过键盘进行触发战舰的左右移动
      • 思路
        • 和上述空格键触发深水炸弹一样,写在键盘出发的方法里
        • 通过不同的按键触发,调用不同的方法
          • 通过按 ← 箭头,触发 Battleship 中的 moveLeft 战舰左移方法

          • 通过按 → 箭头,触发 Battleship 中的 moveRight 战舰右移方法

            if(e.getKeyCode()==KeyEvent.VK_LEFT){ //不要求掌握--若抬起的是左箭头
              // 战舰左移
            }
            if(e.getKeyCode()==KeyEvent.VK_RIGHT){ //不要求掌握--若抬起的是右箭头
              //战舰右移
            }
            
            • 1
            • 2
            • 3
            • 4
            • 5
            • 6
        • moveLeft 和 moveRight 实现,移动 Battleship 的 x 坐标
    • 删除越界的海洋对象:

      • 方法名:outOfBoundsAction
      • 返回值类型:void
      • 业务:
        • 由于超越边界的潜艇,深水炸弹,鱼雷就没有作用了,并且占用内存资源,所以我们需要删除它们
          • 潜艇是超出右边的边界删除
          • 深水炸弹是超出底下的边界删除
          • 鱼雷是超过海平面伤处
      • 思路
        • 分别循环所有的海洋对象,判断是否越界,如果越界,从数组中删除
          • 判断是否越界
            • SeaObject(潜艇越界)
              • 定义 isOutOfBounds 方法,返回值类型为boolean类型
                • 潜艇的x坐标 >= 世界的WIDTH
            • Bomb(深水炸弹越界)
              • 重写 isOutOfBounds 方法
              • 深水炸弹的y坐标 >= 世界的WEIGHT
            • Mine(鱼雷越界)
              • 重写 isOutOfBounds 方法
              • 鱼雷的y坐标 <= 150(海平面的y坐标)- 鱼雷的高height
          • 数组删除
            • 将数组的最后一个元素赋值给想要删除的元素
            • 数组缩容
    • 设计EnemyScore得分接口、EnemyLife得命接口,侦察潜艇与鱼雷潜艇实现EnemyScore接口,水雷潜艇实现EnemyLife接口

      • EnemyScore 得分接口
        • 声明得分的抽象方法
          • 方法名:getScore
          • 返回值类型:int
        • 侦察潜艇和鱼类潜艇实现得分接口,重写 getScore 方法
          • 侦察潜艇得10分
          • 鱼类潜艇得40分
      • EnemyLife 得命接口
        • 声明得名的抽象方法
          • 方法名:getLife
          • 返回值类型:int
        • 水雷潜艇实现得命接口,重写 getLife 方法
          • 水雷潜艇得1条命

    八、day08

    • 水雷入场(下)

      • 水雷入场之前我们已经将方法创建完成,mineEnterAction,但是具体的生成水雷对象及将水雷对象添加到水雷数组中未做,我们需要的就是根据之前的水雷入场继续做即可
      • 业务:
        • 生成水雷对象,并将水雷对象添加到水雷数组中
        • 由于是定时出现水雷,之后我们需要将 mineEnterAction 方法在定时器中调用
      • 思路:
        • 由于水雷对象是由水雷潜艇产生,水雷对象的初始坐标点与水雷潜艇的坐标点有关,所以我们应该在水雷潜艇类中创建生成水雷对象的方法 shootMine
        • 我们需要先遍历潜艇数组中所有的潜艇对象,再判断这些潜艇对象是否是水雷潜艇,如果是水雷潜艇(MineSubmarine),调用创建水雷对象方法(shootMine),并且对水雷数组(mines)进行扩容,之后将水雷对象(Mine)添加到水雷数组中
    • 炸弹与潜艇的碰撞

  • 相关阅读:
    链表面试题(图文详解)
    C语言字符函数和字符串函数详解
    基于github_monitor的源代码监控+自动化监控任务生成+webhook实现飞书机器人通知
    (七)C++中实现argmin与argmax
    Python安全渗透测试-SSH密码暴力破解渗透测试
    uniapp:动态修改页面标题
    【一起来学C++】————(6)C++中的继承
    《C++ Primer》练习9.52:使用栈实现四则运算
    长沙学院2022暑假训练赛(一)六级阅读
    图神经网络简介
  • 原文地址:https://blog.csdn.net/weixin_46030002/article/details/126377489