Java新手小白入门篇 项目 - 深海杀手
文章目录
- 潜艇游戏需求:
- 一、day01
- 二、day02
- 三、day03
- 四、day04
- 五、day05
- 六、day06
- 七、day07
- 八、day08
- 九、day09
潜艇游戏需求:
- 所参与的角色:
- 战舰、深水炸弹、侦察潜艇、鱼雷潜艇、水雷潜艇、水雷
- 角色间的关系:
- 战舰发射深水炸弹
- 深水炸弹可以打潜艇(侦察潜艇、鱼雷潜艇、水雷潜艇),若打中:
- 潜艇消失、深水炸弹消失
- 得东西:
- 打掉侦察潜艇,玩家得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);在这里插入代码片
- main方法
- World
- 侦察潜艇,鱼雷潜艇,水雷潜艇
给类中成员添加访问控制修饰符
- 访问控制修饰符是为了控制访问权限的,适当的减小访问权限可以使得代码更加安全
- 通常我们会将属性(成员变量)私有化
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 ,表示正确
- 在main方法中分别调用
- Images 类中创建main方法
- 在项目的包下创建类
五、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 方法
- 定义 action 方法,作为游戏的启动执行方法
- 潜艇入场:
- 生成潜艇对象方法(侦察潜艇、鱼雷潜艇、水雷潜艇)
- 方法名 nextSubmarine
- 返回值类型 SeaObject
- 要求随机返回某一潜艇对象,为了统一返回的类型,所以使用父类 SeaObject 作为返回值类型
- 方法具体实现
- 业务:按照一定比例随机生成潜艇对象
- 侦查潜艇:50%
- 鱼雷潜艇:30%
- 水雷潜艇:20%
- 思路:
- 通过随机数的形式,加上if…else,返回对应的潜艇对象
- 业务:按照一定比例随机生成潜艇对象
- 潜艇入场方法
- 方法名 submarineEnterAction
- 返回值类型 void
- 方法具体实现
- 业务:每400毫秒调用nextSubmarine方法生成一个潜艇对象
- 每10豪秒走一次方法submarineEnterAction,现在想每400毫秒走一次/调用一个 nextSubmarine 生成潜艇对象
- 之前我们已经清空了潜艇数组(为的就是想让潜艇对象从无到有)
- 将生成的潜艇对象添加到World类中,成员变量(submarines)的潜艇数组中
- 思路:添加一个计数的变量subEnterIndex,通过整除的方式(计数变量自增,取余),if判断等方式达到目的
- 业务:每400毫秒调用nextSubmarine方法生成一个潜艇对象
- 生成潜艇对象方法(侦察潜艇、鱼雷潜艇、水雷潜艇)
- 水雷入场(上):
- 水雷入场方法
- 方法名: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
- 定义 isOutOfBounds 方法,返回值类型为boolean类型
- Bomb(深水炸弹越界)
- 重写 isOutOfBounds 方法
- 深水炸弹的y坐标 >= 世界的WEIGHT
- Mine(鱼雷越界)
- 重写 isOutOfBounds 方法
- 鱼雷的y坐标 <= 150(海平面的y坐标)- 鱼雷的高height
- SeaObject(潜艇越界)
- 数组删除
- 将数组的最后一个元素赋值给想要删除的元素
- 数组缩容
- 判断是否越界
- 分别循环所有的海洋对象,判断是否越界,如果越界,从数组中删除
设计EnemyScore得分接口、EnemyLife得命接口,侦察潜艇与鱼雷潜艇实现EnemyScore接口,水雷潜艇实现EnemyLife接口
- EnemyScore 得分接口
- 声明得分的抽象方法
- 方法名:getScore
- 返回值类型:int
- 侦察潜艇和鱼类潜艇实现得分接口,重写 getScore 方法
- 侦察潜艇得10分
- 鱼类潜艇得40分
- 声明得分的抽象方法
- EnemyLife 得命接口
- 声明得名的抽象方法
- 方法名:getLife
- 返回值类型:int
- 水雷潜艇实现得命接口,重写 getLife 方法
- 水雷潜艇得1条命
- 声明得名的抽象方法
- EnemyScore 得分接口
八、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); //画命----不要求掌握
- 在 Battleship 中设计 getLife() 获取命数
九、day09
Java新手小白入门篇 项目 - 深海杀手相关推荐
- Java新手小白入门篇 Java基础(一)
Java新手小白入门篇 Java基础 Java新手小白入门篇 Java基础(知识点体系汇总) Java新手小白入门篇 Java基础(一) Java新手小白入门篇 Java基础(二) Java新手小白入 ...
- Java新手小白入门篇 Java项目的构建
前言 之前我们已经讲解了 JDK的下载安装及配置操作 和 IDEA的下载和安装 ,学习Java的准备工作我们已经做好了,下面我们需要做的就是创建项目,并且写我们的 Java 程序了 一.如何使用IDE ...
- Java新手小白入门篇 JDK安装及环境变量配置(超详细)
前言 学习Java,必备的就是JDK,所以我们必须得下载安装JDK,才能学习Java,下面我们会介绍 JDK是什么,如何安装并配置. 一.JDK简介 1.名词解释 JVM (Java Virtual ...
- 3DMax”——新手小白入门篇
3Dmax 是一个数字化三维制作软件,常简称为3Ds Max或MAX,是Discreet公司开发的(后被Autodesk公司合并)基于PC系统的三维动画渲染和制作软件.其前身是基于DOS操作系统的3D ...
- 从新手小白入门MFC框架-黄强-专题视频课程
从新手小白入门MFC框架-806人已学习 课程介绍 微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是微软公司提供的一个类库(class li ...
- IP编址(小白入门篇)
IP编址(小白入门篇) 网络层位于数据链路层与传输层之间.网络层中包含了许多协议,其中最为重要的协议就是IP协议.网络层提供了IP路由功能.理解IP路由除了要熟悉IP协议的工作机制之外,还必须理解IP ...
- Java基础小白入门教程-----百知教育java基础学习1---胡鑫喆
Java基础小白入门教程(胡大大出品,彩蛋请自寻) 胡鑫喆 https://www.bilibili.com/video/BV1wE411V7Zo?from=search&seid=38511 ...
- 数据结构——小白入门篇
数据结构--小白入门篇 浅谈学习心得 我为什么想要学数据结构? 在计算机界有这样一个万能公式:数据结构 + 算法 = 程序. 在如今这计算机引领风骚的时代,不学数据结构,你凭什么想要做时代的弄潮儿:所 ...
- 适合新手小白入门的前端书籍
总所周知,学习前端肯定离不开书籍的辅导,很多新手小白不知道该怎么选择,以及是否选对了书籍,本文就以过来人身份,给大家推荐一下新手小白学习过程中需要或可以用到的书籍. 一,html+css阶段: 1.& ...
最新文章
- 在winform嵌入外部应用程序
- 洛谷P1311 选择客栈
- 2017-2018-1 20155229 《信息安全系统设计基础》第十三周学习总结
- Android实现支持缩放平移图片
- 第三章:选择结构(一)
- CloudCC:2017年下半年企业移动CRM市场风向窥测
- C++ 常见错误(00) —— C#调用c++做的dll是报错
- PowerDesigner生成PowerBuilder扩展属性~
- 通过微信查找SAP TCODE代码
- mvn命令传递参数和pom文件配置的关系
- c语言计算机病毒程序代码,bat电脑病毒代码
- XAMPP最详细的安装及使用教程
- 视觉素材-10 个值得珍藏的高清桌面壁纸网站
- 计算机系统维护技术txt,计算机系统维护技术作业装系统.docx
- @Deprecated 的功能
- php 数独计算器,数独
- 实体门店营销,抽奖系统为何独占鳌头
- 基于C语言的简单小游戏-(扫雷)
- 【刷题笔记】--lintcode木头加工(java)
- 网站关键词优化技术:如何对关键词分类细分处理
热门文章
- 运动检测ViBe算法python实现
- 【魏先生搞定Python系列】一文搞定Cufflinks画图
- js 判断是域名还是ip并获取当前url中指定部分
- Linux通过stty命令操作串口设备(linux串口操作命令)
- Vue的安装及使用教程【超详细图文教程】
- MFC编程实例二:进度条的使用
- Ubuntu安装python3.7.5(附加更新python默认指向为python3.7)
- 宁波诺丁汉计算机博士学费,宁诺1600万元博士奖学金开放申请 PhD scholarships open for application...
- c语言pm2.5检测系统,基于Arduino的PM2.5实时检测系统
- 使用ESP8266数据上onenet云平台