271
社区成员
发帖
与我相关
我的任务
分享Adventurer(冒险者)
系统的核心实体类,是整个系统的中心。
主要属性:
id、hitPoint、baseatk、basedef、mana、moneyMap<String, Bottle> bottles、Map<String, Equipment> equipments、Map<String, Spell> spellsLinkedHashSet<String> bottleBackpack(最多10个,FIFO)、carriedWeapon、carriedArmourSet<String> employees、String employer核心方法:
addBottle()、addEquipment()、addSpell()、removeItem()、takeItem()getAtk()(基础攻击+武器)、getDef()(基础防御+护甲)isDead()、isCarrying()hireEmployee()、isBoss()(递归查找上级)、isAlly()(判断盟友)getAllSubordinates()(递归获取所有下属)Equipment(装备)
装备基类,采用三层继承结构。
继承体系:
Equipment
├── Weapon(武器)
│ ├── Sword(剑)
│ └── Magicbook(魔法书)
└── Armour(护甲)
属性:id、ce(战斗力)
设计考虑:Weapon作为中间层便于统一管理武器,与Armour区分开来。
Bottle(药水)
药水基类,四种子类对应不同效果。
子类:
HpBottle:恢复生命值AtkBottle:永久增加基础攻击力DefBottle:永久增加基础防御力ManaBottle:恢复魔法值属性:id、effect
特点:使用后自动从背包移除。
Spell(法术)
法术基类,两种子类实现不同功能。
子类:
HealSpell:治疗法术,为盟友恢复生命值AttackSpell:攻击法术,对敌人造成伤害属性:id、manaCost(魔法消耗)、power(威力)
使用规则:
Factory(工厂类)
集中管理所有对象的创建,实现工厂设计模式。
方法:
createBottle(String type, String id, int effect):创建药水对象createSpell(String type, String id, int cost, int power):创建法术对象createEquipment(String type, String id, int ce):创建装备对象设计目的:
Lexer(词法分析器)
用于解析输入命令,将字符串分解为token序列。
核心功能:
(、)、,)接口:
peek():查看当前tokennext():移动到下一个tokenParser(语法分析器)
使用递归下降法解析复杂的冒险者雇佣关系。
解析文法:
冒险者 → 标识符 [被雇佣者]
被雇佣者 → '(' 冒险者序列 ')'
冒险者序列 → 冒险者 {',' 冒险者}
示例:A(B(C,D),E(F)) 表示 A雇佣B和E,B雇佣C和D,E雇佣F
设计亮点:采用编译原理中的递归下降算法,优雅处理嵌套结构。
Main
程序入口,负责读取输入、初始化数据结构,并调用相关方法处理命令。
核心职责:
Map<String, Adventurer> adventurers主要方法:
addAdventurer():添加冒险者addBottle()、addEquipment()、learnSpell():添加物品useItem():使用物品或法术fight():处理战斗addRelation()、removeRelation()、loadRelation():管理雇佣关系checkAndTriggerHelp():检查并触发援助实现内容
AdventurerBottleEquipment核心设计
数据结构选择:
// 全局管理所有冒险者
private static Map<String, Adventurer> adventurers = new HashMap<>();
// 冒险者内部管理物品
public class Adventurer {
private Map<String, Bottle> bottles;
private Map<String, Equipment> equipments;
}
为什么使用Map?
基础命令实现:
aa advId:添加冒险者ab advId bottleId type effect:添加药水ae advId equipmentId type ce:添加装备架构特点:
实现内容
Spell继承体系建立
Bottle子类化:
class HpBottle extends Bottle { }
class AtkBottle extends Bottle { }
class DefBottle extends Bottle { }
class ManaBottle extends Bottle { }
Spell类设计:
public class Spell {
private String id;
private int manaCost;
private int power;
}
class HealSpell extends Spell { }
class AttackSpell extends Spell { }
Adventurer属性扩展:
private int hitPoint = 500;
private int baseatk = 1;
private int basedef = 0;
private int mana = 10;
private Map<String, Spell> spells;
使用物品功能:
use advId usableId targetId:使用药水或法术架构改进:
实现内容
装备继承体系
Equipment(基类)
├── Weapon(武器,中间层)
│ ├── Sword(剑)
│ └── Magicbook(魔法书)
└── Armour(护甲)
设计考虑:
getAtk()和getDef()计算总战斗力携带装备机制:
private Weapon carriedWeapon;
private Armour carriedArmour;
public int getAtk() {
if (carriedWeapon == null) {
return baseatk;
} else {
return carriedWeapon.getCe() + baseatk;
}
}
战斗系统实现:
命令格式:fight advId k targetId1 targetId2 ... targetIdk
战斗逻辑:
sqrt(ce)点魔法值,伤害=攻击力(无视防御)金钱系统:
private int money = 50; // 初始金钱
// bi命令:购买物品
private static void buyItem(String advId, String itemId, String type) {
int cost = getCost(type);
if (adventurer.getMoney() >= cost) {
adventurer.setMoney(adventurer.getMoney() - cost);
// 创建并添加物品
}
}
架构改进:
实现内容
雇佣关系数据结构
private Set<String> employees; // 雇员集合
private String employer; // 雇主
为什么用Set?
关系查询算法:
判断是否为上级(递归向上):
public boolean isBoss(String targetId, Map<String, Adventurer> allAdventurers) {
if (this.employer == null) return false;
if (this.employer.equals(targetId)) return true;
Adventurer boss = allAdventurers.get(this.employer);
if (boss != null && !boss.isDead()) {
return boss.isBoss(targetId, allAdventurers); // 递归
}
return false;
}
判断是否为盟友:
public boolean isAlly(String targetId, Map<String, Adventurer> allAdventurers) {
if (this.id.equals(targetId)) return true; // 自己
if (isBoss(targetId, allAdventurers)) return true; // 上级
return isSubordinate(targetId, allAdventurers); // 下属
}
关系检查:
援助系统实现:
触发条件:生命值降至原来的一半以下
援助逻辑:
private static void checkAndTriggerHelp(Adventurer target, int oldHp) {
int newHp = target.getHitPoint();
if (newHp > 0 && newHp <= oldHp / 2) {
// 获取所有下属(递归)
List<Adventurer> subordinates = target.getAllSubordinates(adventurers);
int helpCount = 0;
for (Adventurer helper : subordinates) {
if (tryHelp(helper, target)) {
helpCount++;
}
}
if (helpCount > 0) {
System.out.println(target.getId() + " is helped by " + helpCount +
" adventurer(s), now Hp is " + target.getHitPoint());
}
}
}
选择最优法术:
架构改进:
实现内容
利用递归下降法导入复杂冒险者关系
命令格式
lr A(B(C,D),E(F))
含义:
Lexer + Parser设计
词法分析(Lexer):
将输入字符串分解为token序列:
输入:A(B(C,D),E(F))
Token序列:A ( B ( C , D ) , E ( F ) )
实现要点:
peek()和next()接口语法分析(Parser):
文法定义:
冒险者 → 标识符 [被雇佣者]
被雇佣者 → '(' 冒险者序列 ')'
冒险者序列 → 冒险者 {',' 冒险者}
递归下降实现:
private void parseAdventurer() {
String adventurerId = lexer.peek();
lexer.next();
if (lexer.peek() != null && lexer.peek().equals("(")) {
parseEmployees(adventurerId); // 递归处理雇员
}
}
private void parseEmployees(String employerId) {
if (!lexer.peek().equals("(")) {
throw new RuntimeException("Expected '('");
}
lexer.next();
parseAdventurerList(employerId); // 递归解析雇员列表
if (!lexer.peek().equals(")")) {
throw new RuntimeException("Expected ')'");
}
lexer.next();
}
架构完善:
在知道OOPre的迭代作业是编一个类似于rpg的程序,我就非常感兴趣,因为从小到大挺喜欢打游戏,mc,tr,LOL,二游,博德之门3,艾尔登法环等等大小游戏,还不少做将来进游戏大厂编游戏的梦,所以看到作业是做一个“游戏”,非常的感兴趣,但是毕竟从前没有面向对象编程的经历,所以第二次作业很懵逼,因为一下子难度飙升,第一次只是debug,但第二次就直接是一个独立的程序了,而且需要的内容还不少,确实困难很大,毕竟之前都是面向过程编程,不知道该怎么办,从哪里起手,遂问了问s7h学长,说是要先想好都设置哪些类,每个类起什么作用,怎么交互,再写代码,有点似懂非懂,但好歹是有了个大方向,做的过程中也在问起了编程中遇到的具体问题,助教们都非常非常耐心!在这十分感谢所有的助教!随着药水,法术,战斗,雇佣,支援的引入,真的真的很有成就感,仿佛自己做了一个自己的八方旅人,做了一个自己的博德之门3,做出了一个真正的东西,真的很喜欢这样的作业,不过可能是自己能力问题?感觉一次迭代内容好多啊,一周的时间真的好仓促,希望之后能迭代速度慢一点。
建议:
1:迭代速度能放缓一些嘛?感觉进度好赶啊(也有可能是自己菜菜的
感谢OOPre课程组的老师和助教,通过精心设计的迭代作业,让我们在实践中真正理解了面向对象的精髓!做出了属于自己的博德之门3!
文章首发于CSDN
如有问题或建议,欢迎在评论区交流讨论!
如果这篇文章对你有帮助,请点赞支持 👍