pvzclass是如何实现的?pvzclass源代码初步分析(6)PVZ类直属成员变量 & 方法
除去附属的成员类,PVZ类也有直属的成员变量和方法。
本篇将对上述内容有关的代码作简单分析。
强烈建议在阅读本篇前先阅读第3篇和第4篇的内容。



PVZ类直属成员变量
PVZ类中的各种变量,大部分是用PVZ.H开头的那些PROPERTY型的宏实现的。
直属的成员变量也是如此。
不过定义使用的宏会更加五花八门,而不是局限于T_PROPERTY宏及其变种。


第3篇中提到过,PROPERTY宏及其变种需要另外定义读取函数和写入函数。
对于PVZ类直属的成员变量,这些函数的定义在PVZ.cpp中。

如要查询某一成员变量的作用,对于不同的宏应采取不同的方式。
用T_PROPERTY宏及其变种定义的变量,默认从[PVZ_BASE+768],也就是作为基址。
而其他的宏就是八仙过海,各显神通了。
继续以上面提到的LevelId变量为例。根据代码我们可以确定,这个变量与PVZ内部地址为"PVZ_BASE+0x7F8"的变量对应。
我们可以查找MemoryAddressList,从而确定这一变量的作用:

可以看出,LevelId变量对应的是PVZ中当前关卡的序号。
当然,这个变量的作用可以直接通过翻译变量名来确认。
实际上,有的变量根本不对应PVZ本体的变量,而是一个类似方法的存在。
例如这个:

实际上,你可以考虑直接调用__get_SixRoute()……
PVZ类的方法
PVZ类的方法可以分为三类:常用功能、实例化单个对象、实例化某类全部对象。
“常用功能”部分包括五个函数:

GetZombieSeed()可以获取当前关卡的可能出怪种类。
它的代码是这样的:

非常简单。就是扫描一个数组,把符合条件的僵尸计入返回的列表中。
涉及到的BaseAddress+0x54D4的作用可以在MemoryAddressList中查到:

Earthquake(),正如其名,可以使PVZ本体的画面出现震荡(类似窝瓜落地、巨人锤地板等的视觉效果)。
听上去就不好实现?其实不然:

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

Assault()可以立即触发一次袭击(包括墓碑刷怪、珊瑚三人组、屋顶空降三人组)。
其原理和Earthquake()相同,也是运用WriteMemory。
Bell()的原理同上。
Win(),即“直接过关”,运用的是代码注入:

生存模式各关卡对应的LevelId为1~15。在这些关卡下,如果在不正确的时机调用相应的函数,PVZ程序会崩溃。
因此Win()中有针对生存模式的特判。
接下来我们分析实例化单个对象的方法:



这些方法实例化的对象在PVZ本体中,除了Wave以外每关只能存在一个。
它们的代码出奇地一致:

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

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

它们的定义也基本一样:

确认最大数目,扫描对应内存,确认对象是否存在,若存在则加入对应列表。
因为所有的代码都按照上述的方法实现,这里就不再全部贴上了。

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