关于c#:在角色扮演游戏中暂时将玩家转变为动物的设计考虑因素

Design considerations for temporarily transforming a player into an animal in a role playing game

我正在做一个角色扮演游戏,以获得乐趣并练习设计模式。我希望玩家能够将自己变成不同的动物。例如,德鲁伊可能会变形成猎豹。现在我正计划使用装饰图案来完成这项工作,但我的问题是-我该怎么做才能让德鲁伊以猎豹的形式出现时,他们只能访问猎豹的技能?换句话说,他们不应该能够获得他们正常的德鲁伊技能。

使用装饰图案,看起来即使是猎豹形态,我的德鲁伊也能获得他们正常的德鲁伊技能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Druid : Character
{
   // many cool druid skills and spells
   void LightHeal(Character target) { }
}

abstract class CharacterDecorator : Character
{
    Character DecoratedCharacter;
}

class CheetahForm : CharacterDecorator
{
    Character DecoratedCharacter;
    public CheetahForm(Character decoratedCharacter)
    {
       DecoratedCharacter= decoratedCharacter;
    }

    // many cool cheetah related skills
    void CheetahRun()
    {
       // let player move very fast
    }
}

现在使用类

1
2
3
4
Druid myDruid = new Druid();
myDruid.LightHeal(myDruid); // casting light heal here is fine
myDruid = new CheetahForm(myDruid);
myDruid.LightHeal(myDruid); // casting here should not be allowed

嗯……现在我想起来了,我的德鲁伊会不会不能让我们使用Druid类的法术/技能,除非这个类被降低等级?但即使是这样,是否有更好的方法来确保在这一点上,myDruid被锁定在与Druid相关的所有法术/技能之外,直到它被重新投射回Druid(因为目前它在CheetahForm)。


你不应该把你的咒语和技能作为课堂上的方法。它们应该是可以通过角色(或者可能是生物)界面访问的咒语和技能对象的集合。然后,您的cheetaform可以覆盖getskills getspells方法,以返回一个新的修改过的适当技能集合。


很抱歉通知你们,但你们都错了,试图在不是钉子的东西上使用锤子。

为了解决你的问题,Mikedev你需要超越OOP,因为OOP不能正确解决这个问题。看看实体系统/组件系统。

你首先应该阅读的是http://www.devmaster.net/articles/oo-game-design/

然后你的游戏设计之旅将开始。


不要让druid成为从字符派生的类,而是考虑使用类型对象模式。首先,将角色类特定的技能分为自己的对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
abstract class Skill
{
    void Perform();
}

class LightHeal : Skill
{
    public void Perform()
    {
        // stuff...
    }
}

class CheetahRun : Skill
{
    public void Perform()
    {
        // stuff...
    }
}

// other skill classes...

现在,通过这样做来摆脱派生的字符类:

1
2
3
4
5
6
7
8
9
10
11
class CharacterType
{
    public readonly List<Skill> Skills = new List<Skill>();
}

class Character
{
    public IEnumerable<Skill> Skills { get { return mType.Skills; } }

    private CharacterType mType;
}

现在可以将角色"类"创建为对象:

1
2
3
4
5
CharacterType druid = new CharacterType();
druid.Skills.Add(new LightHeal());

CharacterType cheetah = new CharacterType();
cheetah.Skills.Add(new CheetahRun());

现在,通过将Character中的mTypedruid改为cheetah,您实际上可以改变它的类,并交换它可用的技能。


也许你不需要将德鲁伊的技能集放到德鲁伊类中,而是可以将这个技能集移动到装饰器中。

1
2
Druid myDruid = new Druid();
myDruid = new StandardDruid(myDruid);

忽略了这个名字很可怕的"StandardDruid"类,我希望你能看到我要做的是什么:)

这种安排有好处,即所有基于技能的代码都将一致地包含在decorator中,而不是一半包含在原始的druid类中,其余的技能则包含在decorator中。如果您要有另一个可以变形为druid的类,您可以很容易地做到这一点而不需要任何代码重复。


这个怎么样?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface ISkillState { ... }

interface ISkill { ... }

interface IForm
{
    Collection<ISkill> skills { get; set; }
    Dictionary<ISkill,ISkillState> skillStates { get; set; }
}

class Character
{
    private IForm actualForm;
    private Collection<IForm> currentForms;

    ...
}

例如:

1
2
3
class Spell : ISkill {}

class SpellState : ISkillState {}


我只需要在德鲁伊类"form"中创建一个属性,并在施法时做一个if检查,看德鲁伊是否被转化。


我将通过将LightHeal方法更改为virtual来解决这一问题,然后在CheetahForm类中重写该方法,以引发异常,或者向用户显示一条消息,说明他们现在不能这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Druid : Character
{
   // many cool druid skills and spells
   virtual void LightHeal(Character target) { }
}

abstract class CharacterDecorator : Character
{
    Character DecoratedCharacter;
}

class CheetahForm : CharacterDecorator
{
    Character DecoratedCharacter;
    public CheetahDecorator(Character decoratedCharacter)
    {
       DecoratedCharacter= decoratedCharacter;
    }

    // many cool cheetah related skills
    void CheetahRun()
    {
       // let player move very fast
    }

    override void LightHeal(Character target)
    {
        ShowPlayerMessage("You cannot do that while shape shifted.");
    }
}

每当我玩一个涉及这类场景(如魔兽世界)的游戏时,用户界面都会改变以防止这些法术被施法,但用户仍然可以尝试通过宏来施法,因此以这种方式处理它有助于阻止这种情况。

我认为没有一种方法可以"隐藏"方法而不使用interface代替类来描述CheetahForm,因为引用它只会显示interface中可用的方法。