文章目录

  • 潜艇游戏需求:
  • 一、day01
  • 二、day02
  • 三、day03
  • 四、day04
  • 五、day05
  • 六、day06
  • 七、day07
  • 八、day08
  • 九、day09

潜艇游戏需求:

  1. 所参与的角色:

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

一、day01

  • 创建6个类,创建World类并测试

二、day02

  • 给6个类设计构造方法,并测试

三、day03

  • 设计侦察潜艇数组、鱼雷潜艇数组、水雷潜艇数组、水雷数组、炸弹数组,并测试
  • 设计SeaObject超类,设计6个类继承SeaObject
  • 给SeaObject设计两个构造方法,6个类中分别调用
  • 将侦察潜艇数组、鱼雷潜艇数组、水雷潜艇数组统一组合为SeaObject数组,并测试

四、day04

  • 给6个类重写 move() 使其坐标点移动,并测试

    • 侦察潜艇,鱼雷潜艇,水雷潜艇

      • 由于潜艇是从左往右移动,速度为speed,y 坐标不改变,改变的为 x 坐标
      • 方法实现为 x+=speed
    • 水雷
      • 由于水雷是从下往上移动,速度为speed,x 坐标不改变,改变的为 y 坐标
      • 方法实现为 y-=speed
    • 炸弹
      • 由于炸弹是从上往下移动,速度为speed,x 坐标不改变,改变的为 y 坐标
      • 方法实现为 y+=speed
    • 战舰
      • 由于它的移动方式和其他的不一致,方法只需要重写,具体实现先搁置不写
    • 测试
      • World

        • main方法

          • 分别创建 5 个对象

          • 分别输出每个对象的 x,y,speed 数值

          • 分别调用每个对象的 move() 方法

          • 在动用每个对象的 move() 方法后,再次对对象的 x,y,speed 值进行输出

          • 测试可参考以下示例:

             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);在这里插入代码片
            
  • 给类中成员添加访问控制修饰符

    • 访问控制修饰符是为了控制访问权限的,适当的减小访问权限可以使得代码更加安全
    • 通常我们会将属性(成员变量)私有化private,行为(方法)公开化public
    • 但是由于私有的属性不能被继承,这里我们还需要将 SeaObject 中的属性更改为 protected
  • 将图片拷贝到项目中

    • 在项目下创建 img 文件夹/目录
    • 将8张图片拷贝到 img 文件夹中
    • 最好将图片拷贝之后,进行一个 Build -> Rebuild Project 操作
  • 设计Images图片类

    • 在项目的包下创建类 Images
    • 目的:
      • 这个类是为了封装我们的 图片对象而设计的
      • 思路:
        • 由于我们为了减少内存消耗,想让图片只有一份,这里使用 static 关键字对图片对象进行修饰
        • 由于我们想项目一起动就对图片进行加载,使用 static 关键字修饰静态代码块,为图片对象进行赋值
      • 创建8个图片对象,
        • public static ImageIcon xxx;
      • 静态代码块对图片对象进行赋值操作
        • static{xxx = new ImageIcon("img/xxx.png");}
    • 测试
      • Images 类中创建main方法

        • 在main方法中分别调用 System.out.println(xxx.getImageLoadStatus()); 进行测试
        • 测试结果为 8 ,表示正确

五、day05

