欢迎光临散文网 会员登陆 & 注册

pvzclass是如何实现的?pvzclass源代码初步分析(6)PVZ类直属成员变量 & 方法

2021-07-14 12:25 作者:__W1thoutD0ubt  | 我要投稿

除去附属的成员类,PVZ类也有直属的成员变量和方法。 

本篇将对上述内容有关的代码作简单分析。

强烈建议在阅读本篇前先阅读第3篇和第4篇的内容

PVZ类直属成员变量

PVZ类中的各种变量,大部分是用PVZ.H开头的那些PROPERTY型的宏实现的。

直属的成员变量也是如此。

不过定义使用的宏会更加五花八门,而不是局限于T_PROPERTY宏及其变种。

部分使用PROPERTY宏及其变种定义的变量
部分使用PROPERTY_BINDING宏定义的变量

第3篇中提到过,PROPERTY宏及其变种需要另外定义读取函数和写入函数。

对于PVZ类直属的成员变量,这些函数的定义在PVZ.cpp中。

变量GameVersion的getmethod()

如要查询某一成员变量的作用,对于不同的宏应采取不同的方式。

用T_PROPERTY宏及其变种定义的变量,默认从[PVZ_BASE+768],也就是作为基址。

而其他的宏就是八仙过海,各显神通了。

继续以上面提到的LevelId变量为例。根据代码我们可以确定,这个变量与PVZ内部地址为"PVZ_BASE+0x7F8"的变量对应。

我们可以查找MemoryAddressList,从而确定这一变量的作用:

可以看出,LevelId变量对应的是PVZ中当前关卡的序号。

当然,这个变量的作用可以直接通过翻译变量名来确认。

实际上,有的变量根本不对应PVZ本体的变量,而是一个类似方法的存在。

例如这个:

(判定当前场景是否为六行场地)

实际上,你可以考虑直接调用__get_SixRoute()……

PVZ类的方法

PVZ类的方法可以分为三类:常用功能、实例化单个对象、实例化某类全部对象。

“常用功能”部分包括五个函数:

GetZombieSeed()可以获取当前关卡的可能出怪种类。

它的代码是这样的:

非常简单。就是扫描一个数组,把符合条件的僵尸计入返回的列表中。

涉及到的BaseAddress+0x54D4的作用可以在MemoryAddressList中查到:

Earthquake(),正如其名,可以使PVZ本体的画面出现震荡(类似窝瓜落地、巨人锤地板等的视觉效果)。

听上去就不好实现?其实不然:

套皮WriteMemory

涉及到的三个变量的作用同样可以查到:

Assault()可以立即触发一次袭击(包括墓碑刷怪、珊瑚三人组、屋顶空降三人组)。

其原理和Earthquake()相同,也是运用WriteMemory。

Bell()的原理同上。

Win(),即“直接过关”,运用的是代码注入:

生存模式各关卡对应的LevelId为1~15。在这些关卡下,如果在不正确的时机调用相应的函数,PVZ程序会崩溃。

因此Win()中有针对生存模式的特判。

接下来我们分析实例化单个对象的方法:

这些方法实例化的对象在PVZ本体中,除了Wave以外每关只能存在一个

它们的代码出奇地一致:

return new Class(ptr)

Wave类虽然在每关有多个,但实际上,GetWave()的代码并不比其他方法的代码简单许多:

除了特判没啥不同

实例化某类全部对象的方法可以直接将场上的一类对象全部囊括。以下的方法都可以实例化某类全部对象:

它们的定义也基本一样:

确认最大数目,扫描对应内存,确认对象是否存在,若存在则加入对应列表。

因为所有的代码都按照上述的方法实现,这里就不再全部贴上了。

下一篇将PVZ类剩下的内容一并分析完,给PVZ.h的分析画上一个句号。

pvzclass是如何实现的?pvzclass源代码初步分析(6)PVZ类直属成员变量 & 方法的评论 (共 条)

分享到微博请遵守国家法律