Особенности дизайна для временного превращения игрока в животное в ролевой игре - PullRequest
7 голосов
/ 08 февраля 2010

Я работаю над ролевой игрой для развлечения и отработки шаблонов дизайна. Я бы хотел, чтобы игроки могли превращаться в разных животных. Например, друид мог бы превратиться в гепарда. Прямо сейчас я планирую использовать шаблон декоратора для этого, но мой вопрос - как мне сделать так, чтобы, когда друид был в форме гепарда, он мог получить доступ только к навыкам для гепарда? Другими словами, они не должны иметь доступа к своим обычным навыкам друидов.

Используя образец декоратора, кажется, что даже в форме гепарда мой друид сможет получить доступ к своим обычным навыкам друидов.

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
    }
}

теперь использую классы

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

Хммммм ... теперь, когда я об этом подумаю, myDruid не сможет использовать заклинания / навыки класса Druid, если класс не будет понижен? Но даже если это так, есть ли лучший способ убедиться, что myDruid в этот момент заблокирован от всех Druid связанных заклинаний / умений, пока он не будет возвращен к Druid (так как в настоящее время он находится в CheetahForm)

Ответы [ 7 ]

10 голосов
/ 08 февраля 2010

Вы не должны использовать свои заклинания и навыки в качестве метода в классе. Они должны представлять собой набор объектов заклинаний и навыков, доступных через интерфейс персонажа (или, возможно, существа). Тогда ваш CheetaForm может переопределить методы getSkills getSkills, чтобы вернуть новую модифицированную коллекцию соответствующих навыков.

1 голос
/ 21 апреля 2010

Извините, что сообщаю вам, ребята, но вы все ошибаетесь, пытаясь использовать молоток на предмете, который не является гвоздем: -P

Чтобы решить вашу проблему, mikedev, вам нужно выйти за пределы ООП, поскольку ООП не может решить эту проблему должным образом. Взгляните на Entity Systems / Компонентные системы.

Первое чтение, которое вы должны сделать, это http://www.devmaster.net/articles/oo-game-design/

Тогда начнется ваше путешествие в мир игрового дизайна.

1 голос
/ 08 февраля 2010

Вместо того, чтобы делать Druid производным классом от Character, рассмотрите возможность использования шаблона Type Object . Во-первых, разделите умения, характерные для классов персонажей, на их собственные объекты:

abstract class Skill
{
    void Perform();
}

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

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

// other skill classes...

Теперь, избавьтесь от производных классов персонажей, сделав это вместо:

class CharacterType
{
    public readonly List<Skill> Skills = new List<Skill>();
}

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

    private CharacterType mType;
}

Ваши классы персонажей теперь могут быть созданы как объектов :

CharacterType druid = new CharacterType();
druid.Skills.Add(new LightHeal());

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

Теперь, изменив mType в Character с druid на cheetah, вы можете изменить класс и поменять имеющиеся умения.

1 голос
/ 08 февраля 2010

Возможно, вместо помещения набора навыков для друида в класс друидов, вы можете переместить этот набор навыков в самого декоратора.

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

Игнорируя ужасно названный класс "StandardDruid", я надеюсь, что вы можете видеть, куда я иду с этим:)

У этой договоренности есть свои плюсы, а именно то, что весь ваш код, основанный на навыках, будет постоянно содержаться внутри декораторов, а не наполовину внутри исходного класса друидов, а остальные навыки - в декораторах. Если бы у вас был другой класс, который мог бы превратиться в друида, вы могли бы легко сделать это без какого-либо дублирования кода.

0 голосов
/ 08 февраля 2010

Как насчет этого?

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;

    ...
}

и, например:

class Spell : ISkill {}

class SpellState : ISkillState {}
0 голосов
/ 08 февраля 2010

Я бы просто сделал свойство в классе друидов "Форма" и проверил бы, читая заклинание, трансформирован друид или нет.

0 голосов
/ 08 февраля 2010

Я бы решил эту проблему, изменив метод LightHeal на виртуальный, а затем переопределил его в классе CheetahForm, чтобы либо выдать исключение, либо показать пользователю сообщение о том, что он не может сделать это прямо сейчас:

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.");
    }
}

Всякий раз, когда я играю в игру, которая включает в себя сценарии такого типа (например, World of Warcraft), пользовательский интерфейс изменяется, чтобы предотвратить использование этих заклинаний, но пользователь все еще может попытаться разыграть эти заклинания с помощью макросов и т. Д. такое обращение помогает остановить это.

Я не думаю, что есть способ «скрыть» метод без использования interface вместо класса для описания CheetahForm, поскольку ссылка на него будет показывать только методы, доступные из interface .

...