编辑1:我正在使用一些有用的答案来处理解决方案,我会在我开始工作后立即更新帖子。
我正在用C ++中的几个同学为我的成绩最后一个项目制作视频游戏(我已经学习了6个月左右的语言)并且我们正在清理代码。
视频游戏是 RTS (实时策略),和其他人一样,我们有一堆单位,它们的行为方式相同,但它们有很多属性。实际上我们的构造函数代码(对于单位)看起来像(准备好大量的垃圾代码):
Unit::Unit(SceneNode *layer, int32_t id, Enumeration::UnitType type){
switch (type) {
// Basic melee soldier
case Enumeration::UnitType::StandardM:
moveSpeed = 420;
attackDamage = 15;
attackRange = 100;
attackSpeed = 1;
viewRadius = 450;
maxHP = 80;
currentHP = 80;
recruitingTime = 5;
happiness = -10;
citizens = -10;
armyLevel = Enumeration::ArmyLevel::Footmen;
attackEvent = "event:/UnitAttack/Drorania_melee_S";
moveEvent = "event:/UnitMovement/Drorania_melee_S";
selectEvent = "event:/UnitSelect/Drorania_melee_S";
metalCost = Enumeration::UnitCost::MeleeFootmenMetalCost;
crystalCost = Enumeration::UnitCost::MeleeFootmenCrystalCost;
path = L"media/unitModels/Drorania/Melee_Soldier_Drorania.obj";
setModel(layer, path);
troops = new Troop(layer, path, 4, ID);
//tex = new Texture("./media/textures/Drorania/Unit/drorania_melee_soldier.jpg");
break;
//Advanced melee soldier (mounted)
case Enumeration::UnitType::AdvancedM:
if (breed == Enumeration::BreedType::Drorania) {
moveSpeed = 530;
attackDamage = 21;
attackRange = 140;
attackSpeed = 1;
viewRadius = 450;
maxHP = 140;
currentHP = 140;
recruitingTime = 10;
happiness = -10;
citizens = -10;
armyLevel = Enumeration::ArmyLevel::Mounted;
attackEvent = "event:/UnitAttack/Drorania_melee_A";
moveEvent = "event:/UnitMovement/Drorania_melee_A";
selectEvent = "event:/UnitSelect/Drorania_melee_A";
metalCost = Enumeration::UnitCost::MountedMeleeMetalCost;
crystalCost = Enumeration::UnitCost::MountedMeleeCrystalCost;
path = L"media/unitModels/Drorania/criatura_drorania.obj";
//tex = new Texture("./media/textures/Drorania/Unit/drorania_criature.jpg");
setModel(layer, path);
//troops = new Troop(layer, path, 4, ID);
}
break;
/* More code*/
}
}
我确定有很多更好的方法来处理这些案件,但我并不深入研究语言功能(我的不好)。我很乐意清理代码的方式是初始化而不是使用枚举进行分配,但我还需要使用' .ob&分配 strings #39; 路径以加载模型,这就是为什么我认为枚举不是最好的情况。你们的想法是什么?
PS:对不起,如果我犯了很多英语错误。
PS2:我省略了很多代码,因为他们没有服务于问题目的。
PS3:我无法找到自己的其他人回答问题对我的案例有用,但也许我错过了一些商品。答案 0 :(得分:2)
这里可以使用一些模式,例如工厂模式以及Unit
子类的多态层次结构,但这对于减少显示的代码没有太大作用(内部可能看起来非常事实上相似)。
相反,我建议将所有这些数据放在单独的数据文件中,而不是代码中。然后,您只需要一种方法将数据加载到Unit
。如果有一些难以在数据文件中编码的单位类型知识,您仍然可以遵循类层次结构的想法。例如,可能有一个继承自UnitWithTroops
的{{1}}类知道如何读取有关部队的数据。这需要多长时间取决于您的单位系统的(当前和未来)复杂性。
答案 1 :(得分:2)
定义文件格式,例如INI样式:
[StandardM]
moveSpeed = 420
attackDamage = 15
attackRange = 100
attackSpeed = 1
viewRadius = 450
maxHP = 80
currentHP = 80
recruitingTime = 5
happiness = -10
citizens = -10
armyLevel = Enumeration::ArmyLevel::Footmen;
attackEvent = event:/UnitAttack/Drorania_melee_S
moveEvent = event:/UnitMovement/Drorania_melee_S
selectEvent = event:/UnitSelect/Drorania_melee_S
metalCost = Enumeration::UnitCost::MeleeFootmenMetalCost
crystalCost = Enumeration::UnitCost::MeleeFootmenCrystalCost
path = media/unitModels/Drorania/Melee_Soldier_Drorania.obj
[Drorania]
moveSpeed = 530
etc...
解析此文件并构建您的单元。你会在这里保存很多代码。
答案 2 :(得分:0)
有用的经验法则是避免混合数据和逻辑。这听起来像是反OO的立场,但这根本不是我的意思。
考虑
UnitPrototype const *proto = lookup(type, breed);
// code using proto->speed,HP,path etc.
proto->setModel(layer);
现在游戏逻辑使用所有这些参数完全独立于所有硬编码值,因此单元构造函数更具可读性。
我只是handwaved存在的lookup
函数仍然可以硬编码大量的魔术值(尽管这很难看),或者它可以使用声明式样式(仍然是硬编码但不与过程代码交错),或构建映射从启动时的配置文件 - 重点是它不再重要。您可以独立担心两个完全不同的问题。
NB。这里的部分技巧是看到一个" Unit"是两个的东西(然后将它们分开)。
有一个单元的原型,可能永远不会改变,并且是第一次创建时该单元的实例出现的方式。
然后是一个特定的单位实例,其HP和其他属性会随着时间而变化。
如果你的单位区分他们的统计数据和其他属性,而不是通过不同的逻辑,继承可能不是一个很好的模型。