# 固体：容器

LLMS 索引： [llms.txt](/dvw/llms.txt)

---

虚拟世界里的物体可以处在各种层级之中。主要的一种是类层级（X 是 Y 的一种），但其他可能还包括组合体层级（X 是 Y 的组成部分）、空间层级（X 在 Y 上面）和容器层级（X 被 Y 容纳）。后两者是相关的，我们马上就会看到。

容器层级很有用，因为它们给了玩家一种物理手段，让他们能在虚拟世界里成批搬运物体。它们并不是必需的：早期计算机操作系统没有子目录或文件夹这类东西，同样，一些早期的虚拟世界（最著名的是《Shades》）也没有容器。不过，它们非常有用。在采用节点式实现的虚拟世界里，这一步其实早就做到了：房间可以容纳角色，角色可以携带（也就是“容纳”）物体，因此，再让物体也能容纳其他物体，并不是多么了不起的想象飞跃。

使用坐标系统处理位置的虚拟世界，通常必须改用节点式系统来处理容装关系。虽然也可以扩展坐标式的做法，让物体能被装在背包、口袋、腰带之类的地方随身携带，但在实践中这对玩家太不方便了。对程序员来说同样不是乐事：他们得把任意物体锁死在角色的坐标系上，好让角色走到哪里、物体就跟到哪里。因此，大多数图形化虚拟世界会为容装关系单独维护一份物品栏，只把坐标系统用在顶层（顶层更容易用图形方式显示）。

图形世界在呈现物体之间的空间关系上没有困难。你能看见瓶子在桌上、椅子在桌边、靴子在桌下，等等。这要归功于坐标系统强加的那种刚性的空间结构。节点式系统没有这种底层结构：如果两个物体都在一个房间里，这丝毫说明不了两者之间的空间关系。就连两个相邻房间之间的连接关系也不是隐含的，必须明确写出来。有些节点式虚拟世界——例如 Skotos 开发的那些——确实在物体之间有一套关系网络。不过，没有绝对坐标就很难做推断：如果 X 挨着 Y、Y 挨着 Z，那么 X 挨着 Z 吗？当然，在对容器的内容物建模时，坐标系统也有同样的问题。幸运的是，大多数玩家不关心“X 在包里”以外的事——他们并不真的在意到底在包里的哪个位置，只要它不会到处移动、想拿的时候拿得到就行。

容器能装的东西通常是有限的。它们只能容纳一定体积（或数量）的物体。有时只有尺寸小于某个限度的物体才装得进去（你没法把一把汤匙塞进啤酒瓶里），有时只有尺寸大于某个限度的物体才留得住（你没法把铅笔存在网兜里）。容器可以是刚性的或柔软的、不透明的或透明的、能合上的或一直敞开的——这些属性与许多其他物体的属性属于同类。不过，容器有一些特殊问题，是其他物体不会遇到的。

大多数容器是内容器（endocontainer），也就是说，它们把东西装在自己里面。箱子、袋子、碗、篮子——它们都把所装的东西包围在内。不过，还有一类较小的外容器（exocontainer）：它们把别的东西托在自己外面。谱架、帽架和圣诞树就是外容器的例子。外容器会“穿戴”它们托着的东西。

有些虚拟世界把外容器与内容器当成完全不同的两回事，理由是：靠包围来装载，与靠钩挂、系绑或别的方式来装载，有本质的区别。当然，这两个概念确实互不相交，但它们的共同点足够多，一般来说把它们当成同一种东西更好。“take music from stand” 和 “take stand from case” 本质上是同一种动作，可以用几乎相同的功能来实现。

关键的差别在两个方面。

第一，不透明内容器的内容可以瞒过窥探的眼睛，而外容器托着什么，你总是看得见。这对文字世界不算太糟，但图形世界必须能构造出动画图像，来配合玩家们几乎任意尝试的各种穿戴组合，这可能非常棘手 [^85]。

第二，对于内容器，容器会保护自己的内容物。如果你击打一个内容器，里面所装的东西受到的伤害可能会减少。对外容器则相反：容器自身受到的伤害可能会减少，因为伤害被外容器托着的东西吸收了。铠甲就是靠这个原理起作用的。

这就引出了一个非常特殊的内容器：玩家自己的角色。尤其是在奇幻世界里，角色携带或穿戴的东西对位置很敏感。你不会把头盔戴在胳膊上，也不会把靴子穿在胸口。图形虚拟世界和文字虚拟世界都有这个问题。

图形世界采用了单机电脑角色扮演游戏的一套标准：显示角色的图像，通常还标出各个“装备槽”，玩家像给纸娃娃穿衣一样给它打点装扮 [^86]。这虽说不上多有沉浸感，但与物品栏总体的运作方式是一致的。文字世界要操心的事更多，因为玩家想指称身体部位。“wear socks”“wear cravat” 之类还行，但玩家想要的是 “wear ring on left index finger”。这就意味着，身体应当被当作一种组合体来处理。玩家通常并不想有条不紊地把身体拆成部件，而且除了在恐怖类型里，人们也不会想要用部件重新拼出新身体来。尽管如此，如果玩家想要指称一个组合体的各个部分，这个组合体就必须被构建出来，或者被伪造出来；无论哪种做法，实现起来都非常烦人，而且等于在向玩家暗示：组合体这种玩法是行得通的。先是身体，接着是成套的铠甲，然后是马匹，再然后是马车——不知不觉间，你已经走得比原计划远得多，响应时间也开始吃紧了。如果你确实决定要实现身体，那就当场定下来它是不是一次性的，并坚持到底。你不会被说动的，你的意志坚如钢铁……

那么书呢？书里有页，但那些页按固定顺序排列，所以它们基本上是组合体。如果有人想 “read page 24”，你会允许吗？还是说，你会让书短到永远只有一页？

把容器变成组合体，可能非常有诱惑力。小心。

把容器变成生成器同样很有诱惑力，但危险小得多。一袋坚果无论你拿出多少，里面总还有坚果，这样挺好——只要你不让任何人把它翻个底朝天。商店里的一个衣帽架可以挂有固定数量的外套，每一件都用惰性求值的方式创建（也就是说，只有有人试图取一件外套时，才会创建出一件来）。

关于容器，最后要提的是负重（encumbrance）这个概念。这是桌面角色扮演游戏里的一个老观念（有人会说它已经过时）。一般来说，一个容器 [^87] 能容纳的物体重量取决于它的力量；它能容纳的件数取决于容器本身的尺寸和相关物体的尺寸（不过对外容器来说，这还涉及某种可用接触点的度量——也就是容器的灵巧度）。然而，物体往往很别扭，它们拖慢你的程度比重量或形状相近的另一些物体大得多。撑开的伞比收起的伞更难拿；氦气球比足球更碍事（这两样东西放了气都更好拿）。

负重这一构想，是要量化某个东西凭自身的属性，在多大程度上影响其容器的各项属性。它是一个不完美的抽象，但有时很有用。即便一个虚拟世界把物体的精确尺寸都存了下来，有些计算代价高昂的运算仍然只能近似处理——比如背包问题（把一个装满的背包倒空，再把原来装的东西全装回去，这可不简单——就像玩三维拼图）。


[^85]: 即便在二维里也很棘手。KiSS 娃娃（Kisekae Set System——电脑上的数字换装娃娃）经常出现问题，比如蓬松的衬衫会从套在外面的夹克上穿出来。
[^86]: 这又是 KiSS 娃娃。想了解更多关于 KiSS 的内容，可以看看 http://otakuworld.com/kiss/。警告：小孩子特别喜欢这东西。
[^87]: 因为角色也是外容器，所以这里也包括角色。这就是面向对象编程在发挥作用。
