游戏制作过程中难免会涉及到使用一些数据表。

很多游戏对数据表的使用方法是 用游戏对象去依赖数据表,比如初始化血量、攻击力等数值时,去根据相关表格进行计算。

但我个人更倾向于使用 数据表依赖游戏对象 的方法,游戏对象完全不依赖数据表的存在。具体的做法是:数据表中的数据读写,实际上是对游戏对象数据的读写,数据表只是相当于把多个游戏对象的数值汇总,以用于统一管理。

在 Unity 里我习惯使用 ScriptableObject 来作为数据表,这样的话引用 prefab 会很方便。给数据表的 property 加上 Odin InspectorShowInInspector, 就可以实现通过 ScriptableObjectprefab 进行读写。

Prefab 是可以这样做了,但是由于场景中的对象无法在 ScriptableObject 中序列化,所以对于场景对象的修改还得想想办法。

我目前的办法是在场景中放一个对象 M, 用于存放场景中所有需要通过数据表进行修改的对象引用。每次使用数据表时,把 M 拖到数据表中进行数据表中引用的初始化,这样就可以了。

实际上大部分人大概都不是使用 ScriptableObject 来做数据表,而是使用例如 Excel, CSV 之类的表格。这些表格不能读取项目中游戏对象的实际参数,这时我认为应该使用 ScriptableObject 作为中介者,读取表格的数据,写入各个对象。

上面我所说的,都是针对游戏开发阶段。如果是 Stellaris 这类需要在发布后依赖外部表格的游戏,或者是玩家可以通过表格进行自定义修改的游戏,那么需要重新考虑问题。

大部人可能为认为做这些是多此一举,但我写工程习惯于简洁直接地表达事物之间的关系。在整个游戏逻辑里,数据表的概念实际上是不需要的,实际必要的是游戏对象的数值。数据表只是开发者开发时的中间产物,那么它就不应该出现在最后的发布版里。

它就是个怎么看都很奇怪的,基本上没有用处的,凭空让代码变 gay 的,没事找事的,让人幻想以为有用的安慰剂。

以前写 JavaScript 的时候,主流的风格是花括号不提行:

1
2
3
4
function unlerp(a, b, t) {
assert(b > a);
return (t - a) / (b - a);
}

早期的时候 Unity 文档里使用 C# 时花括号也不提行。
但是 C# 的主流风格是花括号要提行:

1
2
3
4
5
6
public static class LayerManager
{
public static readonly int Player = LayerMask.NameToLayer("Player");

public static readonly LayerMask PlayerMask = 1 << Player;
}

由于我有时写 JavaScript,有时写 C#, 所以就干脆都不提行了,统一风格。
于是我写 C# 就会像是这样:

1
2
3
4
5
6
7
8
9
10
public void TogglePlacingState() {
bool shouldSettingPosition = !IsPlacing;
if (shouldSettingPosition) {
ghostObject.SetActive(true);
StartUpdatePosition();
} else {
StopUpdatePosition();
ghostObject.SetActive(false);
}
}

但是现在越来越多的人写 C# 时花括号要提行了。
我自己虽然喜欢不提行,但总是需要跟别人合作的,还是有必要改变一下:

1
2
3
4
5
6
7
public static class LayerManager
{
public static readonly int Player = LayerMask.NameToLayer("Player");

public static readonly LayerMask PlayerMask = 1 << Player;
}

其实花括号只是一个例子,其他一些代码风格也可能有所不同。例如 JavaScript 的函数名流行小驼峰命名法,而 C# 流行大驼峰命名法。

不同的编程语言有不同的语言特性和代码风格,即使需要同时使用多种编程语言,也不应该使用自己最习惯的同一种风格,而应该入乡随俗地根据各自语言的 style guide 来进行编码,而这也没有想象中那么麻烦。

今天在写 C# 的时候遇到下面这样一个问题。

首先我们大多数人知道,如果有一个静态类像这样:

1
2
3
4
5
public static class c1
{
public static int v1 = 256;
public static int v2 = v1;
}

然后打印 v2 会得到 256。

而如果它是:

1
2
3
4
5
public static class c1
{
public static int v2 = v1;
public static int v1 = 256;
}

然后打印 v2 会得到 0。

这是由它声明顺序决定的。

但是如果静态成员变量 v1, v2 在不同的类中,情况就没有这么简单。如果有这么两个类:

1
2
3
4
5
6
7
8
9
public static class c1
{
public static int v1 = 256;
}

public static class c2
{
public static int v2 = c1.v1;
}

此时不管是以上面这样的顺序声明两个类,还是换一下顺序:

1
2
3
4
5
6
7
8
9
public static class c2
{
public static int v2 = c1.v1;
}

public static class c1
{
public static int v1 = 256;
}

打印 c2.v2 的结果都是 256。

这时我就纳闷了,就跟朋友们讨论了一下,他们说可能是因为编译器很智能,会根据类之间的依赖关系来决定初始化顺序。那么就有新的问题了,如果他们相互依赖的话,情况又是怎么样呢?

为了测试,把两个类改成这样:

1
2
3
4
5
6
7
8
9
10
11
public static class c1
{
public static int v1 = 256;
public static int v2 = c2.v1;
}

public static class c2
{
public static int v1 = 1024;
public static int v2 = c1.v1;
}

此时先后打印 c1.v2, c2.v2, 会得到结果:

1
2
1024    // c1.v2
0 // c2.v2

即使我调换了 c1, c2 的声明顺序,也是得到这个结果。

但是,如果我换一下打印顺序,先打印 c2.v2, 再打印 c1.v2, 结果是:

1
2
256    // c2.v2
0 // c1.v2

也就是说,在这种情况下,会根据代码的执行顺序来决定初始化顺序。不会报错,也不会报警告。

而这通常不是我们想要的。在编码过程中要尽量避免把代码写成这种情况,我们不应该依赖智能的编译器。

Subset Games

Subset Games 是由 Justin Ma 和 Matthew Davis 两人在2011年创办的游戏工作室。在此后的几年里,他们制作了著名游戏 FTL: Faster Than LightInto the Breach.

他们在 Youtube 上有几场演讲:

除此之外还有几场没有这么正式的。

从 Justin Ma 的 LinkedIn 可以看到,他是2007年毕业的,在2011年4月成立了 Subset Games 开始做自己的游戏,然后一直工作至今。

也就是说他在工作4年之后开始创业,第一个项目就成了爆款。

最近关注了一位大牛韦易笑,把他到目前为止的博文大致浏览了一下。我比较感兴趣的内容主要是关于 游戏开发随笔网络游戏技术 两部分的。今天记录一下看了他一些 游戏开发随笔 后的感悟。

这方面的文章有三篇:

现实主义题材需要拯救

首先他谈到的是参考游戏 vs 参考生活。做游戏不应该只参考游戏,而应该参考生活,因为艺术源于生活。现在很多人忘了这点,所以做不出创新。游戏只是一个载体,就像小说、电影一样。它所承载的内容才是更重要的。如果只关心做游戏的技术,而不注重观察生活,可能在“术”上能做到很高的水准,但却做不到“艺”上的合格,从而做不出游戏的作品。所以做游戏的不应该住关注游戏领域,而应该关注生活的方方面面,创意往往来源于这些地方,Overcooked 就是很好的例子。

其次谈到了创新 vs 改良

人类既是依赖习惯的动物,也是追求新鲜感的动物。

好的游戏应该平衡这两点,类似的观点在开发者:独立游戏的十个成功秘诀(以及为什么它们不存在)一文中也有所谈到。熟悉感能让玩家将作品与之前的美好记忆联系起来,并被它吸引;新颖性为玩家带来令人兴奋的新鲜感受。做的游戏不应该太老套,也不应该太过新颖让人难以理解。

下面一个重要的话题是现代题材 vs 古典题材。我们背负了五千年文化的大包袱,很少有关于现代题材的优秀游戏。大厂不愿意做现代题材,只有某些个人的灵光乍现,才会产生一些现代题材游戏,像潜伏之赤途/隐形守护者的优秀游戏太少了,而且始终不是主流。

我一直认为把武侠的精神代入现代题材有着很好的意义,武侠是一种精神,而不是功夫。目前看来,相对于国内的研发水平,做这样的游戏太过冒险、太过宏大了,不过我相信以后会有这样的作品的,

现实主义题材需要拯救这篇文章作于2007年,现在已经2019年,文中所提到的问题依旧没有得到解决。大牛能在那个时候就有这些想法也不容易,而十几年过去了在这些方面一点儿进步也没有也是难得……

不过挺好的,有问题才有机会,不然我们这些人干嘛呢?

二十年前是怎样开发游戏的?

啊,大概就是说20年开发游戏巨麻烦,什么都要自己实现,还没有资料查。励志的是最后两段:

行业总是要发展的,我也从《编程技巧与维护》《VGA显示原理》。。。和各种杂志上获取了不少知识,当年写这些文章的人,和身边搞计算机的,都比我大很多,我幼小的心灵里总有一份冲动,冥冥之中觉得将来自己肯定能超过他们,这不是因为我看不起她们,异或我狂妄自大,而是只有这样,站在她们肩上,才能对得起大家共同爱好的这个行业,大家共同追求的事业。

而今天,我会尽量利用业余时间,于各处培训游戏开发,帮助大家该如何实现各种东西,目的也只有一个,让今天的小孩将来有一天能够超过我,不是因为她们狂妄自大,异或我妄自菲薄,而是因为只有这样,让她们站在我的肩上,才能对得起大家共同爱好的这个行业,大家共同追求的这个事业。

太励志了(摇了摇头,自叹不如)。

你为什么会离开游戏行业?

  • 游戏产品成功率只有1%,做游戏成败犹如开宝箱。
  • 做游戏不可持续发展,做游戏不如做应用。
  • 开发团队失去主导。
  • 游戏开发成本持续上升,创业越来越难。
  • 劣币驱逐良币。
  • 大家都只关心钱,不关心游戏了。

这篇文章推荐去看原文你为什么会离开游戏行业? 总结一句话就是:做游戏赚钱越来越难了。

文章最后给出一碗鸡汤解决方案:做精品游戏、拼质量。

大家只有重新找准产品方向,在内容和品质上实现新的突破,继续把行业门槛推高,提升玩家审美。把所谓的大学生都能做的垃圾游戏们送进坟墓,结束目前的混乱,让游戏将重新回到不是谁都能做的年代,用一款款优秀的作品告诉渠道和用户,什么才叫真正的游戏。苹果能在手机泛滥到处山寨化的日子里,重新找到突破。今年上半年上线的若干3A大作,任然能在同质化严重的手游市场脱颖而出,结束了自2013年上半年来渠道被无限放大的乱象。凭借的都不是宣传,更不是渠道,而是一颗颗不甘沉沦的心,和扎扎实实多年摸爬滚打积累的经验。

当然,只有这样,行业价值从渠道回归产品本身,才能让整个行业更理性健康。当然,也只有这样,用一个个的精品游戏,重新将项目变回事业,开发组才能找回昔日逝去的尊严。到那时,渠道当然偶尔也可以招聘一两个大学生,做些棋牌和跑酷娱乐下,但是,那叫做玩具,不能称其为 “游戏作品” 。

我以为只有年纪比较小的人才会中二呢,哈哈,看来作者是真的热爱这行,而且很乐观,这比这段话更容易鼓励人。


大牛的博客里还有这样一篇奇葩:比尔·云风传奇,貌似讲的是云风大牛。以前网易的大牛还真多啊。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×