今日目标

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

    • World 类中设计宽WIDTH = 641,高HEIGHT = 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()方法}
      
  • 画海洋图、至少准备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); //----不要求掌握}
          }
          
    • 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); //画炸弹}}
        
  • 测试

    • 修改 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);
        
  • 战舰移动:

    • 业务:

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

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

          if(e.getKeyCode()==KeyEvent.VK_LEFT){ //不要求掌握--若抬起的是左箭头// 战舰左移
          }
          if(e.getKeyCode()==KeyEvent.VK_RIGHT){ //不要求掌握--若抬起的是右箭头//战舰右移
          }
          
      • 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
      • 我们需要先遍历潜艇数组中所有的潜艇对象,再判断这些潜艇对象是否是水雷潜艇(instanceof),如果是水雷潜艇(MineSubmarine),调用创建水雷对象方法(shootMine),并且对水雷数组(mines)进行扩容,之后将水雷对象(Mine)添加到水雷数组中
  • 炸弹与潜艇的碰撞

    • 在 SeaObject 中设计 isHit() 检测碰撞方法

      • 由于碰撞的两者都是 SeaObject 类型,所以将方法写在 SeaObject 类中,
      • 由于碰撞是两个对象的事,所以我们在设计这个方法的时候,需要提供一个参数 (SeaObject other)
      • 由于这个方法是判断是否碰撞,所以返回值类型为 boolean 类型
      • 碰撞逻辑如下图所示:
    • 参考代码:

      /*** 检测碰撞* @param other 另一个对象  this表示一个对象* @return 若撞上了则返回true,否则返回false*/
      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:炸弹的xint y = other.y; //y:炸弹的y     //练习-----------2:34继续return x>=x1 && x<=x2&&y>=y1 && y<=y2; //x在x1与x2之间,并且,y在y1与y2之间,即为撞上了
      }
      
    • 在 SeaObject 中设计 goDead() 去死方法 - 变更状态

      • 业务:

        • 变更状态,将海洋对象的状态 state 从 LIVE 变为 DEAD
      • 方法名: goDead
      • 返回值: void
    • 在 Battleship 中设计 addLife() 增命方法

      • 业务:设计增命方法
      • 思路:给 Battleship 的 life 属性累加
      • 方法名:addLife
      • 参数:int num
    • 在 World 中设计 bombBangAction() 炸弹与潜艇的碰撞方法

      • 业务:

        • 判断炸弹与潜艇是否碰撞,如果碰撞,让炸弹和潜艇一起去死
        • 如果摧毁的是水雷潜艇得命
        • 如果摧毁的是侦察潜艇得10分
        • 如果摧毁的是鱼雷潜艇得40分
      • 思路:
        • 判断所有炸弹与潜艇是否碰撞

          • 首先需要嵌套循环两个数组(bombs 炸弹,submarines 潜艇)
          • 判断炸弹是否活着(isLive())
          • 判断潜艇是否活着(isLive())
          • 判断炸弹与潜艇是否碰撞(isHit())
        • 如果都满足则代表碰撞上了
          • 让炸弹去死(goDead),让潜艇去死(goDead)
          • 判断摧毁的是得分的潜艇(侦察/鱼雷)
            • 向下转型(引用类型强转)
            • 判断这个对象是否实现了得分接口 (instanceof)
            • 调用 getScore 方法
          • 判断摧毁的是得命的潜艇
            • 向下转型(引用类型强转)
            • 判断这个对象是否实现了得命接口 (instanceof)
            • 调用 getLife 获取命数的方法 和 addLife 增加命数的方法
        • 在定时器中调用 bombBangAction() 方法
  • 海洋对象死亡删除

    • 在 outOfBoundsAction 删除越界的海洋对象的方法中添加是否死了的判断
    • 将方法改为 越界和死亡 都删除删除对象
    • 参考代码:
  • 画分和画命:

    • 在 Battleship 中设计 getLife() 获取命数

      • 方法名:getLife
      • 返回值类型:int - 获取 Battleship 中的 life 属性
    • 在World类的 paint() 中:画分和画命------------不要求掌握
      g.drawString("SCORE: "+score,200,50);         //画分----不要求掌握
      g.drawString("LIFE: "+ship.getLife(),400,50); //画命----不要求掌握
      

九、day09

