Suche…


Implementieren einer Karte im RPG-Spiel

Fliegengewicht ist eines der strukturellen Entwurfsmuster. Es wird verwendet, um die Menge des verwendeten Speichers zu reduzieren, indem möglichst viele Daten mit ähnlichen Objekten gemeinsam genutzt werden. In diesem Dokument erfahren Sie, wie Sie Flyweight DP richtig einsetzen.

Lassen Sie mich Ihnen die Idee an einem einfachen Beispiel erklären. Stellen Sie sich vor, Sie arbeiten an einem RPG-Spiel und müssen riesige Dateien laden, die einige Charaktere enthalten. Zum Beispiel:

  • # ist Gras. Sie können darauf laufen.
  • $ ist Ausgangspunkt
  • @ ist Rock. Du kannst nicht darauf laufen.
  • % ist Schatztruhe

Beispiel einer Karte:

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

@############@@@@@######@#[email protected]@@

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

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

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

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

Da diese Objekte ähnliche Merkmale aufweisen, müssen Sie nicht für jedes Kartenfeld ein separates Objekt erstellen. Ich werde dir zeigen, wie man Fliegengewicht benutzt.

Definieren wir eine Schnittstelle, die unsere Felder implementieren werden:

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

Jetzt können wir Klassen erstellen, die unsere Felder repräsentieren. Wir müssen sie auch irgendwie identifizieren (ich habe eine Aufzählung verwendet):

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

Wie gesagt, wir müssen nicht für jedes Feld eine eigene Instanz erstellen. Wir müssen ein Repository von Feldern erstellen. Das Wesen von Flyweight DP besteht darin, dass wir ein Objekt nur dynamisch erstellen, wenn wir es brauchen und es in unserem Repo noch nicht vorhanden ist, oder es zurückgeben, wenn es bereits existiert. Schreiben wir eine einfache Klasse, die dies für uns erledigt:

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

Großartig! Jetzt können wir unseren Code testen:

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

Das Ergebnis in der Konsole sollte lauten:

Erstellt eine neue Instanz von Grass

Erstellt eine neue Instanz von Rock

Aber warum erscheint Gras nur einmal, wenn wir es zweimal haben wollten? Das liegt daran, dass das erste Mal, wenn wir die GetField aufrufen, nicht in unserem Repository vorhanden ist. Sie wird also erstellt. GetField wir jedoch das nächste Mal Gras benötigen, ist sie bereits vorhanden. Daher geben wir sie nur zurück.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow