攻略:dataarray

本文涉及到的与游戏内部实现有关的名称,来源于PVZ 0.9.9版本中的pdb文件

DataArray

DataArray是原版一代游戏中用于管理一类对象所广泛使用的结构。

对于一种特定的类型,DataArray会先在这种类型后面追加一个mID属性(新的类型称之为DataArrayItem),这个属性在游戏内广泛用于储存对象、寻找对象(例如蹦极僵尸记录抱起植物的过程)。

下文中的描述顺序并不是按照逻辑上最佳的顺序书写,而是按照这个结构在内存中的排布顺序来书写的。

DataArray的核心,为一个指向DataArrayItem类型的对象的指针。

实际游戏中,指向一个长为mMaxSize(下文叙述)的DataArrayItem数组的起始内存。

通俗来讲,这个属性即储存着所有的这类游戏对象。

DataArray曾经被使用的最大编号(不一定是其同一时间内拥有的最大对象数量),也等价于目前存在过的编号最大的对象的编号。

例如DataArray<Plant>在游戏开始时为0,种植两个植物后为2,即使铲除掉一个,这个值仍然为2

DataArray的最大容积。对于游戏内的绝大部分对象为1024.

DataArray上一个释放的对象的编号,与下一个对象在DataArray里所属的位置有关,初始为0,具体在下文中详细描述。

DataArray当前的对象数量。

例如DataArray<Zombie>的mSize属性即为僵尸数

与ID的决定有关,具体在下文中详细描述

为char*,指向DataArray的名称

给定DataArray的大小、名称,进行相关的配置操作 此操作进行后,会将mNextKey的值更改为一个由DataArray名称的第二个字符,第三个字符的ASCII码决定的初始值。

在DataArray里申请一个新的对象,位置为mFreeListHead所对应位置,同时更新mFreeListHead,如果其大于mMaxUsedCount,mMaxUsedCount和mFreeListHead均自增一,否则改为此位置下对象的ID(结合下文Free部分,即为上上个释放的对象的位置),然后构造该对象并赋予该对象新ID。 ID占32位,其中16位为其在DataArray数组中的位置顺序,另16位为mNextKey的值。 完成此操作后,mNextKey的值自增,到达65536后重置为1.

Free操作会释放对象,并且更新当前的mFreeListHead为所释放对象的对应位置。

同时,也会将对象的ID改为当前的mFreeListHead(这导致了其用于校验的Key部分始终为0,而mNextKey不会为0,于是该部分为0的对象始终为处于释放状态)

需要注意的是,游戏内的植物、僵尸等对象死亡时,会先运行Die方法,而Free方法在一轮循环的某时刻统一释放掉所有处于Die状态的对象。这也导致了mMaxUsedCount有时会比场上对象的历史最大数量还要大。

释放所有对象

重置所有状态为初始化前

获取DataArray中对象的ID。

由ID获取到其在DataArray中的位置,从而获取到对象

会事先校验给予的ID值是否为0,给予的ID的对应编号是否超过了mMaxSize 在Get的基础上,还会校验获得的对象的ID是否与给予的ID完全一致,如果不一致则返回空。

此判断被广泛使用,如果没有该判断,会出现如舞王僵尸召唤的伴舞僵尸死亡后,舞王僵尸立刻和新出现的僵尸建立连接的BUG,在有这个校验的情况下,需要在期间内刷新六万五千多次mKey才有可能达到类似的效果,这对于游戏是不可能的(但原版仍有达到现象的方法,见下文“游戏漏洞”)。

尽管不是DataArray的操作,但是几乎所有的DataArray都有对应的迭代所有元素的方法(不会迭代到mNextKey位置为0,即已经释放掉的对象)。

mMaxUsedCount在此使用,用于确定迭代的范围。顺序为从序号0遍历到序号最大,原版大部分遍历按照此顺序遍历,在无尽有关的交流中,由此产生的现象常被解释为“栈位”,这可能是由于其后释放的对象位置先重复利用,其符合栈后入先出的特点。不过DataArray本身结构更贴近数组而非栈。

对于植物、僵尸、子弹、物品,也会排除掉已经死亡但是没有调用过Free方法的对象。

原版对于以下对象的管理均使用了DataArray:

  • 植物(Plant)
  • 僵尸(Zombie)
  • 子弹(Projectile)
  • 物品(Coin)
  • * 与植物,僵尸等不同,除了游戏关卡界面外,商店界面也使用DataArray来管理物品
  • 小推车(LawnMower)
  • 场地物品(GridItem)
  • 粒子对象(TodParticleSystem)
  • 粒子发射器(TodParticleEmitter)
  • 粒子(TodParticle)
  • 尾迹(Trail)
  • 动画(Reanimation)
  • 连接件(Attachment)

游戏内在保存DataArray时,只保存了mBlock,mSize,mMaxUsedCount,mFreeListHead。

这导致可以利用退出重进的方法刷新mNextKey,从而在游戏内建立错误的联系。可以用此方法实现缠绕海草抓取飞贼僵尸、舞王僵尸绑定非伴舞僵尸等效果。

请先登录后发表评论 (・ω・)
  • 最后更改: 2月前
  • Ghastasaucey 修改