存储许多游戏常量的最佳继承/接口结构?

时间:2014-04-11 13:59:10

标签: c# inheritance interface static

我的游戏数据结构如下:

public class CraftableFireTower
{
    public static List<ResourceNumber> RequiredResources = new List<ResourceNumber>
    {
        new ResourceNumber(ResourceType.WOOD, 100),
        new ResourceNumber(ResourceType.STONE, 50)
    };
}

public class CraftableFrostTower
{
    public static List<ResourceNumber> RequiredResources = new List<ResourceNumber>
    {
        new ResourceNumber(ResourceType.WOOD, 120),
        new ResourceNumber(ResourceType.STONE, 70)
    };
}

我可以使用哪种接口,抽象类,继承,静态方法/类组合来使它们成为通用的,这样我就可以将它们传递给这样的方法而不必每次都创建新的类实例?

    if (inventory.HasResourcesFor(CraftableFireTower))
    {
        inventory.RemoveResourcesFor(CraftableFireTower);
        serverWorld.BuildFireTower(position));
    }

我尝试了一个接口,但我不能在接口上使用静态方法。我尝试了一个抽象类,但我不能创建静态抽象类或静态抽象方法。我想做什么不可能?是否有更好的方法来构建游戏数据的硬编码分组数字/常量?

5 个答案:

答案 0 :(得分:1)

我可以想到多种方式,这里只是一个简单的方法:

创建一个名为RequiredResourcesAttribute的类属性,然后你可以像这样添加你的类:

public class RequiredResourceAttribute : System.Attribute
{
    public int Quantity { get; set; } 

    public RequiredResourceAttribute( int qty ){ 
       Quantity = qty;
    }
}

创建木材:

public class RequiredWoodAttribute : RequiredSourceAttribute
{
    public RequiredWoodAttribute ( int qty ) : base(qty ){ 
    }

}

然后使用它们......

[RequiredWood(100)]
[RequiredStone(50)]
public class CraftableFireTower
{

}

然后,您可以通过查看类的Resource属性来修改HasResourcesFor()。您可以轻松保留一个缓存的类型及其资源列表,这样您就不必反映类属性超过1,这使得这非常快速且易于维护。

我喜欢为每个craftable对象创建类的想法,如果将来(或现在)你需要不同的方式来处理这些对象如何处理事件或其他与游戏相关的逻辑,那么该类将允许你处理这个唯一的。

因此,在某个类中将Dictionary<Type,List<RequiredResourceAttribute>>的单个实例保留为静态成员。

private Dictionary<Type,List<RequiredResourceAttribute>> _requiredResources = new Dictionary<Type,List<RequiredResourceAttribute>>();

//validate a type has the required resources..

答案 1 :(得分:1)

我建议不要让它们静止。

我不会尝试将CraftableFireTower的定义与CraftableFireTower实例结合起来。在你的游戏中,你有一个单位目录,CraftableFireTower就是其中之一。此目录只需包含每种类型单元的条目。从这个意义上讲,每个目录只会创建一次资源成本列表。

如果玩家创建了CraftableFireTower的实例,那么它应该是一个单独的对象,它引用目录项来定义单价。

...换句话说,你应该有两个对象:CraftableFireTowerDefinition,其中包含所有可以制作的消防塔具有的基本属性,包括资源成本,损坏属性,HP等等。

然后你有CraftableFireTowerInstance,或者甚至更ItemInstance,它引用了CraftableFireTowerDefinition

说明:

interface UnitDefinition
{
    public ResourceCost resourceCost;
    public string name;
}

class FireTowerDefinition : UnitDefinition
{
    public ResourceCost resourceCost = new ResourceCost(50, 50, 20);
    public string name = "Fire Tower";
}

class UnitInstance
{
    public UnitDefinition unitDefinition;

    public int HP;
    public Point PositionOnMap;
    // etc... and other attributes that are per instance
}


....

class MyGame
{
    // this list is pretty much static...
    public UnitDefinition[] catalog = { new FireTowerDefinition(), new OtherThingDefinition() };

    // this list changes throughout gameplay
    public List<UnitInstances> unitInstances;
}

您可能甚至不需要FireTowerDefinition类......基类UnitDefinition可能足以满足目录中的所有内容。

答案 2 :(得分:1)

我认为可以查询工厂类以查找某些内容的成本,但如果请求则还会返回这些内容的实例。

MetaInfo fireMeta = new MetaInfo(100, 50);

Factory.RegisterCraftable(CraftableFireTower, fireMeta);

Factory.GetRequirements<CraftableFireTower>();

Factory.New<CraftableFireTower>();

在工厂内部,工厂只使用字典存储有关每个可变形实例的元信息,例如资源和构建时间。

其他人提到的想法是将类的信息与类本身分开

答案 3 :(得分:0)

坦率地说,我认为你不需要一个接口或一个抽象类,或者每个项目需要一个类。我认为你是一堂课,称之为CraftableItem

public class CraftableItem 
{
    public List<ResourceNumber> RequiredResources = new List<ResourceNumber>();

    // Other properties / methods
}

Then you have one global property in your program for each resource:

CraftableItem CraftableFireTower {
    get { 
        if ( _CraftableFireTower == null ) {
            _CraftableFireTower = new CraftableItem();
            _CraftableFireTower.Add( new ResourceNumber( ResourceType.WOOD, 100 );
            _CraftableFireTower.Add( new ResourceNumber( ResourceType.STONE, 50);
        }
        return _CraftableFireTower; 
    }
}
private CraftableItem _CraftableFireTower

答案 4 :(得分:0)

这是你的目标:

if (inventory.HasResourcesFor(CraftableFireTower)) {
  inventory.RemoveResourcesFor(CraftableFireTower);
  serverWorld.BuildFireTower(position));
}

这是完全合理的,类,接口等不是解决方案。我总是建议数据代码和数据结构继承。

使CraftableFireTower成为枚举值,将数据(Resources)存储在Dictionary中,编写代码以处理数据对象的属性,而不是名称本身。它简单易用。我认为大多数游戏最终会朝着这个方向发展,如果不是一开始的话。它有时被称为实体组件系统或ECS。

此问题中的更多信息:In C++, should different game entities have different classes? Or should it be in one class which contains all behaviours?