Что не так с этим дизайном системы игровых эффектов RPG или как я могу удалить все конкретные эффекты из списка различных списков производных эффектов? - PullRequest
0 голосов
/ 29 мая 2018

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

Игра.Игроки, монстры, объекты, разные вещи могут находиться под разными эффектами:

public interface IEffect {}

Могут быть разные конкретные эффекты:

public interface IResistanceBuff : IEffect
{
    void modifyIncomingDamage(Damage damage);
}

public interface IDamageBuff : IEffect
{
    void modifyOutgoingDamage(Damage damage);
}

Почему так?Ну, концепция это, чтобы избежать дублирования кода.Например, таким образом я могу унифицировать уменьшение урона от сопротивлений типа и, например, ношение брони.Я просто делаю класс Type, а класс Armor реализует IResistanceBuff.(Точно так же класс Weapon будет реализовывать IDamageBuff).

Но некоторые эффекты являются временными, а не постоянными.Для этого у нас будет:

public interface ITemporaryEffect : IEffect
{
    long TimeRemaining {get; set;}
}

Опять же, цель здесь состоит в том, чтобы избежать дублирования кода.Например, класс PotionOfMight будет реализовывать интерфейс IDamageBuff и наследуется от абстрактного класса Potion, который, в свою очередь, будет реализовывать интерфейс ITemporaryEffect.Или у нас будет IStun интерфейс, который будет реализовывать ITemporaryEffect.

Теперь каждый объект, который может находиться под определенными эффектами, будет хранить коллекцию (HashSet может быть?) Всех эффектов, под которыми он находится.Это для того, чтобы можно было легче назвать эти эффекты.Например, у персонажа будет свойство public HashSet<IResistanceBuff> ResistanceBuffs {get; private set;}, поэтому мы можем сделать метод TakeDamage персонажа похожим на это:

void TakeDamage(Damage damage)
{
    this.ResistanceBuffs.ForEach(resistanceBuff =>
        resistanceBuff.modifyIncomingDamage(damage)
    );

    this.HP -= damage.Amount;

    if(this.HP <= 0) {
        this.Faint();
    }
}

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

Моя ( не работает, по замыслу C # ) идея для этого быласоздать класс Character (и любой другой класс, представляющий объект, который может находиться под любым видом Effect - это означает даже WorldMap, потому что я думал, что буду сохранять погодные условия, как Effects, примененный кworld) внедрить IEffectStorage интерфейс:

public interface IEffectStorage
{
    List<HashSet<IEffect>> AllEffects {get;}
}

public class Character : IEffectStorage
{
    // ...
    public HashSet<IResistanceBuff> ResistanceBuffs {get; private set;}
    public HashSet<IDamageBuff> DamageBuffs {get; private set;}
    // ...
    public List<HashSet<IEffect>> AllEffects =>
        new List<HashSet<IEffect>> {ResistanceBuffs, DamageBuffs, /* ... */};
}

Теперь работа с истечением временного эффекта была бы обязанностью статического класса Effect:

public static class Effect
{
    public static void ExpireTemporaryEffects(IEffectStorage effectStorage)
    {
        effectStorage.AllEffects.ForEach(effectSet =>
        {
            var effects = effectSet.ToList();
            effects.ForEach(effect =>
            {
                if(effect is ITemporaryEffect) {
                    effect.TimeRemaining--;
                    if(effect.TimeRemaining <= 0) {
                        effectSet.Remove(effect);
                    }
                }
            });
        });
    }
}

Но, конечно, какЯ сказал, что не могу этого сделать.

Теперь я могу начать искать какие-то хакерские и / или уродливые способы заставить этот дизайн работать.И наоборот, я могу рассуждать, что, скорее всего, я пытаюсь что-то предпринять против разработки языка программирования C # и / или парадигмы ООП из-за того, что я недостаточно хорошо понимаю эту парадигму ... Тем более, что это первый проект этогоРазмер я делаю самостоятельно, я решаю сделать последний ... Так что я задаю этот вопрос :) Мой дизайн все не так, и если да, то как это исправить?

Извините задлина этого поста, но я чувствую, что вся информация выше необходима.

1 Ответ

0 голосов
/ 30 мая 2018

Я не являюсь разработчиком игр или имею опыт работы с игровыми движками, но я думаю, что большинство игр или движков используют что-то вроде фреймов для оценки времени (возможно, я совершенно не прав в этом).Моя идея состояла бы в том, чтобы изменить ваш ITevenEffect на

public interface ITemporaryEffect : IEffect
{
    bool IsActive(long currentFrame)
}

и реализовать его следующим образом:

public class SilencedEffect : ITemporaryEffect 
{
    private long duration = 1000;
    private long endFrame;

    public SilencedEffect(int currentFrame)
    {
        endFrame = currentFrame + duration;
    }

    public bool IsActive(long currentFrame)
    {
        return endFrame > currentFrame;
    }
}

Таким образом, вы можете перебрать его в своем персонаже или классе карты мира и удалить его, еслине активен больше.

public class Character
{
    private IList<ITemporaryEffect> temporaryEffect;         

    public void UpdateEffects(long currentFrame)
    {
        var outdatedTempEffects = temporaryEffect.Where(p => !p.IsActive(currentFrame));
        temporaryEffects.RemoveRange(outdatedTempEffects);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...