Mokepon代码导读
随时查REF

72 个类百科

每个类一张卡片:干什么、谁创建、谁持有、老师的 UML 图

这一页有 72 张卡片,一个类一张。别的页面上的类名小标签(比如 CBattle),点一下就跳到这里它的卡片。想找某个类,用下面的筛选:输入框里打类名、方法名或中文词;“全部 / 类 / 抽象类 / 接口 / 枚举”按种类筛,“所有包 / mokepon / battle …”按包筛,可以一起用。

小标签左边的字母,和老师打印的 UML 图上类名旁边的圆圈一样(C / A / I / E):CCoffee 是 C,普通类(class);AItem 是 A,抽象类(abstract class);IEnemyStrategy 是 I,接口(interface);EStat 是 E,枚举(enum)。

抽象类:一次性道具,有类型名、显示名、图片键和 use()。AItemitem道具 Coffee:把玩家 Mokepon 的能量补满。CCoffeeitem枚举:六项属性(HP、Energy、Strength 等)和各自的合法范围。EStatmodelHP、ENERGY、STRENGTHACCURACY、DEFENCE、DODGE接口:决定敌人这一回合用哪个技能。IEnemyStrategybattleEnemyStrategy 的实现:从能量够用的技能里随机挑一个。CRandomEnemyStrategybattle一场战斗的规则:双方轮流出招、用道具、记日志、判输赢。CBattlebattleextends只有这 6 个值implements存着:字段enemyStrategy创建:第 26 行new
四种类型,各一个你代码里的例子。实线空心三角 = extends,虚线空心三角 = implements。最右边 Battle 的两条线,就是卡片上的“谁存着它”和“谁创建它”

每张卡片里有两行要特别看:

为什么重要:打印的 UML 图只画继承和实现的线,不画谁 new 谁、谁存着谁,可设计题常问的正是这两件事。答题时照卡片说清楚:哪个类、第几行、哪个字段。

CMain

Main

au.edu.unimelb.swen.oop.mokepon类

程序入口:读数据文件、解析成对象,然后打开游戏窗口。

在游戏里
看不见:只在启动时工作。它最后 new GameWindow 并调用 show(),你才看到选择界面;数据读不了就在控制台打印 “Error loading ...” 并退出。
它的职责
继承 JavaFX 的 Application;依次调用各个解析器,再把结果交给 GameWindow,是把整个程序组装起来的地方。
家族关系
继承 Application
谁创建它
JavaFX 启动时自动创建
谁存着它
没有别的类把它存成字段
方法 2 个
+ start(Stage stage): void · 第 22 行
+ main(String[] args): void · 第 42 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;06 窗口、界面切换和菜单;09 遇敌:地形、类型和挑敌人;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
Main.java(46 行)
看老师打印稿里的这个类(UMLDoclet)
Main 的 UML 类图
CBattle

Battle

au.edu.unimelb.swen.oop.mokepon.battle类

一场战斗的规则:双方轮流出招、用道具、记日志、判输赢。

