将实例或类用于游戏资源(木材,铁,金)


31

因此,我正在制作一个游戏,您可以在该游戏中将船只发送到地点以买卖木材,铁,黄金等资源。

现在我想知道如何在游戏中创建资源。我想出了两种选择

  1. 为每个资源创建一个类:

    public class ResourceBase {
        private int value;
        // other base properties
    }
    
    public class Gold : ResourceBase {
         public Gold {
             this.value = 40 // or whatever
         }
    }
    
  2. 创建资源类的实例

    public class Resource {
        string name;
        int value;
    
        public Resource(string name, int value) {
            this.name = name;
            this.value = value;
         }
     }
    
    // later on...
    
    Resource gold = new Resource("Gold",40);
    

使用第二个选项,可以从resources.json文件填充游戏资源,我有点喜欢这种结构。

总是欢迎新的想法/设计模式/结构!

编辑:它有点像刺客信条黑旗的伴侣应用程序。请参见下图的资源栏

编辑2:我对“从JSON文件加载项目/资源”进行了更多研究,并找到了这个博客:JSON在游戏开发中的力量-Items。它显示了选项1和选项2的优点。您仍然可以向每个资源添加功能:)

在此处输入图片说明


1
Minecraft对每种资源都有单独的类(并非您应该这样做)
MCMastery

@MCMastery哦,我的世界开源吗?我想看看这种结构。
值得

1
并非如此,但对于服务器却总是感到困惑...参见github.com/Wolf-in-a-bukkit/Craftbukkit/tree/master/src/main/…–
MCMastery

12
不要使用这样的字符串。将“ gold”与“ glod”或类似的名称错误地键入都是很容易的,而且调试起来非常麻烦。使用enum代替。
Nolonar

Minecraft在技术上不是开源的,但几乎已完全反编译和模糊处理。您应该无法在Internet上的任何地方找到经过混淆的源,但是您可以从files.minecraftforge.net下载并运行该过程以进行处理(MDK下载是您想要的)
JamEngulfer

Answers:


51

选择第二种方法,仅仅是因为您可以随时引入新的资源类型或项目,而不必重写或更新代码(数据驱动的开发)。


编辑:

要详细说明为什么这是一般的良好做法,即使您100%确信某些价值也不会改变。

让我们以注释中提到的控制台游戏为例,因为这提供了一个很好的理由,说明为什么您不应该硬编码任何东西,除非您确实有(或想要)例如加密密钥,自己的名字等。

在游戏机上发布游戏时,通常必须经过审查过程,游戏机制造商自己的质量检查人员将测试游戏,进行游戏,查找问题等。这是强制性的,而且要花很多钱。我想我曾经读过一个版本,仅用于认证的费用就可能需要30,000-50,000美元。

现在,假设您要发布游戏,支付30,000 $,然后等待。突然间,您发现您的某些游戏价值被字面上破坏了。假设您可以用50金币购买铁条,然后以55金币出售。

你是做什么?如果您对这些内容进行了硬编码,则必须创建一个新的更新/发行版本,该版本必须再次进行审核,因此在最坏的情况下,您将需要为重新认证再次付费!我敢打赌,育碧不介意,但为您自己的独立游戏开发商筹集了资金……哎呀!

但是想象一下,游戏偶尔会检查更新的游戏定义(例如,以JSON文件的形式)。您的游戏可以随时下载并使用最新版本,而无需进行新更新。您可以随时修复该不平衡/漏洞利用/漏洞,而无需重新认证或支付任何其他费用。只是一些小的设计决定,您认为并不值得,只是为您节省了5位数的钱!那不是很棒吗?:)

只是不要误会我的意思。这也适用于其他类型的软件和平台。通常,无论是游戏还是某种应用程序/工具,对于标准用户而言,下载更新的数据文件都更加容易且可行。想象一下在Windows中“程序文件”下安装的游戏。您的更新程序需要管理员权限才能修改任何内容,并且您不能修改正在运行的程序。使用DDD,您的程序只需下载数据并使用它。播放器甚至可能不会注意到有更新。


6
DDD +1。这非常适合诸如资源之类的事情。
Kromster说支持Monica

@Funnydutchman如果有人的答案对您有所帮助,则Stack Exchange习惯于通过单击左侧数字上方的箭头来提升他们的答案。如果答案对您的帮助最大,则应单击底部箭头下方的选中标记以接受他们的答案。两种操作都使答题者获得声誉上的好处,并使社区更容易看到可用的答案。
Nzall

2
我不知道您怎么用第一种方式重写代码;您要做的就是添加一个类(除非我错过了什么)。
SirPython '16

4
这是面向对象的代码和对象痴迷的代码之间的区别。仅仅因为您可以创建一个对象层次结构并不一定意味着您应该这样做。
corsiKa 2013年

