C# Language Mise en œuvre de la carte dans le jeu RPG


Exemple

La masselotte est l'un des modèles de conception structurelle. Il est utilisé pour réduire la quantité de mémoire utilisée en partageant autant de données que possible avec des objets similaires. Ce document vous apprendra à utiliser correctement Flyweight DP.

Laissez-moi vous en expliquer l'idée sur un exemple simple. Imaginez que vous travaillez sur un jeu de rôle et que vous devez charger un fichier volumineux contenant des caractères. Par exemple:

  • # est de l'herbe. Vous pouvez marcher dessus.
  • $ est le point de départ
  • @ c'est du rock. Vous ne pouvez pas marcher dessus.
  • % est le coffre au trésor

Exemple de carte:

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

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

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

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

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

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

Comme ces objets ont des caractéristiques similaires, vous n'avez pas besoin de créer un objet distinct pour chaque champ de carte. Je vais vous montrer comment utiliser le poids mouche.

Définissons une interface que nos champs implémenteront:

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

Maintenant, nous pouvons créer des classes qui représentent nos champs. Nous devons également les identifier en quelque sorte (j'ai utilisé une énumération):

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

Comme je l'ai dit, nous n'avons pas besoin de créer d'instance distincte pour chaque champ. Nous devons créer un référentiel de champs. L'essence de Flyweight DP est que nous créons dynamiquement un objet uniquement si nous en avons besoin et qu'il n'existe pas encore dans notre repo, ou le retourne s'il existe déjà. Écrivons une classe simple qui va gérer cela pour nous:

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

Génial! Maintenant, nous pouvons tester notre code:

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

Le résultat dans la console doit être:

Création d'une nouvelle instance de Grass

Création d'une nouvelle instance de Rock

Mais pourquoi l'herbe n'apparaît-elle qu'une seule fois si on veut l'obtenir deux fois? C'est parce que la première fois que nous appelons GetField , l'occurrence herbe n'existe pas dans notre référentiel , elle est donc créée, mais la prochaine fois que nous aurons besoin d'herbe, elle existe déjà.