在游戏里
战斗界面右下日志框里的每一行(如 “Player's Impike used Stun!”、“You win”)都是它 log 里的字符串;BattleScreen 只负责显示。
它的职责
纯规则(model),完全不碰界面;只依赖 EnemyStrategy 接口来选敌人技能,是 Strategy 模式的使用方(context)。
谁创建它
CEncounter(第 56 行 new Battle(…))
谁存着它
CBattleScreen 的字段 battle: Battle
字段 8 个
- final player: Fighter
- final enemy: Fighter
- final inventory: Inventory
- final enemyStrategy: EnemyStrategy
- final random: Random
- final log: List<String>
- finished: boolean
- playerWon: boolean
方法 12 个
+ Battle(Fighter player, Fighter enemy, Inventory inventory) · 第 25 行
+ Battle(Fighter player, Fighter enemy, Inventory inventory, EnemyStrategy enemyStrategy, Random random) · 第 30 行
+ getPlayer(): Fighter · 第 41 行
+ getEnemy(): Fighter · 第 45 行
+ getInventory(): Inventory · 第 49 行
+ isFinished(): boolean · 第 53 行
+ hasPlayerWon(): boolean · 第 57 行
+ getLog(): List<String> · 第 62 行
+ playTurn(Skill playerSkill): void · 第 69 行
+ useItem(Item item): void · 第 101 行
- endTurn(): void · 第 116 行
- finish(boolean playerWon): void · 第 134 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;06 窗口、界面切换和菜单;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;13 状态效果和道具;14 战斗界面是怎么画出来的;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
battle/Battle.java(148 行)
看老师打印稿里的这个类(UMLDoclet)
Battle 的 UML 类图
IEnemyStrategy

EnemyStrategy

au.edu.unimelb.swen.oop.mokepon.battle接口

接口:决定敌人这一回合用哪个技能。

在游戏里
看不见:在 Battle.playTurn 里被调用,结果出现在日志 “Enemy Galecrest used Tackle!” 这一行。
它的职责
Strategy 模式的接口。Battle 只认识它,以后加更聪明的敌人只要写新的实现类,不用改 Battle。
子类 / 实现者
CRandomEnemyStrategy
谁创建它
接口不能被 new,只能 new 它的实现类
谁存着它
CBattle 的字段 enemyStrategy: EnemyStrategy
方法 1 个
+ chooseSkill(Fighter enemy, Random random): Skill · 第 11 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
battle/EnemyStrategy.java(13 行)
看老师打印稿里的这个类(UMLDoclet)
EnemyStrategy 的 UML 类图
CFighter

Fighter

au.edu.unimelb.swen.oop.mokepon.battle类

正在战斗的 Mokepon:带着会变的 HP、能量、属性和状态效果。

在游戏里
战斗界面两块卷轴上的 HP 条、能量条和 “225 / 225” 这类数字,显示的都是 Fighter 当前的值(已经乘过地形倍率)。
它的职责
把战斗中会变的数据和不变的 Mokepon 分开;战斗结束就丢掉,属性自然复原。伤害公式 calculateDamage 也在这里。
谁创建它
CEncounter(第 54、55 行 new Fighter(…))
谁存着它
CBattle 的字段 player: Fighter、enemy: Fighter;CBleeding 的字段 attacker: Fighter;CFighterPanel 的字段 fighter: Fighter
字段 5 个
- static final DAMAGE_SCALE: int
- final mokepon: Mokepon
- final startingStats: Map<Stat, Integer>
- final stats: Map<Stat, Integer>
- final effects: List<StatusEffect>
方法 23 个
+ Fighter(Mokepon mokepon, TerrainEffect terrainEffect) · 第 31 行
+ getName(): String · 第 40 行
+ getImagePath(): String · 第 44 行
+ getSkills(): List<Skill> · 第 48 行
+ getStat(Stat stat): int · 第 52 行
+ getHp(): int · 第 56 行
+ getMaxHp(): int · 第 60 行
+ getEnergy(): int · 第 64 行
+ getMaxEnergy(): int · 第 68 行
+ isAlive(): boolean · 第 72 行
+ canUse(Skill skill): boolean · 第 77 行
+ takeDamage(int amount): void · 第 82 行
+ spendEnergy(int amount): void · 第 89 行
+ raiseStat(Stat stat, int amount): int · 第 95 行
+ restoreHp(): void · 第 102 行
+ restoreEnergy(): void · 第 106 行
+ reduceHpToOne(): void · 第 110 行
+ calculateDamage(Fighter target, double power): int · 第 118 行
+ addEffect(StatusEffect effect): void · 第 124 行
+ getMissChance(): double · 第 131 行
+ applyLingeringDamage(): List<String> · 第 142 行
+ countDownEffects(): void · 第 154 行
- getDamageMultiplier(): double · 第 168 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;13 状态效果和道具;14 战斗界面是怎么画出来的;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
battle/Fighter.java(176 行)
看老师打印稿里的这个类(UMLDoclet)
Fighter 的 UML 类图
CRandomEnemyStrategy

RandomEnemyStrategy

au.edu.unimelb.swen.oop.mokepon.battle类

EnemyStrategy 的实现:从能量够用的技能里随机挑一个。

在游戏里
看不见:每个敌人回合在 Battle 里运行,它挑出的技能名出现在日志 “Enemy ... used ...!”。
它的职责
Strategy 模式的具体策略(concrete strategy);Battle 的三参数构造器默认就用它。
家族关系
实现 IEnemyStrategy
谁创建它
CBattle(第 26 行 new RandomEnemyStrategy(…))
谁存着它
没有别的类把它存成字段
方法 1 个
+ chooseSkill(Fighter enemy, Random random): Skill · 第 12 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
battle/RandomEnemyStrategy.java(22 行)
看老师打印稿里的这个类(UMLDoclet)
RandomEnemyStrategy 的 UML 类图
CGameData

GameData

au.edu.unimelb.swen.oop.mokepon.data类

数据文件里的全部键值对,外加转成数字和坐标的小工具。

在游戏里
看不见:启动时在 Main 里使用。所有解析器都通过它读 mokepon.game,比如 getPosition 把 “10,18” 变成一个 Position。
它的职责
包装 Java 的 Properties,把“怎样读文本”集中在一处;countEntries 数出编号条目有几个。
谁创建它
CGameDataReader(第 34 行 new GameData(…))
谁存着它
没有别的类把它存成字段
字段 1 个
- final properties: Properties
方法 6 个
+ GameData(Properties properties) · 第 12 行
+ has(String key): boolean · 第 16 行
+ getText(String key): String · 第 20 行
+ getNumber(String key): int · 第 24 行
+ getPosition(String key): Position · 第 29 行
+ countEntries(String prefix, String suffix): int · 第 37 行
在哪章讲
02 Java 最小知识包;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;09 遇敌:地形、类型和挑敌人;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
data/GameData.java(45 行)
看老师打印稿里的这个类(UMLDoclet)
GameData 的 UML 类图
CGameDataReader

GameDataReader

au.edu.unimelb.swen.oop.mokepon.data类

读取命令行参数 data=... 指定的数据文件,生成 GameData。

在游戏里
看不见:启动时第一个运行。参数缺失或文件不存在时,Main 在控制台打印 “Error loading ...”,游戏窗口不会打开。
它的职责
只负责找到并加载文件,并去掉每个值两边的空格;出错就抛异常,交给 Main 处理。
谁创建它
CMain(第 25 行 new GameDataReader(…))
谁存着它
没有别的类把它存成字段
字段 1 个
- static final ARGUMENT_PREFIX: String
方法 1 个
+ read(List<String> arguments): GameData · 第 17 行
在哪章讲
04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
data/GameDataReader.java(37 行)
看老师打印稿里的这个类(UMLDoclet)
GameDataReader 的 UML 类图
CGameImages

GameImages

au.edu.unimelb.swen.oop.mokepon.data类

界面要用的图片路径:类型图标、地块、方向按钮、道具、玩家。

在游戏里
看不见它本身,但它存的路径就是你看到的图:地图格子、四个箭头按钮、道具图标、地图上的玩家、名字旁的火焰图标。
它的职责
只存路径、不加载图片,所以 data 包不依赖 JavaFX;构造时用 Map.copyOf 拷贝,外面改不了。
谁创建它
CImageParser(第 20 行 new GameImages(…))
谁存着它
CGameWindow 的字段 images: GameImages;CSelectScreen 的字段 images: GameImages
字段 5 个
- final typeImages: Map<MokeponType, String>
- final tileImages: Map<Terrain, String>
- final buttonImages: Map<Direction, String>
- final itemImages: Map<Item, String>
- final playerImage: String
方法 7 个
+ GameImages(Map<MokeponType, String> typeImages, Map<Terrain, String> tileImages, Map<Direction, String> buttonImages, Map<Item, String> itemImages, String playerImage) · 第 20 行
+ hasTypeImage(MokeponType type): boolean · 第 31 行
+ getTypeImage(MokeponType type): String · 第 35 行
+ getTileImage(Terrain terrain): String · 第 39 行
+ getButtonImage(Direction direction): String · 第 43 行
+ getItemImage(Item item): String · 第 47 行
+ getPlayerImage(): String · 第 51 行
在哪章讲
04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;09 遇敌:地形、类型和挑敌人;13 状态效果和道具;14 战斗界面是怎么画出来的;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
data/GameImages.java(55 行)
看老师打印稿里的这个类(UMLDoclet)
GameImages 的 UML 类图
CImageParser

ImageParser

au.edu.unimelb.swen.oop.mokepon.data类

从数据文件读出所有图片路径,组装成一个 GameImages。

在游戏里
看不见:启动时在 Main 里运行一次,结果交给 GameWindow 和各个界面。
它的职责
一个泛型方法 readImages 按枚举值的名字找键(如 map.tiles.images.grass);NORMAL 没有键,所以没有图标。
谁创建它
CMain(第 37 行 new ImageParser(…))
谁存着它
没有别的类把它存成字段
方法 3 个
+ parse(GameData data): GameImages · 第 14 行
- readImages(GameData data, String prefix, T[] values): <T extends Enum<T>> Map<T, String> · 第 28 行
- readItemImages(GameData data): Map<Item, String> · 第 41 行
在哪章讲
02 Java 最小知识包;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;07 选择界面 SelectScreen;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
data/ImageParser.java(49 行)
看老师打印稿里的这个类(UMLDoclet)
ImageParser 的 UML 类图
CMapParser

MapParser

au.edu.unimelb.swen.oop.mokepon.data类

把数据文件的地图部分变成 GameMap:地块、起点和地图上的物体。

在游戏里
看不见:启动时运行。地图的样子,以及感叹号、问号箱子和出口门的位置,都是它读出来的。
它的职责
给三组标记配不同的 EnemyPicker(随机、强、弱),在这里把策略对象注入 Marker,Marker 本身不用知道区别。
谁创建它
CMain(第 36 行 new MapParser(…))
谁存着它
没有别的类把它存成字段
字段 2 个
- static final TILES_PREFIX: String
- static final ITEMS_PREFIX: String
方法 5 个
+ parse(GameData data): GameMap · 第 25 行
- parseTiles(GameData data): Terrain[][] · 第 43 行
- parseMarkers(GameData data, String group, EnemyPicker picker): List<MapObject> · 第 57 行
- parseMysteryBoxes(GameData data): List<MapObject> · 第 69 行
- parseExit(GameData data): Exit · 第 81 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
data/MapParser.java(86 行)
看老师打印稿里的这个类(UMLDoclet)
MapParser 的 UML 类图
CMokeponParser

MokeponParser

au.edu.unimelb.swen.oop.mokepon.data类

把数据文件里的 Mokepon 条目变成 Mokepon 对象列表。

在游戏里
看不见:启动时运行。选择界面左边那 36 个名字按钮,就来自它读出的列表。
它的职责
按编号 mokepon.0、mokepon.1… 逐个读;技能名通过 SkillCatalogue.find 换成共享的技能对象。
谁创建它
CMain(第 35 行 new MokeponParser(…))
谁存着它
没有别的类把它存成字段
字段 1 个
- static final PREFIX: String
方法 3 个
+ parse(GameData data): List<Mokepon> · 第 18 行
- parseMokepon(GameData data, String prefix): Mokepon · 第 27 行
- parseSkills(String skillNames): List<Skill> · 第 43 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;07 选择界面 SelectScreen;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;12 技能家族:继承和模板方法;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
data/MokeponParser.java(51 行)
看老师打印稿里的这个类(UMLDoclet)
MokeponParser 的 UML 类图
CBleeding

Bleeding

au.edu.unimelb.swen.oop.mokepon.effect类

流血效果:每回合结束按攻击者一半力量扣血,持续 2 回合。

在游戏里
流血伤害不写日志,只看到 HP 条在回合末变短;第二次扣血后,日志出现 “The bleeding stopped.”。
它的职责
StatusEffect 的子类,只覆盖 applyLingeringDamage;记住攻击者,用他一半的力量算伤害。
家族关系
继承 AStatusEffect
谁创建它
CLance(第 20 行 new Bleeding(…))
谁存着它
没有别的类把它存成字段
字段 3 个
- static final TURNS: int
- static final HALF_STRENGTH: double
- final attacker: Fighter
方法 2 个
+ Bleeding(Fighter attacker) · 第 15 行
+ applyLingeringDamage(Fighter owner): List<String> · 第 24 行
在哪章讲
04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
effect/Bleeding.java(32 行)
看老师打印稿里的这个类(UMLDoclet)
Bleeding 的 UML 类图
CBlinded

Blinded

au.edu.unimelb.swen.oop.mokepon.effect类

致盲效果:目标性技能额外有 50% 机会打空,持续 3 回合。

在游戏里
效果本身看不见:中招时日志写 “Pocket sand blinded ...!”(这句来自 PocketSand);之后被致盲的一方更常出现 “But they missed.”。
它的职责
StatusEffect 的子类,只覆盖 getMissChance() 返回 0.5;TargetedSkill 通过普通命中检查后再用它判一次。
家族关系
继承 AStatusEffect
谁创建它
CPocketSand(第 17 行 new Blinded(…))
谁存着它
没有别的类把它存成字段
字段 2 个
+ static final TURNS: int
- static final MISS_CHANCE: double
方法 2 个
+ Blinded() · 第 10 行
+ getMissChance(): double · 第 15 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;12 技能家族:继承和模板方法;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
effect/Blinded.java(19 行)
看老师打印稿里的这个类(UMLDoclet)
Blinded 的 UML 类图
AStatusEffect

StatusEffect

au.edu.unimelb.swen.oop.mokepon.effect抽象类

抽象类:所有状态效果的共同部分,主要是还剩几回合。

在游戏里
看不见:挂在 Fighter 的 effects 列表里,在战斗中改变伤害、命中,或在回合末扣血。
它的职责
三个方法先写好“不改变任何东西”的默认值,子类只覆盖自己要改的那个;Fighter 用多态统一处理所有效果。
子类 / 实现者
CBleeding CBlinded CStunned
谁创建它
抽象类不能直接 new,只能 new 它的子类
谁存着它
CFighter 的字段 effects: List<StatusEffect>
字段 1 个
- turnsLeft: int
方法 7 个
# StatusEffect(int turns) · 第 12 行
+ getDamageMultiplier(): double · 第 17 行
+ getMissChance(): double · 第 22 行
+ applyLingeringDamage(Fighter owner): List<String> · 第 29 行
+ countDown(): void · 第 34 行
+ isOver(): boolean · 第 38 行
# isLastTurn(): boolean · 第 43 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
effect/StatusEffect.java(47 行)
看老师打印稿里的这个类(UMLDoclet)
StatusEffect 的 UML 类图
CStunned

Stunned

au.edu.unimelb.swen.oop.mokepon.effect类

眩晕效果:被眩晕的一方造成的伤害减半,持续 3 回合。

在游戏里
中招时日志写 “... was stunned! Their damage is halved for 3 turns.”(这句来自 Stun);之后它打出的伤害数字变小。
它的职责
StatusEffect 的子类,只覆盖 getDamageMultiplier() 返回 0.5;算伤害时最后乘上它。
家族关系
继承 AStatusEffect
谁创建它
CStun(第 17 行 new Stunned(…))
谁存着它
没有别的类把它存成字段
字段 2 个
+ static final TURNS: int
- static final DAMAGE_MULTIPLIER: double
方法 2 个
+ Stunned() · 第 8 行
+ getDamageMultiplier(): double · 第 13 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;12 技能家族:继承和模板方法;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
effect/Stunned.java(17 行)
看老师打印稿里的这个类(UMLDoclet)
Stunned 的 UML 类图
CCoffee

Coffee

au.edu.unimelb.swen.oop.mokepon.item类

道具 Coffee:把玩家 Mokepon 的能量补满。

在游戏里
战斗界面第 3 个道具按钮(杯子图标);地图卷轴里的 “Coffee:” 一行;用后日志写 “... It restored all your energy!”。
它的职责
Item 的子类,只覆盖 use():调用 player.restoreEnergy();数据文件里叫 COFFEE。
家族关系
继承 AItem
谁创建它
CItemCatalogue(第 11 行 new Coffee(…))
谁存着它
没有别的类把它存成字段
方法 2 个
+ Coffee() · 第 7 行
+ use(Fighter player, Fighter enemy): String · 第 12 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
item/Coffee.java(17 行)
看老师打印稿里的这个类(UMLDoclet)
Coffee 的 UML 类图
CHealthTonic

HealthTonic

au.edu.unimelb.swen.oop.mokepon.item类

道具 Health Tonic:把玩家 Mokepon 的 HP 回满。

在游戏里
战斗界面第 1 个道具按钮(绿色十字);地图卷轴里的 “Health Tonic:” 一行;用后日志写 “... It healed you to max hp!”。
它的职责
Item 的子类,只覆盖 use():调用 player.restoreHp();数据文件里叫 HEALTH。
家族关系
继承 AItem
谁创建它
CItemCatalogue(第 10 行 new HealthTonic(…))
谁存着它
没有别的类把它存成字段
方法 2 个
+ HealthTonic() · 第 7 行
+ use(Fighter player, Fighter enemy): String · 第 12 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;10 战斗的数据:Mokepon、Fighter、Battle;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
item/HealthTonic.java(17 行)
看老师打印稿里的这个类(UMLDoclet)
HealthTonic 的 UML 类图
CInventory

Inventory

au.edu.unimelb.swen.oop.mokepon.item类

背包:记录每种道具各有几个。

在游戏里
地图右上卷轴 Inventory 下面的三个数字,和战斗界面道具按钮上的数字,读的都是同一个 Inventory。
它的职责
用 LinkedHashMap 计数;每种道具只有一个对象,所以直接拿对象当键。Player 和 Battle 共用它。
谁创建它
COverworld(第 38 行 new Inventory(…))
谁存着它
CBattle 的字段 inventory: Inventory;CPlayer 的字段 inventory: Inventory
字段 1 个
- final counts: Map<Item, Integer>
方法 6 个
+ Inventory(List<Item> items) · 第 15 行
+ getItems(): List<Item> · 第 21 行
+ getCount(Item item): int · 第 25 行
+ has(Item item): boolean · 第 29 行
+ add(Item item): void · 第 33 行
+ remove(Item item): void · 第 38 行
在哪章讲
01 先玩一局:用真实截图认识游戏;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;08 地图世界:走一步发生了什么;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;13 状态效果和道具;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
item/Inventory.java(44 行)
看老师打印稿里的这个类(UMLDoclet)
Inventory 的 UML 类图
AItem

Item

au.edu.unimelb.swen.oop.mokepon.item抽象类

抽象类:一次性道具,有类型名、显示名、图片键和 use()。

在游戏里
它本身看不见;三个子类就是三个道具按钮和卷轴里的三行。日志 “You used your ... on ...” 的开头由它的 describeUse 拼出。
它的职责
抽象方法 use() 让每种道具各写各的效果(多态);加新道具只要写新子类,不改旧代码(开闭原则)。
子类 / 实现者
CCoffee CHealthTonic CPoison
谁创建它
抽象类不能直接 new,只能 new 它的子类
谁存着它
CGameImages 的字段 itemImages: Map<Item, String>;CInventory 的字段 counts: Map<Item, Integer>;CBattleScreen 的字段 itemButtons: Map<Item, GameButton>;CPlayerStatsScroll 的字段 itemValues: Map<Item, Label>;CMysteryBox 的字段 item: Item
字段 3 个
- final typeName: String
- final name: String
- final imageName: String
方法 6 个
# Item(String typeName, String name, String imageName) · 第 14 行
+ getTypeName(): String · 第 20 行
+ getName(): String · 第 24 行
+ getImageName(): String · 第 28 行
+ use(Fighter player, Fighter enemy): String · 第 35 行
# describeUse(Fighter target, String result): String · 第 40 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
item/Item.java(44 行)
看老师打印稿里的这个类(UMLDoclet)
Item 的 UML 类图
CItemCatalogue

ItemCatalogue

au.edu.unimelb.swen.oop.mokepon.item类

全部道具的目录:每种道具只造一个对象,全游戏共用。

在游戏里
看不见,但它决定顺序:卷轴里是 Health Tonic、Coffee、Poison;战斗按钮是 Health Tonic、Poison、Coffee。
它的职责
只有静态方法 getAll、getBattleOrder、find;find 把数据文件里的 “POISON” 换成道具对象。
谁创建它
只有 static 成员,直接用类名调用,不需要 new
谁存着它
没有别的类把它存成字段
字段 5 个
- static final HEALTH_TONIC: Item
- static final COFFEE: Item
- static final POISON: Item
- static final ITEMS: List<Item>
- static final BATTLE_ORDER: List<Item>
方法 3 个
+ getAll(): List<Item> · 第 19 行
+ getBattleOrder(): List<Item> · 第 23 行
+ find(String typeName): Item · 第 28 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;10 战斗的数据:Mokepon、Fighter、Battle;13 状态效果和道具;14 战斗界面是怎么画出来的;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
item/ItemCatalogue.java(37 行)
看老师打印稿里的这个类(UMLDoclet)
ItemCatalogue 的 UML 类图
CPoison

Poison

au.edu.unimelb.swen.oop.mokepon.item类

道具 Poison:把敌人的 HP 直接降到 1。

在游戏里
战斗界面第 2 个道具按钮(绿色圆球);地图卷轴里的 “Poison:” 一行;用后日志写 “You used your Poison on ... It devastated them!”。
它的职责
Item 的子类,只覆盖 use():调用 enemy.reduceHpToOne();是唯一作用在敌人身上的道具。
家族关系
继承 AItem
谁创建它
CItemCatalogue(第 12 行 new Poison(…))
谁存着它
没有别的类把它存成字段
方法 2 个
+ Poison() · 第 7 行
+ use(Fighter player, Fighter enemy): String · 第 12 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
item/Poison.java(17 行)
看老师打印稿里的这个类(UMLDoclet)
Poison 的 UML 类图
CMokepon

Mokepon

au.edu.unimelb.swen.oop.mokepon.model类

数据文件里的一只 Mokepon:名字、图片、类型、六项属性和技能。

在游戏里
选择界面的头像、名字和属性卷轴,以及地图右上卷轴里的属性,都来自 Mokepon(没有乘地形倍率的原始值)。
它的职责
不可变(immutable):字段全是 final,构造时拷贝 Map 和 List;战斗中会变的数据交给 Fighter。
谁创建它
CMokeponParser(第 39 行 new Mokepon(…))
谁存着它
CFighter 的字段 mokepon: Mokepon;CGameWindow 的字段 mokepons: List<Mokepon>;CSelectScreen 的字段 selectedMokepon: Mokepon;CEncounter 的字段 playerMokepon: Mokepon、enemy: Mokepon;COverworld 的字段 mokepons: List<Mokepon>;CPlayer 的字段 mokepon: Mokepon
字段 5 个
- final name: String
- final imagePath: String
- final type: MokeponType
- final stats: Map<Stat, Integer>
- final skills: List<Skill>
方法 6 个
+ Mokepon(String name, String imagePath, MokeponType type, Map<Stat, Integer> stats, List<Skill> skills) · 第 19 行
+ getName(): String · 第 28 行
+ getImagePath(): String · 第 32 行
+ getType(): MokeponType · 第 36 行
+ getStat(Stat stat): int · 第 40 行
+ getSkills(): List<Skill> · 第 44 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;07 选择界面 SelectScreen;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
model/Mokepon.java(48 行)
看老师打印稿里的这个类(UMLDoclet)
Mokepon 的 UML 类图
EMokeponType

MokeponType

au.edu.unimelb.swen.oop.mokepon.model枚举

枚举:五种类型;除 NORMAL 外,每种有一个强势地形和一个弱势地形。

在游戏里
选择界面名字旁边的类型图标(如 FIRE 的火焰)和 “Type: FIRE” 这一行;NORMAL 没有图标。
它的职责
每个常量带构造参数(强、弱地形);getEffectOn(terrain) 返回 ADVANTAGE、DISADVANTAGE 或 NEUTRAL。
谁创建它
枚举的几个值在类加载时就自动建好了,不用 new
谁存着它
CGameImages 的字段 typeImages: Map<MokeponType, String>;CMokepon 的字段 type: MokeponType
枚举值
NORMAL、FIRE、ICE、WATER、LIGHTNING
字段 2 个
- final strongTerrain: Terrain
- final weakTerrain: Terrain
方法 2 个
~ MokeponType(Terrain strongTerrain, Terrain weakTerrain) · 第 17 行
+ getEffectOn(Terrain terrain): TerrainEffect · 第 23 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;07 选择界面 SelectScreen;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;17 考试准备:用这份代码答题
源文件
model/MokeponType.java(33 行)
看老师打印稿里的这个类(UMLDoclet)
MokeponType 的 UML 类图
EStat

Stat

au.edu.unimelb.swen.oop.mokepon.model枚举

枚举:六项属性(HP、Energy、Strength 等)和各自的合法范围。

在游戏里
选择界面和地图卷轴上的 “HP:”、“Energy:”… 用的是它的 label;日志 “They raised their strength ...” 里的属性名也是。
它的职责
limit() 把数值压回范围(HP 1–1000,其余 1–100),所以 Impike 力量 76×1.5=114,进战斗后只有 100。
谁创建它
枚举的几个值在类加载时就自动建好了,不用 new
谁存着它
CFighter 的字段 startingStats: Map<Stat, Integer>、stats: Map<Stat, Integer>;CMokepon 的字段 stats: Map<Stat, Integer>;ABoostSkill 的字段 stat: Stat;CSelectScreen 的字段 statValues: Map<Stat, Label>
枚举值
HP、ENERGY、STRENGTH、ACCURACY、DEFENCE、DODGE
字段 3 个
- final label: String
- final minimum: int
- final maximum: int
方法 3 个
~ Stat(String label, int minimum, int maximum) · 第 16 行
+ getLabel(): String · 第 22 行
+ limit(int value): int · 第 27 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;07 选择界面 SelectScreen;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;12 技能家族:继承和模板方法;15 逃跑、回主菜单、走到出口;17 考试准备:用这份代码答题
源文件
model/Stat.java(31 行)
看老师打印稿里的这个类(UMLDoclet)
Stat 的 UML 类图
ETerrain

Terrain

au.edu.unimelb.swen.oop.mokepon.model枚举

枚举:地图上的七种地块,每种对应数据文件里的一个字母。

在游戏里
地图上的每一格:草地、森林、水、岩石、小路,以及走不上去的 OCEAN(深蓝色)和 BARRIER(灰色方砖)。
它的职责
每种地块带一个字母和 walkable;fromSymbol(‘G’) 把字母变成枚举值,MapParser 用它读每一行地图。
谁创建它
枚举的几个值在类加载时就自动建好了,不用 new
谁存着它
CGameImages 的字段 tileImages: Map<Terrain, String>;EMokeponType 的字段 strongTerrain: Terrain、weakTerrain: Terrain;CEncounter 的字段 terrain: Terrain;CGameMap 的字段 tiles: Terrain[][]
枚举值
BARRIER、FOREST、GRASS、OCEAN、PATH、ROCKS、WATER
字段 2 个
- final symbol: char
- final walkable: boolean
方法 3 个
~ Terrain(char symbol, boolean walkable) · 第 16 行
+ isWalkable(): boolean · 第 21 行
+ fromSymbol(char symbol): Terrain · 第 26 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;17 考试准备:用这份代码答题
源文件
model/Terrain.java(35 行)
看老师打印稿里的这个类(UMLDoclet)
Terrain 的 UML 类图
ETerrainEffect

TerrainEffect

au.edu.unimelb.swen.oop.mokepon.model枚举

枚举:地形对属性的影响:优势 ×1.5、中性 ×1、劣势 ×0.5。

在游戏里
遇敌对话框里 “Your mokepon will be at an advantage here!” 的后半句;进入战斗后属性改变,如 Impike 的 HP 150 → 225。
它的职责
adjust() 乘上倍率再四舍五入(Math.round);Fighter 构造时对每项属性调用它,再用 Stat.limit 限制范围。
谁创建它
枚举的几个值在类加载时就自动建好了,不用 new
谁存着它
CTerrainEnemyPicker 的字段 wantedEffect: TerrainEffect
枚举值
ADVANTAGE、NEUTRAL、DISADVANTAGE
字段 2 个
- final multiplier: double
- final description: String
方法 3 个
~ TerrainEffect(double multiplier, String description) · 第 12 行
+ getDescription(): String · 第 18 行
+ adjust(int value): int · 第 23 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;17 考试准备:用这份代码答题
源文件
model/TerrainEffect.java(27 行)
看老师打印稿里的这个类(UMLDoclet)
TerrainEffect 的 UML 类图
CAim

Aim

au.edu.unimelb.swen.oop.mokepon.skill类

技能 Aim:花 3 点能量,提高自己的命中(Accuracy)。

在游戏里
战斗按钮 “Aim [3]”;日志 “They raised their accuracy by N points!”。
它的职责
BoostSkill 的子类,只在构造器里传入名字、费用 3 和 Stat.ACCURACY,没有别的代码。
家族关系
继承 ABoostSkill
谁创建它
CSkillCatalogue(第 13 行 new Aim(…))
谁存着它
没有别的类把它存成字段
字段 1 个
- static final ENERGY_COST: int
方法 1 个
+ Aim() · 第 9 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;12 技能家族:继承和模板方法;17 考试准备:用这份代码答题
源文件
skill/Aim.java(13 行)
看老师打印稿里的这个类(UMLDoclet)
Aim 的 UML 类图
AAttackSkill

AttackSkill

au.edu.unimelb.swen.oop.mokepon.skill抽象类

抽象类:命中后造成伤害的攻击技能,彼此只差威力 power。

在游戏里
日志 “Hit Galecrest for 83 damage!” 这句由它的 applyHit 拼出;目标的 HP 条随之变短。
它的职责
TargetedSkill 的子类,实现 applyHit:按威力算伤害再扣血;是 Template Method 里的一步。
家族关系
继承 ATargetedSkill
子类 / 实现者
CBite CLance CTackle
谁创建它
抽象类不能直接 new,只能 new 它的子类
谁存着它
没有别的类把它存成字段
字段 1 个
- final power: double
方法 2 个
# AttackSkill(String name, int energyCost, double power) · 第 12 行
# applyHit(Fighter user, Fighter target, Random random): String · 第 18 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;12 技能家族:继承和模板方法;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
skill/AttackSkill.java(24 行)
看老师打印稿里的这个类(UMLDoclet)
AttackSkill 的 UML 类图
CBite

Bite

au.edu.unimelb.swen.oop.mokepon.skill类

技能 Bite:花 1 点能量的普通攻击,威力 1。

在游戏里
战斗按钮 “Bite [1]”;打中时日志写 “Hit ... for N damage!”。
它的职责
AttackSkill 的子类,只传入名字、费用 1 和威力 1。
家族关系
继承 AAttackSkill
谁创建它
CSkillCatalogue(第 12 行 new Bite(…))
谁存着它
没有别的类把它存成字段
字段 2 个
- static final ENERGY_COST: int
- static final POWER: double
方法 1 个
+ Bite() · 第 8 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;12 技能家族:继承和模板方法;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
skill/Bite.java(12 行)
看老师打印稿里的这个类(UMLDoclet)
Bite 的 UML 类图
ABoostSkill

BoostSkill

au.edu.unimelb.swen.oop.mokepon.skill抽象类

抽象类:一定成功、给自己某项属性加 1 到 10 点的强化技能。

在游戏里
日志 “They raised their strength by 5 points!” 这类句子;写的是实际加了多少(到上限就加得少)。
它的职责
Skill 的子类,实现 applyEffect:随机 1–10 再 raiseStat,不做命中检查;四个子类只差加哪项属性。
家族关系
继承 ASkill
子类 / 实现者
CAim CBunker CNimble CSwole
谁创建它
抽象类不能直接 new,只能 new 它的子类
谁存着它
没有别的类把它存成字段
字段 2 个
- static final MAX_BOOST: int
- final stat: Stat
方法 2 个
# BoostSkill(String name, int energyCost, Stat stat) · 第 15 行
# applyEffect(Fighter user, Fighter target, Random random): String · 第 22 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
skill/BoostSkill.java(29 行)
看老师打印稿里的这个类(UMLDoclet)
BoostSkill 的 UML 类图
CBunker

Bunker

au.edu.unimelb.swen.oop.mokepon.skill类

技能 Bunker:花 3 点能量,提高自己的防御(Defence)。

在游戏里
战斗按钮 “Bunker [3]”;日志 “They raised their defence by N points!”。
它的职责
BoostSkill 的子类,只传入名字、费用 3 和 Stat.DEFENCE。
家族关系
继承 ABoostSkill
谁创建它
CSkillCatalogue(第 13 行 new Bunker(…))
谁存着它
没有别的类把它存成字段
字段 1 个
- static final ENERGY_COST: int
方法 1 个
+ Bunker() · 第 9 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;12 技能家族:继承和模板方法;17 考试准备:用这份代码答题
源文件
skill/Bunker.java(13 行)
看老师打印稿里的这个类(UMLDoclet)
Bunker 的 UML 类图
CLance

Lance

au.edu.unimelb.swen.oop.mokepon.skill类

技能 Lance:花 4 点能量,用一半力量攻击,并让目标流血。

在游戏里
战斗按钮 “Lance [4]”;日志 “Hit Galecrest for 83 damage! They started bleeding!”。
它的职责
AttackSkill 的子类,覆盖 applyHit:先 super.applyHit 造成伤害,再给目标加 new Bleeding(user)。
家族关系
继承 AAttackSkill
谁创建它
CSkillCatalogue(第 12 行 new Lance(…))
谁存着它
没有别的类把它存成字段
字段 2 个
- static final ENERGY_COST: int
- static final HALF_STRENGTH: double
方法 2 个
+ Lance() · 第 12 行
# applyHit(Fighter user, Fighter target, Random random): String · 第 18 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;12 技能家族:继承和模板方法;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
skill/Lance.java(24 行)
看老师打印稿里的这个类(UMLDoclet)
Lance 的 UML 类图
CNimble

Nimble

au.edu.unimelb.swen.oop.mokepon.skill类

技能 Nimble:花 3 点能量,提高自己的闪避(Dodge)。

在游戏里
战斗按钮 “Nimble [3]”;日志 “They raised their dodge by N points!”。
它的职责
BoostSkill 的子类,只传入名字、费用 3 和 Stat.DODGE。
家族关系
继承 ABoostSkill
谁创建它
CSkillCatalogue(第 13 行 new Nimble(…))
谁存着它
没有别的类把它存成字段
字段 1 个
- static final ENERGY_COST: int
方法 1 个
+ Nimble() · 第 9 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;12 技能家族:继承和模板方法;17 考试准备:用这份代码答题
源文件
skill/Nimble.java(13 行)
看老师打印稿里的这个类(UMLDoclet)
Nimble 的 UML 类图
CPocketSand

PocketSand

au.edu.unimelb.swen.oop.mokepon.skill类

技能 Pocket Sand:花 4 点能量,没有伤害,但让目标致盲 3 回合。

在游戏里
战斗按钮 “Pocket Sand [4]”;日志 “Pocket sand blinded Bubbore!” 和 “Their targeted skills may miss for 3 turns.”。
它的职责
TargetedSkill 的子类,实现 applyHit:给目标加上 new Blinded();必须先通过命中检查才生效。
家族关系
继承 ATargetedSkill
谁创建它
CSkillCatalogue(第 12 行 new PocketSand(…))
谁存着它
没有别的类把它存成字段
字段 1 个
- static final ENERGY_COST: int
方法 2 个
+ PocketSand() · 第 11 行
# applyHit(Fighter user, Fighter target, Random random): String · 第 16 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
skill/PocketSand.java(22 行)
看老师打印稿里的这个类(UMLDoclet)
PocketSand 的 UML 类图
ASkill

Skill

au.edu.unimelb.swen.oop.mokepon.skill抽象类

抽象类:所有技能的共同部分:名字、能量费用和 use()。

在游戏里
技能按钮上的 “Lance [4]” 就是 getName() 加 getEnergyCost();每回合日志里技能的结果由 use() 返回。
它的职责
Template Method:final 的 use() 先扣能量,再调用抽象的 applyEffect(),由子类决定效果。
子类 / 实现者
ABoostSkill ATargetedSkill CWait
谁创建它
抽象类不能直接 new,只能 new 它的子类
谁存着它
CMokepon 的字段 skills: List<Skill>
字段 2 个
- final name: String
- final energyCost: int
方法 5 个
# Skill(String name, int energyCost) · 第 14 行
+ getName(): String · 第 19 行
+ getEnergyCost(): int · 第 23 行
+ use(Fighter user, Fighter target, Random random): String · 第 30 行
# applyEffect(Fighter user, Fighter target, Random random): String · 第 36 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;13 状态效果和道具;14 战斗界面是怎么画出来的;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
skill/Skill.java(38 行)
看老师打印稿里的这个类(UMLDoclet)
Skill 的 UML 类图
CSkillCatalogue

SkillCatalogue

au.edu.unimelb.swen.oop.mokepon.skill类

全部 10 个技能的目录:按名字找到对应的技能对象。

在游戏里
看不见:启动时 MokeponParser 用它把 “Bite|Wait” 这样的技能名换成技能对象。
它的职责
技能对象不会变,所以全游戏共用一份;find() 区分大小写,找不到就抛异常。加新技能要在这里登记。
谁创建它
只有 static 成员,直接用类名调用,不需要 new
谁存着它
没有别的类把它存成字段
字段 1 个
- static final SKILLS: List<Skill>
方法 1 个
+ find(String name): Skill · 第 16 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;10 战斗的数据:Mokepon、Fighter、Battle;12 技能家族:继承和模板方法;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
skill/SkillCatalogue.java(25 行)
看老师打印稿里的这个类(UMLDoclet)
SkillCatalogue 的 UML 类图
CStun

Stun

au.edu.unimelb.swen.oop.mokepon.skill类

技能 Stun:花 4 点能量,没有伤害,但让目标伤害减半 3 回合。

在游戏里
战斗按钮 “Stun [4]”;日志 “Galecrest was stunned! Their damage is halved for 3 turns.”。
它的职责
TargetedSkill 的子类,实现 applyHit:给目标加上 new Stunned();必须先通过命中检查才生效。
家族关系
继承 ATargetedSkill
谁创建它
CSkillCatalogue(第 12 行 new Stun(…))
谁存着它
没有别的类把它存成字段
字段 1 个
- static final ENERGY_COST: int
方法 2 个
+ Stun() · 第 11 行
# applyHit(Fighter user, Fighter target, Random random): String · 第 16 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
skill/Stun.java(22 行)
看老师打印稿里的这个类(UMLDoclet)
Stun 的 UML 类图
CSwole

Swole

au.edu.unimelb.swen.oop.mokepon.skill类

技能 Swole:花 3 点能量,提高自己的力量(Strength)。

在游戏里
战斗按钮 “Swole [3]”;日志 “They raised their strength by N points!”。
它的职责
BoostSkill 的子类,只传入名字、费用 3 和 Stat.STRENGTH。
家族关系
继承 ABoostSkill
谁创建它
CSkillCatalogue(第 13 行 new Swole(…))
谁存着它
没有别的类把它存成字段
字段 1 个
- static final ENERGY_COST: int
方法 1 个
+ Swole() · 第 9 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;12 技能家族:继承和模板方法;17 考试准备:用这份代码答题
源文件
skill/Swole.java(13 行)
看老师打印稿里的这个类(UMLDoclet)
Swole 的 UML 类图
CTackle

Tackle

au.edu.unimelb.swen.oop.mokepon.skill类

技能 Tackle:花 5 点能量的重击,威力 2(双倍伤害)。

在游戏里
战斗按钮 “Tackle [5]”;能量不到 5 时按钮变灰(如 Shellurk 只剩 3 点能量时)。
它的职责
AttackSkill 的子类,只传入名字、费用 5 和威力 2。
家族关系
继承 AAttackSkill
谁创建它
CSkillCatalogue(第 12 行 new Tackle(…))
谁存着它
没有别的类把它存成字段
字段 2 个
- static final ENERGY_COST: int
- static final POWER: double
方法 1 个
+ Tackle() · 第 8 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;12 技能家族:继承和模板方法;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
skill/Tackle.java(12 行)
看老师打印稿里的这个类(UMLDoclet)
Tackle 的 UML 类图
ATargetedSkill

TargetedSkill

au.edu.unimelb.swen.oop.mokepon.skill抽象类

抽象类:对准对手的技能,必须先通过命中检查才生效。

在游戏里
没打中时日志写 “But they missed.”,这句就是它的 MISS_MESSAGE。
它的职责
Template Method 的第二层:final 的 applyEffect 先做命中检查(再看致盲),通过了才调用子类的 applyHit。
家族关系
继承 ASkill
子类 / 实现者
AAttackSkill CPocketSand CStun
谁创建它
抽象类不能直接 new,只能 new 它的子类
谁存着它
没有别的类把它存成字段
字段 1 个
- static final MISS_MESSAGE: String
方法 5 个
# TargetedSkill(String name, int energyCost) · 第 13 行
# applyEffect(Fighter user, Fighter target, Random random): String · 第 18 行
# applyHit(Fighter user, Fighter target, Random random): String · 第 26 行
- hits(Fighter user, Fighter target, Random random): boolean · 第 31 行
- calculateHitChance(Fighter user, Fighter target): double · 第 38 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
skill/TargetedSkill.java(46 行)
看老师打印稿里的这个类(UMLDoclet)
TargetedSkill 的 UML 类图
CWait

Wait

au.edu.unimelb.swen.oop.mokepon.skill类

技能 Wait:什么都不做;费用是 -2,所以反而回 2 点能量。

在游戏里
战斗按钮 “Wait [-2]”;日志随机一句,如 “They wonder if this is a good strategy.”。
它的职责
直接继承 Skill,applyEffect 只返回一句随机消息;负的费用让 spendEnergy 变成加能量,也不会打空。
家族关系
继承 ASkill
谁创建它
CSkillCatalogue(第 13 行 new Wait(…))
谁存着它
没有别的类把它存成字段
字段 2 个
- static final ENERGY_COST: int
- static final MESSAGES: List<String>
方法 2 个
+ Wait() · 第 15 行
# applyEffect(Fighter user, Fighter target, Random random): String · 第 20 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
skill/Wait.java(24 行)
看老师打印稿里的这个类(UMLDoclet)
Wait 的 UML 类图
CBattleScreen

BattleScreen

au.edu.unimelb.swen.oop.mokepon.ui类

战斗界面:显示双方 Mokepon、技能按钮、道具按钮和日志。

在游戏里
整个战斗界面:左下玩家卷轴、右上敌人卷轴、Actions 下的技能按钮、上方道具按钮、右下日志框,以及 You Win / Game Over 对话框。
它的职责
GameScreen 的子类,只把点击和按键 1–4 交给 Battle 再刷新显示,规则全在 Battle;覆盖 canRunAway。
家族关系
继承 AGameScreen
谁创建它
CGameWindow(第 67 行 new BattleScreen(…))
谁存着它
没有别的类把它存成字段
字段 35 个
- static final SKILL_KEYS: List<KeyCode>
- static final BUTTON_RADIUS: int
- static final PLAYER_X: int
- static final PLAYER_Y: int
- static final PLAYER_WIDTH: int
- static final PLAYER_HEIGHT: int
- static final PLAYER_CONTENT_X: int
- static final ENEMY_X: int
- static final ENEMY_Y: int
- static final ENEMY_WIDTH: int
- static final ENEMY_HEIGHT: int
- static final ENEMY_CONTENT_X: int
- static final ACTIONS_X: int
- static final ACTIONS_LABEL_Y: int
- static final ACTIONS_FONT_SIZE: int
- static final SKILLS_Y: int
- static final SKILL_WIDTH: int
- static final SKILL_HEIGHT: int
- static final SKILL_GAP: int
- static final SKILL_FONT_SIZE: int
- static final ITEM_WIDTH: int
- static final ITEM_HEIGHT: int
- static final ITEM_ICON_SIZE: int
- static final ITEM_GAP: int
- static final ITEM_FONT_SIZE: int
- static final LOG_X: int
- static final LOG_Y: int
- static final LOG_HEIGHT: int
- static final LOG_FONT_SIZE: int
- final battle: Battle
- final playerPanel: FighterPanel
- final enemyPanel: FighterPanel
- final logArea: TextArea
- final skillButtons: List<GameButton>
- final itemButtons: Map<Item, GameButton>
方法 13 个
+ BattleScreen(Battle battle, GameImages images, GameNavigator navigator) · 第 73 行
+ canRunAway(): boolean · 第 103 行
# handleKey(KeyEvent event): void · 第 109 行
- useSkill(Skill skill): void · 第 117 行
- useItem(Item item): void · 第 122 行
- update(): void · 第 128 行
- showLog(): void · 第 141 行
- updateSkillButtons(): void · 第 148 行
- updateItemButtons(): void · 第 157 行
- showResult(): void · 第 170 行
- createSkillButtons(List<Skill> skills): VBox · 第 182 行
- createItemButtons(GameImages images): HBox · 第 203 行
- createLogArea(): TextArea · 第 225 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;12 技能家族:继承和模板方法;13 状态效果和道具;14 战斗界面是怎么画出来的;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/BattleScreen.java(236 行)
看老师打印稿里的这个类(UMLDoclet)
BattleScreen 的 UML 类图
CFighterPanel

FighterPanel

au.edu.unimelb.swen.oop.mokepon.ui类

战斗中一方的显示块:卷轴、头像、名字、HP 条和能量条。

在游戏里
战斗界面左下(玩家)和右上(敌人)两块卷轴各是一个 FighterPanel;只有玩家的条上写数字。
它的职责
组合(composition)一个 FighterScroll 和两个 StatBar;update() 让条和红色遮罩跟上 Fighter 的数据。
谁创建它
CBattleScreen(第 78、81 行 new FighterPanel(…))
谁存着它
CBattleScreen 的字段 playerPanel: FighterPanel、enemyPanel: FighterPanel
字段 14 个
- static final HP_COLOUR: String
- static final ENERGY_COLOUR: String
- static final PORTRAIT_SIZE: int
- static final NAME_FONT_SIZE: int
- static final NAME_OFFSET: int
- static final PORTRAIT_OFFSET: int
- static final HP_BAR_OFFSET: int
- static final ENERGY_BAR_OFFSET: int
- final fighter: Fighter
- final scroll: FighterScroll
- final portrait: ImageView
- final name: Label
- final hpBar: StatBar
- final energyBar: StatBar
方法 4 个
+ FighterPanel(Fighter fighter, Rectangle2D area, double contentX, boolean showNumbers) · 第 37 行
+ getNodes(): List<Node> · 第 63 行
+ getFaintMask(): Rectangle · 第 71 行
+ update(): void · 第 76 行
在哪章讲
01 先玩一局:用真实截图认识游戏;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;06 窗口、界面切换和菜单;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;14 战斗界面是怎么画出来的;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/FighterPanel.java(82 行)
看老师打印稿里的这个类(UMLDoclet)
FighterPanel 的 UML 类图
CFighterScroll

FighterScroll

au.edu.unimelb.swen.oop.mokepon.ui类

战斗者身后的卷轴图片,和倒下时盖上去的红色遮罩。

在游戏里
卷轴背景本身;Mokepon 倒下时整张卷轴变红(如 You Win 时敌人 Galecrest 的卷轴)。
它的职责
半透明红色矩形用卷轴图片做 clip,所以只有卷轴形状变红;遮罩单独返回,好画在最上层。
谁创建它
CFighterPanel(第 41 行 new FighterScroll(…))
谁存着它
CFighterPanel 的字段 scroll: FighterScroll
字段 3 个
- static final FAINT_TINT: Color
- final scroll: ImageView
- final faintMask: Rectangle
方法 5 个
+ FighterScroll(double x, double y, double width, double height) · 第 15 行
+ getScroll(): ImageView · 第 21 行
+ getFaintMask(): Rectangle · 第 26 行
+ setFainted(boolean fainted): void · 第 30 行
- createFaintMask(Image scrollImage, double x, double y, double width, double height): Rectangle · 第 35 行
在哪章讲
01 先玩一局:用真实截图认识游戏;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;14 战斗界面是怎么画出来的;17 考试准备:用这份代码答题
源文件
ui/FighterScroll.java(49 行)
看老师打印稿里的这个类(UMLDoclet)
FighterScroll 的 UML 类图
CGameButton

GameButton

au.edu.unimelb.swen.oop.mokepon.ui类

游戏统一样式的按钮:圆角、半透明的灰色背景。

在游戏里
选择界面的名字按钮和 Choose Mokepon、战斗的技能和道具按钮、地图的四个箭头按钮;变淡(40% 不透明)表示不能点。
它的职责
继承 JavaFX 的 Button,加上按下变深、选中高亮、setUsable 整体变淡;对话框里的按钮不是它。
家族关系
继承 Button
谁创建它
CBattleScreen(第 189、212 行 new GameButton(…));COverworldScreen(第 169 行 new GameButton(…));CSelectScreen(第 216、238 行 new GameButton(…))
谁存着它
CBattleScreen 的字段 skillButtons: List<GameButton>、itemButtons: Map<Item, GameButton>;COverworldScreen 的字段 moveButtons: Map<Direction, GameButton>;CSelectScreen 的字段 chooseButton: GameButton、selectedButton: GameButton
字段 4 个
- static final NORMAL: double
- static final HIGHLIGHTED: double
- static final DISABLED_OPACITY: double
- final cornerRadius: int
方法 6 个
+ GameButton(String text, Font font, int cornerRadius) · 第 18 行
+ GameButton(ImageView icon, int cornerRadius) · 第 26 行
+ addPressEffect(): void · 第 32 行
+ setHighlighted(boolean highlighted): void · 第 46 行
+ setUsable(boolean usable): void · 第 51 行
- setBackgroundOpacity(double opacity): void · 第 57 行
在哪章讲
01 先玩一局:用真实截图认识游戏;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;08 地图世界:走一步发生了什么;11 一个回合的完整流程;12 技能家族:继承和模板方法;14 战斗界面是怎么画出来的;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/GameButton.java(63 行)
看老师打印稿里的这个类(UMLDoclet)
GameButton 的 UML 类图
CGameMenu

GameMenu

au.edu.unimelb.swen.oop.mokepon.ui类

窗口顶部的 Game 菜单:Run away、Main menu、Exit 三项。

在游戏里
左上角的 “Game”;打开后有三项,灰色的不能点;快捷键 Ctrl+R、Ctrl+B、Alt+F4。
它的职责
只认识 GameNavigator 接口;update(screen) 按当前界面的 canRunAway 等方法开关选项。
谁创建它
CGameWindow(第 39 行 new GameMenu(…))
谁存着它
CGameWindow 的字段 menu: GameMenu
字段 3 个
- final menuBar: MenuBar
- final runAway: MenuItem
- final mainMenu: MenuItem
方法 3 个
+ GameMenu(GameNavigator navigator) · 第 19 行
+ getMenuBar(): MenuBar · 第 39 行
+ update(GameScreen screen): void · 第 46 行
在哪章讲
01 先玩一局:用真实截图认识游戏;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;14 战斗界面是怎么画出来的;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/GameMenu.java(51 行)
看老师打印稿里的这个类(UMLDoclet)
GameMenu 的 UML 类图
IGameNavigator

GameNavigator

au.edu.unimelb.swen.oop.mokepon.ui接口

接口:界面和菜单可以请窗口做的事,主要是切换界面。

在游戏里
看不见:点 Choose Mokepon、Fight!、Back to it! 或菜单项时,代码调用的就是它的方法(startGame、startBattle 等)。
它的职责
Dependency Inversion:界面和菜单只依赖这个接口,不依赖 GameWindow;GameWindow 实现它。
子类 / 实现者
CGameWindow
谁创建它
接口不能被 new,只能 new 它的实现类
谁存着它
AGameScreen 的字段 navigator: GameNavigator
方法 7 个
+ startGame(Mokepon playerChoice): void · 第 12 行
+ startBattle(): void · 第 15 行
+ winBattle(): void · 第 18 行
+ runAway(): void · 第 21 行
+ returnToMainMenu(): void · 第 24 行
+ quit(): void · 第 27 行
+ updateMenu(): void · 第 32 行
在哪章讲
01 先玩一局:用真实截图认识游戏;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;14 战斗界面是怎么画出来的;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/GameNavigator.java(34 行)
看老师打印稿里的这个类(UMLDoclet)
GameNavigator 的 UML 类图
AGameScreen

GameScreen

au.edu.unimelb.swen.oop.mokepon.ui抽象类

抽象类:三个界面的共同部分:背景、对话框、按键、菜单开关。

在游戏里
每个界面底下的棕色背景图;对话框由它放到最上层,对话框打开时它不再处理按键。
它的职责
Template Method:final 的 handleKeyPress 先挡掉对话框和组合键,再调子类的 handleKey。
子类 / 实现者
CBattleScreen COverworldScreen CSelectScreen
谁创建它
抽象类不能直接 new,只能 new 它的子类
谁存着它
CGameWindow 的字段 currentScreen: GameScreen
字段 3 个
- final navigator: GameNavigator
- final view: Pane
- dialog: ModalDialog
方法 13 个
# GameScreen(GameNavigator navigator) · 第 18 行
+ getView(): Pane · 第 24 行
+ handleKeyPress(KeyEvent event): void · 第 32 行
+ canRunAway(): boolean · 第 42 行
+ canReturnToMainMenu(): boolean · 第 47 行
# handleKey(KeyEvent event): void · 第 52 行
# getNavigator(): GameNavigator · 第 55 行
# addToView(Node... nodes): void · 第 60 行
# addToView(List<Node> nodes): void · 第 64 行
# showDialog(ModalDialog newDialog): void · 第 69 行
# closeDialog(): void · 第 76 行
# isDialogOpen(): boolean · 第 83 行
# createGameEndDialog(String heading): ModalDialog · 第 88 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;14 战斗界面是怎么画出来的;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/GameScreen.java(95 行)
看老师打印稿里的这个类(UMLDoclet)
GameScreen 的 UML 类图
CGameWindow

GameWindow

au.edu.unimelb.swen.oop.mokepon.ui类

游戏窗口:拥有 Stage,决定现在显示哪个界面。

在游戏里
标题为 Mokepon 的整个窗口:顶部菜单栏一直不变,下面换成选择、地图或战斗界面。
它的职责
实现 GameNavigator;用 BorderPane(菜单在 top、界面在 center)切换界面;用事件过滤器把按键交给当前界面。
家族关系
实现 IGameNavigator
谁创建它
CMain(第 38 行 new GameWindow(…))
谁存着它
没有别的类把它存成字段
字段 10 个
- final stage: Stage
- final mokepons: List<Mokepon>
- final map: GameMap
- final images: GameImages
- final menu: GameMenu
- final root: BorderPane
- final selectScreen: SelectScreen
- currentScreen: GameScreen
- world: Overworld
- overworldScreen: OverworldScreen
方法 10 个
+ GameWindow(Stage stage, List<Mokepon> mokepons, GameMap map, GameImages images) · 第 31 行
+ show(): void · 第 52 行
+ startGame(Mokepon playerChoice): void · 第 58 行
+ startBattle(): void · 第 66 行
+ winBattle(): void · 第 71 行
+ runAway(): void · 第 77 行
+ returnToMainMenu(): void · 第 84 行
+ quit(): void · 第 92 行
+ updateMenu(): void · 第 97 行
- showScreen(GameScreen screen): void · 第 101 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;14 战斗界面是怎么画出来的;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/GameWindow.java(107 行)
看老师打印稿里的这个类(UMLDoclet)
GameWindow 的 UML 类图
CLabelledStatBar

LabelledStatBar

au.edu.unimelb.swen.oop.mokepon.ui类

带数字的属性条:在条上写出 “225 / 225” 这样的数字。

在游戏里
战斗界面玩家卷轴上的 HP 条和能量条(如 “225 / 225”、“25 / 33”);敌人的条没有数字。
它的职责
继承 StatBar,覆盖 update() 和 getNodes()(先调 super),在父类的条上面多叠一个 Label。
家族关系
继承 CStatBar
谁创建它
CFighterPanel(第 51、53 行 new LabelledStatBar(…))
谁存着它
没有别的类把它存成字段
字段 3 个
- static final SEPARATOR: String
- static final FONT_SIZE: int
- final numbers: Label
方法 3 个
+ LabelledStatBar(double x, double y, String colour, int current, int max) · 第 17 行
+ update(int current, int max): void · 第 28 行
+ getNodes(): List<Node> · 第 35 行
在哪章讲
01 先玩一局:用真实截图认识游戏;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;11 一个回合的完整流程;14 战斗界面是怎么画出来的;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/LabelledStatBar.java(41 行)
看老师打印稿里的这个类(UMLDoclet)
LabelledStatBar 的 UML 类图
CMapView

MapView

au.edu.unimelb.swen.oop.mokepon.ui类

画地图:地块、还留在地图上的物体,以及玩家。

在游戏里
地图界面中间 20×20 格的大地图:每格 32 像素,上面有感叹号、问号、门和玩家图标。
它的职责
JavaFX 绘图集中在这里,world 包就不用碰 JavaFX;update() 按 Overworld 重新摆放物体;每张图片只加载一次。
谁创建它
COverworldScreen(第 63 行 new MapView(…))
谁存着它
COverworldScreen 的字段 mapView: MapView
字段 7 个
+ static final TILE_SIZE: int
- final world: Overworld
- final pane: Pane
- final objectLayer: Pane
- final playerView: ImageView
- final loadedImages: Map<String, Image>
- final objectViews: Map<MapObject, ImageView>
方法 8 个
+ MapView(Overworld world, GameImages images, double x, double y) · 第 30 行
+ getNode(): Pane · 第 46 行
+ update(): void · 第 53 行
- createTileLayer(GameMap map, GameImages images): Pane · 第 61 行
- createObjectView(MapObject object): ImageView · 第 74 行
- createTileView(Image image, Position position): ImageView · 第 84 行
- placeOnTile(ImageView imageView, Position position): void · 第 91 行
- getImage(String path): Image · 第 96 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;06 窗口、界面切换和菜单;08 地图世界:走一步发生了什么;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/MapView.java(103 行)
看老师打印稿里的这个类(UMLDoclet)
MapView 的 UML 类图
CModalDialog

ModalDialog

au.edu.unimelb.swen.oop.mokepon.ui类

模态对话框:屏幕中间的白框,带标题、消息和按钮。

在游戏里
“Encountered a Hexwing”、“You Win”、“Game Over”、“You finished the game! ...” 这些白框,以及后面的暗色遮罩。
它的职责
暗层盖住整个屏幕,挡住后面的点击;用 addMessage / addButton 按需加内容;按钮是普通的 Button。
谁创建它
CBattleScreen(第 173 行 new ModalDialog(…));AGameScreen(第 89 行 new ModalDialog(…));COverworldScreen(第 81 行 new ModalDialog(…))
谁存着它
AGameScreen 的字段 dialog: ModalDialog
字段 10 个
- static final SHADE_STYLE: String
- static final BOX_STYLE: String
- static final BUTTON_STYLE: String
- static final HEADING_SIZE: int
- static final SPACING: int
- static final BUTTON_GAP: int
- static final PADDING: Insets
- final layer: StackPane
- final messages: VBox
- final buttons: HBox
方法 5 个
+ ModalDialog(String heading) · 第 37 行
+ getLayer(): StackPane · 第 56 行
+ addMessage(String text): void · 第 61 行
+ addButton(String text, EventHandler<ActionEvent> action): void · 第 68 行
+ focusFirstButton(): void · 第 78 行
在哪章讲
01 先玩一局:用真实截图认识游戏;04 项目地图:9 个包、72 个类;06 窗口、界面切换和菜单;09 遇敌:地形、类型和挑敌人;11 一个回合的完整流程;14 战斗界面是怎么画出来的;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/ModalDialog.java(84 行)
看老师打印稿里的这个类(UMLDoclet)
ModalDialog 的 UML 类图
COverworldScreen

OverworldScreen

au.edu.unimelb.swen.oop.mokepon.ui类

地图界面:地图、右上属性卷轴、方向按钮和下方状态栏。

在游戏里
整个地图界面;状态栏的 “You picked up a Poison!”、遇敌对话框的 Fight! / Run Away! 都由它显示。
它的职责
GameScreen 的子类,实现 OverworldListener(Observer 的观察者);只显示,移动规则在 Overworld。
家族关系
继承 AGameScreen;实现 IOverworldListener
谁创建它
CGameWindow(第 60 行 new OverworldScreen(…))
谁存着它
CGameWindow 的字段 overworldScreen: OverworldScreen
字段 20 个
- static final ARROW_KEYS: Map<KeyCode, Direction>
- static final MAP_Y: int
- static final STATS_X: int
- static final STATS_Y: int
- static final STATS_WIDTH: int
- static final STATS_HEIGHT: int
- static final STATUS_WIDTH: int
- static final STATUS_HEIGHT: int
- static final STATUS_GAP: int
- static final STATUS_STYLE: String
- static final PAD_X: int
- static final PAD_Y: int
- static final BUTTON_SIZE: int
- static final BUTTON_GAP: int
- static final ICON_SIZE: int
- final world: Overworld
- final mapView: MapView
- final statsScroll: PlayerStatsScroll
- final statusBar: Label
- final moveButtons: Map<Direction, GameButton>
方法 12 个
+ OverworldScreen(Overworld world, GameImages images, GameNavigator navigator) · 第 55 行
+ onPlayerMoved(): void · 第 73 行
+ onEncounter(Encounter encounter): void · 第 80 行
+ onItemCollected(Item item): void · 第 97 行
+ onEncounterWon(Mokepon enemy): void · 第 103 行
+ onExitReached(int fightsWon): void · 第 109 行
# handleKey(KeyEvent event): void · 第 116 行
- movePlayer(Direction direction): void · 第 127 行
- update(): void · 第 134 行
- createStatusBar(double y): Label · 第 142 行
- createMovePad(GameImages images): GridPane · 第 153 行
- createMoveButton(Direction direction, GameImages images): GameButton · 第 166 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;13 状态效果和道具;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/OverworldScreen.java(178 行)
看老师打印稿里的这个类(UMLDoclet)
OverworldScreen 的 UML 类图
CPlayerStatsScroll

PlayerStatsScroll

au.edu.unimelb.swen.oop.mokepon.ui类

地图界面右上的卷轴:玩家的 Mokepon、属性、胜场和道具数量。

在游戏里
右上卷轴里的 “Mokepon: Impike”、HP 等六项属性、“Fights: 0”,以及 Inventory 下三种道具的数量。
它的职责
属性在地图上不会变,所以只写一次;update() 只刷新胜场和道具数。名字用无衬线字体,数字用等宽字体。
谁创建它
COverworldScreen(第 64 行 new PlayerStatsScroll(…))
谁存着它
COverworldScreen 的字段 statsScroll: PlayerStatsScroll
字段 12 个
- static final FONT_SIZE: int
- static final ROW_HEIGHT: int
- static final LABEL_WIDTH: int
- static final SEPARATOR_WIDTH: int
- static final TEXT_X: int
- static final TEXT_Y: int
- final player: Player
- final nameFont: Font
- final numberFont: Font
- final pane: Pane
- final fightsValue: Label
- final itemValues: Map<Item, Label>
方法 5 个
+ PlayerStatsScroll(Player player, double x, double y, double width, double height) · 第 37 行
+ getNode(): Pane · 第 76 行
+ update(): void · 第 81 行
- addRow(GridPane grid, int row, String name, Label value): void · 第 89 行
- createLabel(String text, Font font): Label · 第 94 行
在哪章讲
01 先玩一局:用真实截图认识游戏;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;08 地图世界:走一步发生了什么;10 战斗的数据:Mokepon、Fighter、Battle;13 状态效果和道具;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/PlayerStatsScroll.java(100 行)
看老师打印稿里的这个类(UMLDoclet)
PlayerStatsScroll 的 UML 类图
CSelectScreen

SelectScreen

au.edu.unimelb.swen.oop.mokepon.ui类

选择界面:从列表里挑一只 Mokepon,并查看它的属性。

在游戏里
游戏一打开的界面:左边可滚动的名字列表、灰色圆里的头像、名字和类型图标、属性卷轴、Choose Mokepon 按钮。
它的职责
GameScreen 的子类;覆盖 canReturnToMainMenu 返回 false;没选之前 Choose 按钮不能点。
家族关系
继承 AGameScreen
谁创建它
CGameWindow(第 41 行 new SelectScreen(…))
谁存着它
CGameWindow 的字段 selectScreen: SelectScreen
字段 47 个
- static final PROMPT: String
- static final TITLE_X: int
- static final TITLE_Y: int
- static final TITLE_FONT_SIZE: int
- static final LIST_X: int
- static final LIST_Y: int
- static final LIST_WIDTH: int
- static final LIST_HEIGHT: int
- static final LIST_BUTTON_WIDTH: int
- static final LIST_FONT_SIZE: int
- static final LIST_GAP: int
- static final BUTTON_RADIUS: int
- static final CIRCLE_CENTRE_X: int
- static final CIRCLE_CENTRE_Y: int
- static final CIRCLE_RADIUS: int
- static final PORTRAIT_SIZE: int
- static final CIRCLE_COLOUR: Color
- static final NAME_Y: int
- static final NAME_WIDTH: int
- static final NAME_FONT_SIZE: int
- static final TYPE_ICON_SIZE: int
- static final TYPE_ICON_GAP: int
- static final SCROLL_X: int
- static final SCROLL_Y: int
- static final SCROLL_WIDTH: int
- static final SCROLL_HEIGHT: int
- static final STATS_X: int
- static final STATS_Y: int
- static final LABEL_WIDTH: int
- static final VALUE_WIDTH: int
- static final ROW_HEIGHT: int
- static final STAT_FONT_SIZE: int
- static final CHOOSE_X: int
- static final CHOOSE_Y: int
- static final CHOOSE_SIZE: int
- static final CHOOSE_FONT_SIZE: int
- static final CHOOSE_RADIUS: int
- final images: GameImages
- final portraitView: ImageView
- final nameLabel: Label
- final typeIcon: ImageView
- final statValues: Map<Stat, Label>
- final skillsValue: Label
- final typeValue: Label
- final chooseButton: GameButton
- selectedButton: GameButton
- selectedMokepon: Mokepon
方法 15 个
+ SelectScreen(List<Mokepon> mokepons, GameImages images, GameNavigator navigator) · 第 88 行
+ canReturnToMainMenu(): boolean · 第 120 行
+ clearSelection(): void · 第 125 行
- select(Mokepon mokepon, GameButton button): void · 第 143 行
- showTypeIcon(boolean visible): void · 第 170 行
- formatSkills(Mokepon mokepon): String · 第 175 行
- createTitle(DropShadow outline): Label · 第 183 行
- createPortraitCircle(): Circle · 第 193 行
- createNameRow(): HBox · 第 202 行
- createMokeponList(List<Mokepon> mokepons): ScrollPane · 第 212 行
- createChooseButton(): GameButton · 第 237 行
- createStatsGrid(): GridPane · 第 253 行
- addStatRow(GridPane grid, int row, String name, Label value, int height): void · 第 271 行
- createValueLabel(): Label · 第 280 行
- createRowLabel(String text, Font font): Label · 第 285 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;10 战斗的数据:Mokepon、Fighter、Battle;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/SelectScreen.java(292 行)
看老师打印稿里的这个类(UMLDoclet)
SelectScreen 的 UML 类图
CStatBar

StatBar

au.edu.unimelb.swen.oop.mokepon.ui类

彩色进度条:显示 HP 或能量还剩多少。

在游戏里
战斗界面的绿色 HP 条和蓝色能量条;敌人卷轴上的两条就是普通 StatBar(没有数字)。
它的职责
包装 JavaFX 的 ProgressBar;只要值大于 0,至少显示 3%,免得看不见。是 LabelledStatBar 的父类。
子类 / 实现者
CLabelledStatBar
谁创建它
CFighterPanel(第 56、57 行 new StatBar(…))
谁存着它
CFighterPanel 的字段 hpBar: StatBar、energyBar: StatBar
字段 4 个
# static final WIDTH: int
# static final HEIGHT: int
- static final MIN_VISIBLE_RATIO: double
- final bar: ProgressBar
方法 4 个
+ StatBar(double x, double y, String colour, int current, int max) · 第 18 行
+ update(int current, int max): void · 第 28 行
+ getNodes(): List<Node> · 第 33 行
- calculateRatio(int current, int max): double · 第 37 行
在哪章讲
01 先玩一局:用真实截图认识游戏;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;11 一个回合的完整流程;13 状态效果和道具;14 战斗界面是怎么画出来的;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/StatBar.java(44 行)
看老师打印稿里的这个类(UMLDoclet)
StatBar 的 UML 类图
CUiStyle

UiStyle

au.edu.unimelb.swen.oop.mokepon.ui类

公共样式工具:游戏尺寸、素材文件,以及造标签和图片的静态方法。

在游戏里
它本身看不见,但哥特字体、棕色背景、卷轴图片、标记的着色(白、红、绿感叹号和品红色的门)都经过它。
它的职责
只有 static 常量和方法的工具类(utility class),所有界面共用,样式只写一处。
谁创建它
只有 static 成员,直接用类名调用,不需要 new
谁存着它
没有别的类把它存成字段
字段 8 个
+ static final GAME_WIDTH: int
+ static final GAME_HEIGHT: int
+ static final SCROLL_FILE: String
- static final BACKGROUND_FILE: String
- static final FONT_FILE: String
- static final SANS_SERIF: String
- static final MONOSPACE: String
- static final STRAIGHT_DOWN: double
方法 11 个
+ loadGameFont(int size): Font · 第 29 行
+ createSansSerifFont(FontWeight weight, int size): Font · 第 33 行
+ createMonospaceFont(FontWeight weight, int size): Font · 第 37 行
+ loadImage(String path): Image · 第 42 行
+ createImageView(Image image, double x, double y, double width, double height): ImageView · 第 47 行
+ createIcon(Image image, double size): ImageView · 第 58 行
+ createBackground(): ImageView · 第 66 行
+ tint(ImageView imageView, String colour): void · 第 74 行
+ createWhiteOutline(): DropShadow · 第 83 行
+ createCenteredLabel(String text, Font font, double x, double y, double width): Label · 第 92 行
+ createLabel(String text, Font font): Label · 第 105 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;14 战斗界面是怎么画出来的;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
ui/UiStyle.java(112 行)
看老师打印稿里的这个类(UMLDoclet)
UiStyle 的 UML 类图
EDirection

Direction

au.edu.unimelb.swen.oop.mokepon.world枚举

枚举:上下左右四个移动方向,各带 x、y 的变化量。

在游戏里
地图界面右下的四个箭头按钮和键盘方向键,各对应一个 Direction。
它的职责
y 向下增大,所以 UP 是 (0, -1);Position.move(direction) 用它算出新的坐标。
谁创建它
枚举的几个值在类加载时就自动建好了,不用 new
谁存着它
CGameImages 的字段 buttonImages: Map<Direction, String>;COverworldScreen 的字段 moveButtons: Map<Direction, GameButton>
枚举值
UP、DOWN、LEFT、RIGHT
字段 2 个
- final xChange: int
- final yChange: int
方法 3 个
~ Direction(int xChange, int yChange) · 第 13 行
+ getXChange(): int · 第 18 行
+ getYChange(): int · 第 22 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;08 地图世界:走一步发生了什么;17 考试准备:用这份代码答题
源文件
world/Direction.java(26 行)
看老师打印稿里的这个类(UMLDoclet)
Direction 的 UML 类图
CEncounter

Encounter

au.edu.unimelb.swen.oop.mokepon.world类

一次遇敌:哪个标记、玩家的 Mokepon、敌人和脚下的地形。

在游戏里
遇敌对话框的标题 “Encountered a Hexwing” 里的敌人和下面两句地形提示,都来自 Encounter。
它的职责
getTerrainMessages 生成地形提示;createBattle 按地形效果造出两个 Fighter,再造出 Battle。
谁创建它
COverworld(第 106 行 new Encounter(…))
谁存着它
COverworld 的字段 encounter: Encounter
字段 4 个
- final marker: Marker
- final playerMokepon: Mokepon
- final enemy: Mokepon
- final terrain: Terrain
方法 8 个
+ Encounter(Marker marker, Mokepon playerMokepon, Mokepon enemy, Terrain terrain) · 第 21 行
+ getMarker(): Marker · 第 28 行
+ getEnemy(): Mokepon · 第 32 行
- getPlayerEffect(): TerrainEffect · 第 36 行
- getEnemyEffect(): TerrainEffect · 第 40 行
+ getTerrainMessages(): List<String> · 第 45 行
+ createBattle(Inventory inventory): Battle · 第 53 行
- addTerrainMessage(List<String> messages, String who, TerrainEffect effect): void · 第 59 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;06 窗口、界面切换和菜单;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;11 一个回合的完整流程;13 状态效果和道具;14 战斗界面是怎么画出来的;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/Encounter.java(65 行)
看老师打印稿里的这个类(UMLDoclet)
Encounter 的 UML 类图
IEnemyPicker

EnemyPicker

au.edu.unimelb.swen.oop.mokepon.world接口

接口:决定在某个标记上遇到哪只 Mokepon。

在游戏里
看不见:踩上感叹号时在 Overworld.startEncounter 里运行,结果就是对话框 “Encountered a ...” 里的名字。
它的职责
Strategy 模式的接口;随机、强、弱三种标记只是用的 picker 不同,Marker 的代码完全一样。
子类 / 实现者
CRandomEnemyPicker CTerrainEnemyPicker
谁创建它
接口不能被 new,只能 new 它的实现类
谁存着它
CMarker 的字段 picker: EnemyPicker
方法 1 个
+ pick(List<Mokepon> mokepons, Terrain terrain, Random random): Mokepon · 第 12 行
在哪章讲
03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;09 遇敌:地形、类型和挑敌人;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/EnemyPicker.java(14 行)
看老师打印稿里的这个类(UMLDoclet)
EnemyPicker 的 UML 类图
CExit

Exit

au.edu.unimelb.swen.oop.mokepon.world类

出口门:踩上去游戏就结束。

在游戏里
地图最上面 (6,0) 的品红色门;踩上去弹出 “You finished the game! You won 1 fights!”。
它的职责
MapObject 的子类,interact() 只调用 world.reachExit();结束对话框由 OverworldScreen 弹出。
家族关系
继承 AMapObject
谁创建它
CMapParser(第 83 行 new Exit(…))
谁存着它
没有别的类把它存成字段
方法 2 个
+ Exit(Position position, Sprite sprite) · 第 6 行
~ interact(Overworld world): void · 第 11 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/Exit.java(15 行)
看老师打印稿里的这个类(UMLDoclet)
Exit 的 UML 类图
CGameMap

GameMap

au.edu.unimelb.swen.oop.mokepon.world类

数据文件里的地图:每格的地形、玩家起点和开局时的物体。

在游戏里
地图 20×20 的格子布局,和开局时的标记、箱子、门;玩家从 (10,18) 出发。
它的职责
游戏中不会变:构造时逐行拷贝数组、用 List.copyOf 拷贝物体,防止隐私泄露(privacy leak);isWalkable 判断能否走。
谁创建它
CMapParser(第 39 行 new GameMap(…))
谁存着它
CGameWindow 的字段 map: GameMap;COverworld 的字段 map: GameMap
字段 3 个
- final tiles: Terrain[][]
- final startPosition: Position
- final objects: List<MapObject>
方法 8 个
+ GameMap(Terrain[][] tiles, Position startPosition, List<MapObject> objects) · 第 15 行
+ getWidth(): int · 第 26 行
+ getHeight(): int · 第 30 行
+ getStartPosition(): Position · 第 34 行
+ getObjects(): List<MapObject> · 第 38 行
+ getTerrain(Position position): Terrain · 第 42 行
+ isWalkable(Position position): boolean · 第 47 行
- isInside(Position position): boolean · 第 51 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;06 窗口、界面切换和菜单;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/GameMap.java(56 行)
看老师打印稿里的这个类(UMLDoclet)
GameMap 的 UML 类图
AMapObject

MapObject

au.edu.unimelb.swen.oop.mokepon.world抽象类

抽象类:放在地图某一格上、玩家踩上去会有反应的东西。

在游戏里
地图上的感叹号、问号箱子和门都是它的子类对象;样子由各自的 Sprite 决定。
它的职责
抽象方法 interact(Overworld) 让每种物体自己决定做什么;Overworld 一视同仁地调用,不用 instanceof(多态)。
子类 / 实现者
CExit CMarker CMysteryBox
谁创建它
抽象类不能直接 new,只能 new 它的子类
谁存着它
CMapView 的字段 objectViews: Map<MapObject, ImageView>;CGameMap 的字段 objects: List<MapObject>;COverworld 的字段 objects: List<MapObject>
字段 2 个
- final position: Position
- final sprite: Sprite
方法 5 个
# MapObject(Position position, Sprite sprite) · 第 10 行
+ getPosition(): Position · 第 15 行
+ getSprite(): Sprite · 第 19 行
+ isAt(Position other): boolean · 第 23 行
~ interact(Overworld world): void · 第 30 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;13 状态效果和道具;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/MapObject.java(32 行)
看老师打印稿里的这个类(UMLDoclet)
MapObject 的 UML 类图
CMarker

Marker

au.edu.unimelb.swen.oop.mokepon.world类

Mokepon 标记(感叹号):踩上去遇到一只野生 Mokepon。

在游戏里
地图上的感叹号:白色是随机,红色是强(敌人占优势),绿色是弱(敌人占劣势)。
它的职责
MapObject 的子类,持有一个 EnemyPicker;interact() 调用 world.startEncounter(this)。
家族关系
继承 AMapObject
谁创建它
CMapParser(第 63 行 new Marker(…))
谁存着它
CEncounter 的字段 marker: Marker
字段 1 个
- final picker: EnemyPicker
方法 3 个
+ Marker(Position position, Sprite sprite, EnemyPicker picker) · 第 14 行
~ chooseEnemy(List<Mokepon> mokepons, Terrain terrain, Random random): Mokepon · 第 20 行
~ interact(Overworld world): void · 第 25 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/Marker.java(29 行)
看老师打印稿里的这个类(UMLDoclet)
Marker 的 UML 类图
CMysteryBox

MysteryBox

au.edu.unimelb.swen.oop.mokepon.world类

神秘箱子(问号):里面有一个道具,踩上去就捡到。

在游戏里
地图上的白色问号;捡到后问号消失,状态栏显示 “You picked up a Poison!”,卷轴里的数量加 1。
它的职责
MapObject 的子类,持有一个 Item;interact() 调用 world.collect(this),由 Overworld 移走它。
家族关系
继承 AMapObject
谁创建它
CMapParser(第 76 行 new MysteryBox(…))
谁存着它
没有别的类把它存成字段
字段 1 个
- final item: Item
方法 3 个
+ MysteryBox(Position position, Sprite sprite, Item item) · 第 9 行
+ getItem(): Item · 第 14 行
~ interact(Overworld world): void · 第 19 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;13 状态效果和道具;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/MysteryBox.java(23 行)
看老师打印稿里的这个类(UMLDoclet)
MysteryBox 的 UML 类图
COverworld

Overworld

au.edu.unimelb.swen.oop.mokepon.world类

一局地图上的游戏:玩家、还剩下的物体和移动规则。

在游戏里
看不见:玩家每走一步、捡箱子、遇敌、到出口,都是它先改数据,再通知界面去画。
它的职责
Observer 模式的被观察者(subject):保存 listeners,用 notifyListeners 加 lambda 通知,不认识界面。
谁创建它
CGameWindow(第 59 行 new Overworld(…))
谁存着它
CGameWindow 的字段 world: Overworld;CMapView 的字段 world: Overworld;COverworldScreen 的字段 world: Overworld
字段 7 个
- final map: GameMap
- final mokepons: List<Mokepon>
- final player: Player
- final objects: List<MapObject>
- final listeners: List<OverworldListener>
- final random: Random
- encounter: Encounter
方法 15 个
+ Overworld(GameMap map, List<Mokepon> mokepons, Mokepon playerChoice) · 第 29 行
+ Overworld(GameMap map, List<Mokepon> mokepons, Mokepon playerChoice, Random random) · 第 34 行
+ addListener(OverworldListener listener): void · 第 44 行
+ getMap(): GameMap · 第 48 行
+ getPlayer(): Player · 第 52 行
+ getObjects(): List<MapObject> · 第 57 行
+ canMove(Direction direction): boolean · 第 61 行
+ move(Direction direction): void · 第 66 行
+ createBattle(): Battle · 第 82 行
+ runAway(): void · 第 87 行
+ winEncounter(): void · 第 94 行
~ startEncounter(Marker marker): void · 第 103 行
~ collect(MysteryBox box): void · 第 111 行
~ reachExit(): void · 第 118 行
- notifyListeners(Consumer<OverworldListener> message): void · 第 125 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;06 窗口、界面切换和菜单;07 选择界面 SelectScreen;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;13 状态效果和道具;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/Overworld.java(131 行)
看老师打印稿里的这个类(UMLDoclet)
Overworld 的 UML 类图
IOverworldListener

OverworldListener

au.edu.unimelb.swen.oop.mokepon.world接口

接口:地图上会发生的五件事(移动、遇敌、捡道具、打赢、到出口)。

在游戏里
看不见:OverworldScreen 实现它;比如 onItemCollected 被调用时,状态栏才写出 “You picked up a ...!”。
它的职责
Observer 模式的观察者接口;Overworld 只调用这些方法,不知道它们具体做什么。
子类 / 实现者
COverworldScreen
谁创建它
接口不能被 new,只能 new 它的实现类
谁存着它
COverworld 的字段 listeners: List<OverworldListener>
方法 5 个
+ onPlayerMoved(): void · 第 12 行
+ onEncounter(Encounter encounter): void · 第 15 行
+ onItemCollected(Item item): void · 第 18 行
+ onEncounterWon(Mokepon enemy): void · 第 21 行
+ onExitReached(int fightsWon): void · 第 24 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/OverworldListener.java(26 行)
看老师打印稿里的这个类(UMLDoclet)
OverworldListener 的 UML 类图
CPlayer

Player

au.edu.unimelb.swen.oop.mokepon.world类

玩家:他的 Mokepon、位置、上一个位置、背包和胜场。

在游戏里
地图上玩家图标(白色光芒)所在的格子,和卷轴里 “Fights:” 的数字,读的都是 Player。
它的职责
moveTo、moveBack、addWin 是包内可见(package-private),只有 world 包里的 Overworld 能改它。
谁创建它
COverworld(第 39 行 new Player(…))
谁存着它
CPlayerStatsScroll 的字段 player: Player;COverworld 的字段 player: Player
字段 5 个
- final mokepon: Mokepon
- final inventory: Inventory
- position: Position
- previousPosition: Position
- fightsWon: int
方法 8 个
+ Player(Mokepon mokepon, Position startPosition, Inventory inventory) · 第 17 行
+ getMokepon(): Mokepon · 第 24 行
+ getInventory(): Inventory · 第 28 行
+ getPosition(): Position · 第 32 行
+ getFightsWon(): int · 第 36 行
~ moveTo(Position newPosition): void · 第 40 行
~ moveBack(): void · 第 46 行
~ addWin(): void · 第 50 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;06 窗口、界面切换和菜单;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;13 状态效果和道具;15 逃跑、回主菜单、走到出口;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/Player.java(54 行)
看老师打印稿里的这个类(UMLDoclet)
Player 的 UML 类图
CPosition

Position

au.edu.unimelb.swen.oop.mokepon.world类

地图上的一格:x 是列,y 是行,(0,0) 在左上角。

在游戏里
看不见:玩家和每个物体的位置,如起点 (10,18);MapView 把 x、y 乘以 32 换成像素位置。
它的职责
不可变(immutable):move() 返回新对象;覆盖 equals 和 hashCode,坐标相同就算相等,isAt 靠它判断。
谁创建它
CGameData(第 31 行 new Position(…));CMapView(第 65 行 new Position(…))
谁存着它
CGameMap 的字段 startPosition: Position;AMapObject 的字段 position: Position;CPlayer 的字段 position: Position、previousPosition: Position
字段 2 个
- final x: int
- final y: int
方法 6 个
+ Position(int x, int y) · 第 12 行
+ getX(): int · 第 17 行
+ getY(): int · 第 21 行
+ move(Direction direction): Position · 第 26 行
+ equals(Object other): boolean · 第 32 行
+ hashCode(): int · 第 45 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;15 逃跑、回主菜单、走到出口;17 考试准备:用这份代码答题
源文件
world/Position.java(49 行)
看老师打印稿里的这个类(UMLDoclet)
Position 的 UML 类图
CRandomEnemyPicker

RandomEnemyPicker

au.edu.unimelb.swen.oop.mokepon.world类

EnemyPicker 的实现:从全部 Mokepon 里随便挑一只,不管地形。

在游戏里
白色感叹号用它:踩上去遇到的敌人完全随机。
它的职责
Strategy 模式的具体策略;MapParser 把它交给 map.mokeponRandom 这一组标记。
家族关系
实现 IEnemyPicker
谁创建它
CMapParser(第 31 行 new RandomEnemyPicker(…))
谁存着它
没有别的类把它存成字段
方法 1 个
+ pick(List<Mokepon> mokepons, Terrain terrain, Random random): Mokepon · 第 12 行
在哪章讲
01 先玩一局:用真实截图认识游戏;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;09 遇敌:地形、类型和挑敌人;10 战斗的数据:Mokepon、Fighter、Battle;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/RandomEnemyPicker.java(16 行)
看老师打印稿里的这个类(UMLDoclet)
RandomEnemyPicker 的 UML 类图
CSprite

Sprite

au.edu.unimelb.swen.oop.mokepon.world类

地图物体的外观:图片路径和着色用的颜色字符串。

在游戏里
感叹号的白、红、绿和门的品红色就是 Sprite 的 colour;问号箱子没有颜色,按原图显示。
它的职责
只存字符串,没有 JavaFX 代码,让 world 包保持独立;真正的着色由 MapView 调用 UiStyle.tint 完成。
谁创建它
CMapParser(第 58、70、82 行 new Sprite(…))
谁存着它
AMapObject 的字段 sprite: Sprite
字段 3 个
- static final NO_TINT: String
- final imagePath: String
- final colour: String
方法 5 个
+ Sprite(String imagePath) · 第 15 行
+ Sprite(String imagePath, String colour) · 第 19 行
+ getImagePath(): String · 第 24 行
+ getColour(): String · 第 28 行
+ hasTint(): boolean · 第 32 行
在哪章讲
02 Java 最小知识包;03 读懂老师打印的 UML;04 项目地图:9 个包、72 个类;05 程序是怎么跑起来的;08 地图世界:走一步发生了什么;09 遇敌:地形、类型和挑敌人;13 状态效果和道具;17 考试准备:用这份代码答题
源文件
world/Sprite.java(36 行)
看老师打印稿里的这个类(UMLDoclet)
Sprite 的 UML 类图
CTerrainEnemyPicker

TerrainEnemyPicker

au.edu.unimelb.swen.oop.mokepon.world类

EnemyPicker 的实现:挑一只类型在这块地形上有指定效果的 Mokepon。

在游戏里
红色感叹号(要 ADVANTAGE)和绿色感叹号(要 DISADVANTAGE)用它;如在森林里遇到占劣势的 Hexwing。
它的职责
Strategy 模式的具体策略,构造时传入想要的 TerrainEffect;一只都不符合时,就从全部 Mokepon 里挑。
家族关系
实现 IEnemyPicker
谁创建它
CMapParser(第 33、35 行 new TerrainEnemyPicker(…))
谁存着它
没有别的类把它存成字段
字段 1 个
- final wantedEffect: TerrainEffect
方法 2 个
+ TerrainEnemyPicker(TerrainEffect wantedEffect) · 第 16 行
+ pick(List<Mokepon> mokepons, Terrain terrain, Random random): Mokepon · 第 21 行
在哪章讲
01 先玩一局:用真实截图认识游戏;02 Java 最小知识包;04 项目地图:9 个包、72 个类;09 遇敌:地形、类型和挑敌人;16 设计模式和 OOP 原则;17 考试准备:用这份代码答题
源文件
world/TerrainEnemyPicker.java(36 行)
看老师打印稿里的这个类(UMLDoclet)
TerrainEnemyPicker 的 UML 类图