2
@AgustínLado如果客户每次说“这永远不会改变”,我都会得到一美元,而且它改变了,我可以带我们俩去一家像样的餐厅吃晚饭(尽管我们不得不在小费上略作一番,所以也许只是一家平庸的餐厅。虽然仍然有足够的时间可以吃两个人。)
corsiKa

29

一条经验法则是,当对象需要不同的代码时,您将使用不同的类;而当对象仅需要不同的值时,您将使用同一类的实例。

当资源具有独特的不同游戏机制时,可能有必要用类来表示它们。例如,当你有钚具有半衰期时间和兔根据其生育斐波纳契数列,那么它可能是有意义的有一个基类Resource以的方法Update为无操作和两个派生类中实现HalfLifeResourceSelfGrowingResource其覆盖该方法以减少/增加值(并且可能还包括控制将两者相邻存储时发生的情况的逻辑)。

但是,当您的资源实际上只是愚蠢的数字时,用简单的变量来实现它们就没有任何意义。


感谢@Phillipp的回答。这就是我的想法。但是资源不会在属性/方法方面真正改变,所以我现在将选择选项2
MDijkstra

14

我想添加两个额外的选项:
接口:如果资源类只是5个整数的“存储”,而每个其他实体在资源方面都有不同的逻辑(例如,玩家花费/掠夺,城市生产),则可以考虑使用资源)。在这种情况下,您可能根本不需要类-您只想公开某些实体具有变量,而其他变量可以与之交互:

interface IHasResources {
  int Gold { get; set; }
  int Wood { get; set; }
  int Cloth { get; set; }
  // ....
}

class Player : IHasResources { }
class City: IHasResources { }

此外,这样做还有一个好处,就是您可以使用与掠夺敌方舰队完全相同的代码来掠夺城市,从而促进代码的重用。
缺点是,如果许多类都实现了该接口,可能会很乏味,因此您可能最终会使用接口,而不是原来的问题,可以使用选项1或2来解决:

interface IHasResources { 
   IEnumerable<Resource> Resources { get; }
}

实例(带有枚举):在某些情况下,定义资源类型时最好使用枚举而不是字符串:

enum Resource {
   Gold, Wood, Cloth, //...
}

class ResourceStorage {
   public Resource ResourceType { get; set; }
   public int Value { get; set; }
}

这会提供一些“安全性”,因为在编写点之后,IDE会在分配它时为您提供所有有效资源的列表ResourceType = Resource.,此外,您还可能需要更多带有枚举的“技巧” ,例如显式Type或composition / 标志我可以想象在制作时很有用:

[Flags]
enum Metal {
 Copper = 0x01/*01*/, Tin = 0x02/*10*/, Bronze = 0x03/*11*/
}
Metal alloy = Metal.Copper; //lets forget Value(s) for sake of simplicity
alloy |= Metal.Tin; //now add a bit of tin
Console.WriteLine(alloy); //will print "Bronze"


至于什么是最好的-没有灵丹妙药,但是我个人倾向于任何形式的实例,它们可能不像界面那么花哨,但它们很简单,没有混乱的继承树,并且被广泛理解。


2
谢谢您的答复@wondra我喜欢枚举选项,以及您如何用铜和锡制成青铜; p
MDijkstra 2016年

2
我专门加入了该社区,因此可以投票支持枚举解决方案。您还可以研究使用enum Description属性将enum(my-great-enum)的JSON表示映射到enum()的C#表示MyGreatEnum
丹·福布斯

显然我离开Java循环太久了。从什么时候开始允许使用接口的字段声明?据我所知,这些是自动静态的和最终的,因此对于问题中所述的目的没有太大用处。
M.Herzkamp

2
@ M.Herzkamp不是字段,而是属性-Java不支持属性。问题被标记为C#,C#允许接口中的属性-毕竟属性是方法的底层。恐怕标记注释也是如此,尽管我不确定,但Java不支持标记注释。
温德拉

感谢您清理!我错过了C#标记,问题中的代码看起来非常像Java:D
M.Herzkamp 2016年

2

您应该使用选项1,它具有3个优点:

  1. 实例化资源更加容易-例如,您不必这样做,而不必将资源的类型作为参数传递。 new Gold(50)
  2. 如果您需要对资源进行特殊处理,则可以通过更改其类来实现。
  3. 检查资源是否为特定类型更容易- resource instanceof Gold

所有答案都有其优缺点,很难选择哪个更好。我对问题进行了编辑,您如何看待这种结构?
MDijkstra

1

如果您的资源没有自己的业务逻辑,或者没有特殊情况下如何与环境交互,则其他资源(除了您已介绍的交易之外)或参与者都可以轻松地添加两个新资源。

如果您需要考虑将两种资源混合在一起进行加工时会发生的情况,如果这些资源可能具有截然不同的属性(一桶水与一整块煤有很大不同)或其他复杂的经济相互作用,则方法1是引擎的灵活性要大得多,但数据要灵活得多。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.