显示页面修订记录链入页面回到顶部 开始编辑之前,请务必阅读使用指南与编辑规范。这会省去很多不必要的麻烦。 点击“预览”时,会自动保存草稿;编辑结束后记得“保存”。编辑的目的是改进该词条;如果你只想尝试语法,请在沙盒里测试。 媒体文件~~SNIPPET_O1676535103~~snippet:通用排版~~ /* 以上为所有页面共用的排版格式,请勿删除。 */ ~~SNIPPET_C~~snippet:通用排版~~ <WRAP center round todo 70%> 本文涉及到的与游戏内部实现有关的名称,来源于PVZ 0.9.9版本中的pdb文件 </WRAP> ====== DataArray ====== DataArray是原版一代游戏中用于管理一类对象所广泛使用的结构。 对于一种特定的类型,DataArray会先在这种类型后面追加一个mID属性(新的类型称之为DataArrayItem),这个属性在游戏内广泛用于储存对象、寻找对象(例如蹦极僵尸记录抱起植物的过程)。 ===== 结构 ===== 下文中的描述顺序并不是按照逻辑上最佳的顺序书写,而是按照这个结构在内存中的排布顺序来书写的。 ==== mBlock ==== DataArray的核心,为一个指向DataArrayItem类型的对象的指针。 实际游戏中,指向一个长为mMaxSize(下文叙述)的DataArrayItem数组的起始内存。 通俗来讲,这个属性即储存着所有的这类游戏对象。 ==== mMaxUsedCount ==== DataArray曾经被使用的最大编号(不一定是其同一时间内拥有的最大对象数量),也等价于目前存在过的编号最大的对象的编号。 > 例如DataArray<Plant>在游戏开始时为0,种植两个植物后为2,即使铲除掉一个,这个值仍然为2 ==== mMaxSize ==== DataArray的最大容积。对于游戏内的绝大部分对象为1024. ==== mFreeListHead ==== DataArray上一个释放的对象的编号,与下一个对象在DataArray里所属的位置有关,初始为0,具体在下文中详细描述。 ==== mSize ==== DataArray当前的对象数量。 > 例如DataArray<Zombie>的mSize属性即为僵尸数 ==== mNextKey ==== 与ID的决定有关,具体在下文中详细描述 ==== mName ==== 为char*,指向DataArray的名称 ===== 相关操作 ===== ==== Initialize ==== 给定DataArray的大小、名称,进行相关的配置操作 此操作进行后,会将mNextKey的值更改为一个由DataArray名称的第二个字符,第三个字符的ASCII码决定的初始值。 ==== Alloc ==== 在DataArray里申请一个新的对象,位置为mFreeListHead所对应位置,同时更新mFreeListHead,如果其大于mMaxUsedCount,mMaxUsedCount和mFreeListHead均自增一,否则改为此位置下对象的ID(结合下文Free部分,即为上上个释放的对象的位置),然后构造该对象并赋予该对象新ID。 ID占32位,其中16位为其在DataArray数组中的位置顺序,另16位为mNextKey的值。 完成此操作后,mNextKey的值自增,到达65536后重置为1. ==== Free ==== Free操作会释放对象,并且更新当前的mFreeListHead为所释放对象的对应位置。 同时,也会将对象的ID改为当前的mFreeListHead(这导致了其用于校验的Key部分始终为0,而mNextKey不会为0,于是该部分为0的对象始终为处于释放状态) 需要注意的是,游戏内的植物、僵尸等对象死亡时,会先运行Die方法,而Free方法在一轮循环的某时刻统一释放掉所有处于Die状态的对象。这也导致了mMaxUsedCount有时会比场上对象的历史最大数量还要大。 ==== FreeAll ==== 释放所有对象 ==== Dispose ==== 重置所有状态为初始化前 ==== GetID ==== 获取DataArray中对象的ID。 ==== Get ==== 由ID获取到其在DataArray中的位置,从而获取到对象 ==== TryToGet ==== 会事先校验给予的ID值是否为0,给予的ID的对应编号是否超过了mMaxSize 在Get的基础上,还会校验获得的对象的ID是否与给予的ID完全一致,如果不一致则返回空。 此判断被广泛使用,如果没有该判断,会出现如舞王僵尸召唤的伴舞僵尸死亡后,舞王僵尸立刻和新出现的僵尸建立连接的BUG,在有这个校验的情况下,需要在期间内刷新六万五千多次mKey才有可能达到类似的效果,这对于游戏是不可能的(但原版仍有达到现象的方法,见下文“游戏漏洞”)。 ==== Iterate ==== 尽管不是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,从而在游戏内建立错误的联系。可以用此方法实现缠绕海草抓取飞贼僵尸、舞王僵尸绑定非伴舞僵尸等效果。请在输入框中填入验证码以证明您不是机器人。 请将此区域留空:保存预览取消 编辑摘要 当你选择开始编辑本页时,即视作同意将你贡献的内容按下列许可协议发布: CC Attribution-Share Alike 4.0 International 最后更改: 10月前由 Ghastasaucey 修改