Поиск…


Реализация карты в игре RPG

Flyweight - один из структурных шаблонов проектирования. Он используется для уменьшения объема используемой памяти путем совместного использования как можно большего количества данных с похожими объектами. В этом документе вы научитесь правильно использовать Flyweight DP.

Позвольте мне объяснить вам это на простом примере. Представьте, что вы работаете в RPG-игре, и вам нужно загрузить огромный файл, содержащий несколько символов. Например:

  • # трава. Вы можете ходить по нему.
  • $ - начальная точка
  • @ - рок. Вы не можете ходить по нему.
  • % - сундук с сокровищами

Пример карты:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@############@@@@@######@#$@@@

@#############@@@######@###@@@

@#######%######@###########@@@

@############################@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Поскольку эти объекты имеют сходную характеристику, вам не нужно создавать отдельный объект для каждого поля карты. Я покажу вам, как использовать мухи.

Давайте определим интерфейс, который будут реализовывать наши поля:

public interface IField
{
    string Name { get; }
    char Mark { get; }
    bool CanWalk { get; }
    FieldType Type { get; }
}

Теперь мы можем создавать классы, представляющие наши поля. Мы также должны идентифицировать их как-то (я использовал перечисление):

public enum FieldType
{
    GRASS,
    ROCK,
    START,
    CHEST
}
public class Grass : IField
{
    public string Name { get { return "Grass"; } }
    public char Mark { get { return '#'; } }
    public bool CanWalk { get { return true; } }
    public FieldType Type { get { return FieldType.GRASS; } }
}
public class StartingPoint : IField
{
    public string Name { get { return "Starting Point"; } }
    public char Mark { get { return '$'; } }
    public bool CanWalk { get { return true; } }
    public FieldType Type { get { return FieldType.START; } }
}
public class Rock : IField
{
    public string Name { get { return "Rock"; } }
    public char Mark { get { return '@'; } }
    public bool CanWalk { get { return false; } }
    public FieldType Type { get { return FieldType.ROCK; } }
}
public class TreasureChest : IField
{
    public string Name { get { return "Treasure Chest"; } }
    public char Mark { get { return '%'; } }
    public bool CanWalk { get { return true; } } // you can approach it
    public FieldType Type { get { return FieldType.CHEST; } }
}

Как я уже сказал, нам не нужно создавать отдельный экземпляр для каждого поля. Мы должны создать репозиторий полей. Суть Flyweight DP заключается в том, что мы динамически создаем объект только в том случае, если он нам нужен, и он еще не существует в нашем репо или возвращает его, если он уже существует. Давайте напишем простой класс, который будет обрабатывать это для нас:

public class FieldRepository
{
    private List<IField> lstFields = new List<IField>();

    private IField AddField(FieldType type)
    {
        IField f;
        switch(type)
        {
            case FieldType.GRASS: f = new Grass(); break;
            case FieldType.ROCK: f = new Rock(); break;
            case FieldType.START: f = new StartingPoint(); break;
            case FieldType.CHEST:
            default: f = new TreasureChest(); break;
        }
        lstFields.Add(f); //add it to repository
        Console.WriteLine("Created new instance of {0}", f.Name);
        return f;
    }
    public IField GetField(FieldType type)
    {
        IField f = lstFields.Find(x => x.Type == type);
        if (f != null) return f;
        else return AddField(type);
    }
}

Большой! Теперь мы можем проверить наш код:

public class Program
{
    public static void Main(string[] args)
    {
        FieldRepository f = new FieldRepository();
        IField grass = f.GetField(FieldType.GRASS);
        grass = f.GetField(FieldType.ROCK);
        grass = f.GetField(FieldType.GRASS);       
    }
}

Результат в консоли должен быть:

Создал новый экземпляр Grass

Создал новый экземпляр Rock

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



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow