C# Language Implementazione della mappa nel gioco RPG


Esempio

Il peso piuma è uno dei modelli di progettazione strutturale. Viene utilizzato per ridurre la quantità di memoria utilizzata condividendo il maggior numero possibile di dati con oggetti simili. Questo documento ti insegnerà come usare correttamente Flyweight DP.

Lascia che ti spieghi l'idea su un semplice esempio. Immagina di lavorare su un gioco di ruolo e devi caricare un file enorme contenente alcuni personaggi. Per esempio:

  • # è erba Puoi camminarci sopra.
  • $ è il punto di partenza
  • @ è rock. Non puoi camminarci sopra.
  • % è scrigno del tesoro

Esempio di una mappa:

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

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

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

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

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

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

Poiché questi oggetti hanno caratteristiche simili, non è necessario creare oggetti separati per ogni campo mappa. Ti mostrerò come usare il peso mosca.

Definiamo un'interfaccia che i nostri campi implementeranno:

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

Ora possiamo creare classi che rappresentano i nostri campi. Dobbiamo anche identificarli in qualche modo (ho usato un'enumerazione):

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

Come ho detto, non è necessario creare un'istanza separata per ogni campo. Dobbiamo creare un repository di campi. L'essenza di Flyweight DP è che creiamo dinamicamente un oggetto solo se ne abbiamo bisogno e non esiste ancora nel nostro repository, o lo restituiamo se già esiste. Scriviamo una semplice lezione che gestirà questo per noi:

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

Grande! Ora possiamo testare il nostro codice:

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

Il risultato nella console dovrebbe essere:

Creata una nuova istanza di Grass

Creata una nuova istanza di Rock

Ma perché l'erba appare solo una volta se volevamo ottenerla due volte? Questo perché la prima volta che chiamiamo l'istanza di erba di GetField non esiste nel nostro repository , quindi è stato creato, ma la prossima volta che abbiamo bisogno di erba esiste già, quindi lo restituiamo solo.