我正在编写一个游戏作为练习,我遇到了一个设计问题。我的角色扮演游戏将有典型的类,如战士,向导,Theif,牧师。我如何设计我的课程以便玩家可以多班?例如,一个玩家可能从战斗机开始(并获得相关技能的战士),然后多级到一个巫师(此时他们获得巫师法术),后来又多了一个级别又一个流氓(现在获得所有能力的流氓有)。所以这个玩家现在是战斗机向导 - 盗贼。我不知道在C#中代表这个。
起初我尝试使用装饰器模式但是我不能多次多次使用它。关于如何设计这个的任何指针?
我唯一能想到的就是为每个角色拥有IList<CharacterBaseClass>
属性,并将Fighter,Wizard,Rogue等添加到玩家多类中。这样的事情......
class CharacterBaseClass
{
public IList<CharacterBaseClass> MultiClasses { get; set; }
// constructors, etc
}
每次他们多次加入IList
// player starts off as Fighter
Warrior player1 = new Warrior();
// now multi-class to Wizard
player1.MultiClasses.Add(new Wizard());
// now multi-class to Theif
player1.MultiClasses.Add(new Theif());
我确定必须有比这更好的方法吗?
答案 0 :(得分:7)
仅仅因为你的角色是巫师和战士,这并不意味着你必须为他们创建子类。相反,问问自己,“在代码级别,角色的课程做什么?”可能,你根本不想要为字符类设置C#子类。相反,弄清楚类实际做了什么,然后确定在代码中对其进行建模的正确方法。
例如,如果字符类限制了角色可以使用的设备,那么您可以为AllowedEquipment
定义一个类:
public class AllowedEquipment
{
public static AllowedEquiment Warrior()
{
return new AllowedEquipment() {
Daggers = true;
Swords = true;
Shields = true;
Armor = true
};
}
public static AllowedEquiment Wizard()
{
return new AllowedEquipment() {
Daggers = true;
Swords = false;
Shields = false;
Armor = true
};
}
public bool Daggers { get; set; }
public bool Swords { get; set; }
public bool Shields { get; set; }
public bool Armor { get; set; }
}
不要觉得你需要使用子类来模拟游戏中的每个“is-a”关系。
另一个选择是使用Type Object模式为角色类建模。如果你这样做,那么很容易为每个角色提供一组Type Object实例而不是单个实例,这实际上为你提供了多重继承。
答案 1 :(得分:3)
使用装饰器模式,可能可能会这样做。
Character person = new Character("Rambo");
person = new Fighter(person); // decorate him with Fighter skills
person = new Thief(person); // also decorate him with Thief skills
就个人而言,我可能会考虑将字符附加到字符中:
Character person = new Character("Rambo");
person.AttachClass(new Fighter());
person.AttachClass(new Thief());
当然,如果你需要在课程之间进行复杂的互动,那么战斗机/小偷不仅可以从每个人那里获得奖金和技能,而且还可以获得更多的东西,也许唯一正确的途径就是创造所有组合的特定多类:
Character person = new Character("Rambo");
person.AttachClass(new FighterThief());
这当然会爆炸所有组合。
纯表驱动的努力怎么样?
将所有适用的技能,法术,奖励,效果等放在一张大表中,然后通过将特定类链接到该表中的特定项来定义类。这样,通过链接不同的基类来创建混合类会更加简单。
要使用装饰器模式并仍然可以正确访问所有内容,每个类(在编程意义上的单词)需要作为装饰器类正确实现。
例如:
public class BaseClass
{
protected BaseClass(BaseClass underlyingCharacterClass);
public abstract bool CanCastSpells();
public abstract List<Spell> GetAvailableSpells();
protected BaseClass UnderlyingCharacterClass;
}
public class Wizard : BaseClass
{
public override bool CanCastSpells() { return true; }
public override List<Spell> GetAvailableSpells()
{
List<Spell> result = new List<Spell>();
if (UnderlyingCharacterClass != null)
result.AddRange(UnderlyingCharacterClass.GetAvailableSpells());
result.Add(new WizardSpell1());
...
return result;
}
}
public class Thief : BaseClass
{
public override bool CanCastSpells()
{
if (UnderlyingCharacterClass != null)
return UnderlyingCharacterClass.CanCastSpells();
return false;
}
public override List<Spell> GetAvailableSpells()
{
List<Spell> result = new List<Spell>();
if (UnderlyingCharacterClass != null)
result.AddRange(UnderlyingCharacterClass.GetAvailableSpells());
return result;
}
}
答案 2 :(得分:1)
如果类有一些公共接口或基类,那么multiclass是附加类(MultiClass),它也实现了这个接口或基类,然后委托给它包含的实例。
例如:
public class MultiClass : Class {
...
public MultiClass(params Class[] classes) {
this.classes = classes;
}
public IEnumerable<Ability> GetAbilities() {
return this.classes.SelectMany(с => c.GetAbilities());
}
...
}
如果要添加更多类,可以将AddClass方法添加到基类,这将从单个类创建MultiClass,或者为MultiClass重新创建包含多个类的多类。
答案 3 :(得分:1)
不是每个人都喝茶,但你可以使用州模式。
public interface Player
{
void Fight();
void CastSpell();
void DoRoguishThings();
}
public class PlayerImpl : Player
{
Player fighter;
Player wizard;
Player rogue;
Player current;
public void Fight(){ current.Fight(); }
public void CastSpell(){ current.CastSpell(); }
public void DoRoguishThings(){ current.DoRoguishThings; }
public void MakeWizard(){ current = wizard; }
public void GoRogue(){ current = rogue; }
}
public class Fighter : Player
{
public void Fight(){ // do fighting }
public void CastSpell()
{
Console.WriteLine("You can't cast a spell, you are but a mere pugilist.");
}
...
}
public class Wizard : Player
{
public void Fight(){ // do wizardly fighting }
public void CastSpell() { // do spell-casting }
public void DoRoguishThings() { // whatever }
}
答案 4 :(得分:1)
我认为你的角色应该能够有多个Facet / Role实现“Archetypes”。 然后每个人都有多种技能或属性。让我们说......
class Archetype
{
string Name;
Dictionary<string,Type> Properties;
Dictionary<string,Action> Skills;
}
class Character
{
string Name;
string Alias;
Dictionary<Archetype,Dictionary<string,object>> FacetData;
}
class TheGame
{
public static void Main()
{
var Pilot = new Archetype();
Pilot.Name = "Combat-Pilot";
Pilot.Properties.Add("FlightHours", typeof(int));
Pilot.Properties.Add("AmbientTypes", typeof(List<string>));
var Jedi = new Archetype();
Jedi.Name = "Jedi";
Jedi.Properties.Add("ForceLevel", typeof(int));
Jedi.Properties.Add("Title", typeof(string));
Jedi.Properties.Add("IsCombatVeteran", typeof(bool));
Jedi.Skills.Add("LightSaberFight", FightWithLightSaber());
var Anakin = new Character();
Anakin.Id = 100;
Anakin.Name = "Anakin Skywalker";
Anakin.Alias = "Darth Vader";
Anakin.FacetData.Add(Pilot, new Dictionary<string, object>()
{ { "FlightHours", 2500 },
{ "AmbientTypes", new List<string>() {"Atmospheric", "Space", "Hyper-Space"} } };
Anakin.FacetData.Add(Jedi, new Dictionary<string, object>()
{ { "ForceLevel", 7 },
{ "Title", "Padawan" },
{ "IsCombatVeteran", true } };
Anakin.ApplySkill(Jedi, "LightSaberFight", Target);
}
public static void FightWithLightSaber(Character Target)
{
ShowBrightLightSaberPointingTo(Target);
EmitCoolSound();
}
}
如果您获得了Idea,那么您可以存储属性/数据并通过某种程度的间接性和灵活性调用技能/任务。 祝你好运!
答案 5 :(得分:0)
您可能需要考虑构图。
interface IWarrior
{
void Slash();
}
interface IMage
{
void Cast();
}
class Warrior : IWarrior
{
public void Slash() { }
}
class Mage : IMage
{
public void Cast() { }
}
class WarriorMage : IWarrior, IMage
{
private readonly Warrior _Warrior;
private readonly Mage _Mage;
public void Slash()
{
_Warrior.Slash();
}
public void Cast()
{
_Mage.Cast();
}
}
答案 6 :(得分:0)
NéstorSánchezA。为您提供了一个很好的解决方案。放弃你的OOP思考一段时间并阅读:
http://www.devmaster.net/articles/oo-game-design/
并非所有问题都可以通过简单的OOP以优雅的方式解决。