Java新手小白入门篇 项目 - 深海杀手相关推荐

  1. Java新手小白入门篇 Java基础(一)

    Java新手小白入门篇 Java基础 Java新手小白入门篇 Java基础(知识点体系汇总) Java新手小白入门篇 Java基础(一) Java新手小白入门篇 Java基础(二) Java新手小白入 ...

  2. Java新手小白入门篇 Java项目的构建

    前言 之前我们已经讲解了 JDK的下载安装及配置操作 和 IDEA的下载和安装 ,学习Java的准备工作我们已经做好了,下面我们需要做的就是创建项目,并且写我们的 Java 程序了 一.如何使用IDE ...

  3. Java新手小白入门篇 JDK安装及环境变量配置(超详细)

    前言 学习Java,必备的就是JDK,所以我们必须得下载安装JDK,才能学习Java,下面我们会介绍 JDK是什么,如何安装并配置. 一.JDK简介 1.名词解释 JVM (Java Virtual ...

  4. 3DMax”——新手小白入门篇

    3Dmax 是一个数字化三维制作软件,常简称为3Ds Max或MAX,是Discreet公司开发的(后被Autodesk公司合并)基于PC系统的三维动画渲染和制作软件.其前身是基于DOS操作系统的3D ...

  5. 从新手小白入门MFC框架-黄强-专题视频课程

    从新手小白入门MFC框架-806人已学习 课程介绍         微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是微软公司提供的一个类库(class li ...

  6. IP编址(小白入门篇)

    IP编址(小白入门篇) 网络层位于数据链路层与传输层之间.网络层中包含了许多协议,其中最为重要的协议就是IP协议.网络层提供了IP路由功能.理解IP路由除了要熟悉IP协议的工作机制之外,还必须理解IP ...

  7. Java基础小白入门教程-----百知教育java基础学习1---胡鑫喆

    Java基础小白入门教程(胡大大出品,彩蛋请自寻) 胡鑫喆 https://www.bilibili.com/video/BV1wE411V7Zo?from=search&seid=38511 ...

  8. 数据结构——小白入门篇

    数据结构--小白入门篇 浅谈学习心得 我为什么想要学数据结构? 在计算机界有这样一个万能公式:数据结构 + 算法 = 程序. 在如今这计算机引领风骚的时代,不学数据结构,你凭什么想要做时代的弄潮儿:所 ...

  9. 适合新手小白入门的前端书籍

    总所周知,学习前端肯定离不开书籍的辅导,很多新手小白不知道该怎么选择,以及是否选对了书籍,本文就以过来人身份,给大家推荐一下新手小白学习过程中需要或可以用到的书籍. 一,html+css阶段: 1.& ...

最新文章

  1. 在winform嵌入外部应用程序
  2. 洛谷P1311 选择客栈
  3. 2017-2018-1 20155229 《信息安全系统设计基础》第十三周学习总结
  4. Android实现支持缩放平移图片
  5. 第三章:选择结构(一)
  6. CloudCC:2017年下半年企业移动CRM市场风向窥测
  7. C++ 常见错误(00) —— C#调用c++做的dll是报错
  8. PowerDesigner生成PowerBuilder扩展属性~
  9. 通过微信查找SAP TCODE代码
  10. mvn命令传递参数和pom文件配置的关系
  11. c语言计算机病毒程序代码,bat电脑病毒代码
  12. XAMPP最详细的安装及使用教程
  13. 视觉素材-10 个值得珍藏的高清桌面壁纸网站
  14. 计算机系统维护技术txt,计算机系统维护技术作业装系统.docx
  15. @Deprecated 的功能
  16. php 数独计算器,数独
  17. 实体门店营销,抽奖系统为何独占鳌头
  18. 基于C语言的简单小游戏-(扫雷)
  19. 【刷题笔记】--lintcode木头加工(java)
  20. 网站关键词优化技术:如何对关键词分类细分处理

热门文章

  1. 运动检测ViBe算法python实现
  2. 【魏先生搞定Python系列】一文搞定Cufflinks画图
  3. js 判断是域名还是ip并获取当前url中指定部分
  4. Linux通过stty命令操作串口设备(linux串口操作命令)
  5. Vue的安装及使用教程【超详细图文教程】
  6. MFC编程实例二:进度条的使用
  7. Ubuntu安装python3.7.5(附加更新python默认指向为python3.7)
  8. 宁波诺丁汉计算机博士学费,宁诺1600万元博士奖学金开放申请 PhD scholarships open for application...
  9. c语言pm2.5检测系统,基于Arduino的PM2.5实时检测系统
  10. 使用ESP8266数据上onenet云平台