Szukaj…


Implementacja mapy w grze RPG

Flyweight jest jednym z wzorów konstrukcyjnych. Służy do zmniejszania ilości używanej pamięci poprzez udostępnianie jak największej ilości danych podobnym obiektom. Ten dokument nauczy Cię, jak prawidłowo używać Flyweight DP.

Pozwól, że wyjaśnię ci ten pomysł na prostym przykładzie. Wyobraź sobie, że pracujesz nad grą RPG i musisz załadować ogromny plik zawierający niektóre postacie. Na przykład:

  • # to trawa. Możesz po nim chodzić.
  • $ jest punktem wyjścia
  • @ jest kamieniem. Nie możesz po nim chodzić.
  • % to skrzynia skarbów

Próbka mapy:

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

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

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

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

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

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

Ponieważ te obiekty mają podobną charakterystykę, nie trzeba tworzyć osobnego obiektu dla każdego pola mapy. Pokażę ci, jak korzystać z wagi muchowej.

Zdefiniujmy interfejs, który będą wdrażane przez nasze pola:

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

Teraz możemy tworzyć klasy reprezentujące nasze pola. Musimy też jakoś je zidentyfikować (użyłem wyliczenia):

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

Tak jak powiedziałem, nie musimy tworzyć osobnej instancji dla każdego pola. Musimy stworzyć repozytorium pól. Istotą Flyweight DP jest to, że dynamicznie tworzymy obiekt tylko wtedy, gdy go potrzebujemy i nie istnieje on jeszcze w naszym repozytorium, lub zwracamy go, jeśli już istnieje. Napiszmy prostą klasę, która sobie z tym poradzi:

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

Świetny! Teraz możemy przetestować nasz kod:

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

Wynik w konsoli powinien wynosić:

Utworzono nową instancję Grass

Utworzono nową instancję Rocka

Ale dlaczego trawa pojawia się tylko raz, skoro chcemy ją zdobyć dwa razy? GetField tak, ponieważ przy pierwszym wywołaniu instancji trawy GetField nie ma w naszym repozytorium , więc została utworzona, ale następnym razem, gdy potrzebujemy trawy, już istnieje, więc zwracamy ją tylko.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow