2009-12-13 7 views
2

Je travaille sur un système d'inventaire de joueur pour un jeu.Constructeur avec un tableau de sous-classes d'une classe abstraite en tant que paramètre

J'ai un struct emplacement qui a une liste <Loot> collection qui représente quels types d'articles sont autorisés en elle. La classe abstraite Le butin est sous-classé par tous les éléments lootables - c'est-à-dire: valides Valeurs de contenu pour le Emplacement struct.

Je veux exprimer qu'un sous peut avoir des restrictions sur les sous-classes de Loot qu'il peut contenir. Par exemple, si la fente représente un conteneur de munitions, je veux seulement tenir Loot sous-classes qui sont des conteneurs de munitions, comme « carquois » et « Pouches Shot » (qui sous-classement Container quelque part le long de la ligne).

classe Loot

public abstract class Loot : GameEntity, ILootable 
{ 
    public int MaxUnitsPerStack { get; set; } 
    public int MaxUnitsCarriable { get; set; } 
    public int MaxUnitsOwnable { get; set; } 

    public void Stack() { } 
    public void Split() { } 
    public void Scrap() { } 
} 

classe Container

public abstract class Container : Loot 
{ 
    public List<Slot> Slots { get; set; } 

    public Container(int slots) 
    { 
     this.Slots = new List<Slot>(slots); 
    } 
} 

struct Slot

public struct Slot 
{ 
    public Loot Content; 
    public int Count; 
    public List<Loot> ExclusiveLootTypes; 

    public Slot(Loot[] exclusiveLootTypes) 
    { 
     this.Content = null; 
     this.Count = 0; 

     List<Loot> newList; 
     if (exclusiveLootTypes.Count() > 0) 
     { 
      newList = new List<Loot>(exclusiveLootTypes.Count()); 
      foreach (Loot l in exclusiveLootTypes) 
      { 
       newList.Add(l); 
      } 
     } 
     else { newList = new List<Loot>(); } 
     this.ExclusiveLootTypes = newList; 
    } 
} 

PlayerInventory

public struct PlayerInventory 
{ 
    static Dictionary<Slot, string> Slots; 

    static void Main() 
    { 
     Slots = new Dictionary<Slot, string>(); 

     /* Add a bunch of slots */ 
     Slots.Add(new Slot(/* I don't know the 
           syntax for this: 
           Quiver, Backpack */), "Backpack"); // Container 
    } 

} 

Je ne sais pas comment fournir les arguments pour les sous-classes Loot dans la fente appel constructeur dans la principale méthode de la PlayerInventory classe.

J'espère que c'est clair. Merci d'avance.

EDIT

j'ai pu résoudre ce (et par là, je veux dire pour le compiler) en utilisant l'approche de David Sieler ainsi que quelques réflexions.

struct Slot


using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 

    public struct Slot 
    { 
     private Loot _content; 
     private int _count; 
     public List ExclusiveLootTypes; 

     public Loot Content 
     { 
      get { return _content; } 
      private set 
      { 
       if ((ExclusiveLootTypes.Contains(value.GetType())) && (value.GetType().IsSubclassOf(Type.GetType("Loot")))) 
       { 
        _content = value; 
       } 
      } 
     } 

     public int Count 
     { 
      get { return _count; } 
      set { _count = value; } 
     } 

     public Slot(params Type[] exclusiveLootTypes) 
     { 
      this._content = null; 
      this._count = 0; 

      List newList; 
      if (exclusiveLootTypes.Count() > 0) 
      { 
       newList = new List(exclusiveLootTypes.Count()); 
       foreach (Type l in exclusiveLootTypes) 
       { 
        newList.Add(l); 
       } 
      } 
      else { newList = new List(); } 
      this.ExclusiveLootTypes = newList; 
     } 
    } 

appel à PlayerInventory constructeur Fente


Slots.Add(new Slot(typeof(Backpack))); 

Merci encore à tous pour la discussion.

+0

Après avoir fait seulement un jour de réflexion à ce sujet, les instances de butin représentent un type de butin. Le slot lui-même a une propriété Count qui représente le nombre de butins qu'il contient. Je m'attends à changer cela une douzaine de fois, mais c'est comme ça que ça fonctionne actuellement. Nice référence TES :) –

+0

Désolé, j'ai enlevé le commentaire demandant si les instances de «butin» représentent un type de butin ou de butin réel, car j'ai oublié l'idée que j'avais en l'écrivant. Donc il semble que vous ayez juste besoin de passer les types de butin possibles au constructeur 'Slot' comme indiqué dans la réponse de @Anon, bien qu'il y ait probablement * beaucoup * de types de butin qui peuvent être placés dans un sac à dos. Avez-vous pensé à une interface avec des types d'outils de butin pouvant être placés dans un sac à dos? – dtb

+0

Eh bien, la liste ExclusiveLootTypes représente un ensemble de contraintes sur le contenu de l'emplacement, pas une plage de contenu possible. Si cette liste contenait TOUTES les entrées, alors la fente pourrait contenir SEULEMENT des éléments du type (s) dans la liste. Cependant, si la liste est vide, elle peut contenir n'importe quoi. Je n'ai pas encore écrit cette routine, mais c'est l'idée. Toutes les sous-classes de butin peuvent être placées dans un sac à dos - c'est l'une des choses qui les rend "piller". –

Répondre

1

Une approche consiste à passer un tableau d'objets Type au constructeur de l'emplacement:

public Slot(Type[] exclusiveLootTypes) { 
    // be sure and check that each Type is a subtype of Loot! 
} 

// Construction looks like: 
new Slot(new[] {GetType(AmmoContainer), GetType(GemContainer) /* or whatever */}); 

ensuite écrire un setter de propriété pour Content qui vérifie le type de l'objet assigné, et signale une sorte d'erreur si ce type ne figure pas dans ExclusiveLootTypes.

2

Vous trouveriez probablement plus facile à utiliser params dans la définition du constructeur à sous:

Slot(params Loot[] exclusiveLootTypes) 

Cela vous permettra de l'appeler comme:

new Slot(lootItem1, lootItem2, lootItem2 /*...etc*/); 

Sinon, vous auriez Vous devez créer un tableau et le transmettre.

+0

J'espérais traiter de cette façon, mais cela ne me permet que d'utiliser des instances, pas des types. Le nouvel emplacement ci-dessus (lootItem1 ...) transmettrait des instances existantes. Je veux passer des types, comme:

 new Slot(Quiver, ShotPouch); 
où Quiver et ShotPouch seraient des sous-catégories de butin. –

1

et de combiner la suggestion précédente d'utiliser params, vous pouvez utiliser une extension LINQ pour convertir les params dans une liste en une seule étape:

public Slot(params Type[] exclusiveLootTypes) 
{ 
    this.Content = null; 
    this.Count = 0; 

    this.ExclusiveLootTypes = exclusiveLootTypes.ToList(); 
} 
2

Il semble que votre conception de l'objet a besoin d'un léger ajustement.

Et si les types d'éléments de butin étaient également des interfaces, par exemple, tous les éléments de butin de mémoire héritent de IAmmoContainer.

Ensuite, vous pouvez transmettre le type IAmmoContainer pour restreindre l'emplacement.

public class Quiver : Container, IAmmoContainer 
public class ShotPouch : Container, IAmmoContainer 
// ... 
new Slot(typeof(IAmmoContainer)) 

EDIT

Sur la base de la discussion dans les commentaires, voici comment je vais sur la conception de ce système.

La classe Loot est correcte. Il représente la base de la hiérarchie du butin.

Ensuite, vous définissez des interfaces pour les «emplacements» qu'un élément peut occuper. Par exemple:

public class LongSword : Loot, IRightHandItem 
public class ShortSword : Loot, IRightHandItem, ILeftHandItem 

Puis la classe PlayerInventory a des "emplacements" en tant que propriétés, qui sont limités au type approprié.

public class PlayerInventory 
{ 
    public List<IRightHandItem> RightHandSlot { get; private set; } 
    public List<ILeftHandItem> LeftHandSlot { get; private set; } 
    // etc... 
} 
+0

Slots.Add (nouvelle fente (IAmmoBag), "Backpack"); donne l'erreur: "Argument '1': ne peut pas convertir de 'System.Type' à (espace de noms) .Loot [] '. –

+0

OK, maintenant je suis vraiment confus. Donc votre emplacement contient déjà une instance des types qu'il peut Essayez-vous de restreindre les types ajoutés à un emplacement ou de pré-initialiser l'emplacement avec les types déjà? –

+0

Initialement - à ce stade - non, l'emplacement ne contient rien (sa variable de contenu qui contient un type de butin actuellement == null .) Ce que j'essaie de faire est de dire que s'il y a des éléments dans la liste ExclusiveLootTypes, alors le slot va exécuter la validation (quand je le code) pour s'assurer que la variable Content reçoit UNIQUEMENT un item qui sous-classe l'un des Types dans Liste ExclusiveLootTypes. Donc, je veux créer le Slot, et lui passer un certain nombre de sous-classes de Loot, puis il va ajouter ces types à la liste ExclusiveLootTypes. –