サーチ…


RPGゲームでのマップの実装

フライウェイトは構造設計パターンの1つです。類似したオブジェクトでできるだけ多くのデータを共有することによって、使用されるメモリの量を減らすために使用されます。この文書は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の新しいインスタンスを作成しました

ロックの新しいインスタンスを作成しました

しかし、なぜ我々は2回それを取得したい場合、芝生は一度だけ表示されますか?これは、初めてGetField grassインスタンスをリポジトリに存在しないと呼ぶためです 。作成されましたが、次に草が必要なときは既に存在しているので、返すだけです。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow