回顾和今天的计划
我们不使用引擎,也不依赖库,只有我们自己和我们的小手指在敲击代码。
今天我们会继续进行一些工作。首先,我们会清理昨天留下的一些问题,这些问题我们当时没有深入探讨。除了这些,我觉得我们在资产系统方面的工作差不多可以告一段落了。虽然我们在处理资产时遇到了一些小bug,但今天的主要目标是继续实现字体相关的功能。
之前我们已经完成了字体字形的获取部分,但我们还没有开始处理字体的度量(metrics)问题,也就是如何计算字母的尺寸、如何对齐字母等。今天我们会集中精力做这些工作。
在正式开始之前,我希望先清理一下昨天问答环节中留下的一些问题。我们当时编写了一些代码,但并没有仔细检查,所以今天我想确保这些问题都得到解决。
首先,解决上次问答中代码中提出的两个小问题
我们讨论了一个状态自旋锁的问题。当时的代码逻辑大致是,如果尝试加载某个资产时,发现自己不是第一个尝试加载它的(即如果这个加载操作是即时的),那么就应该使用自旋锁。
在回顾这段代码时,我发现了几个问题。首先,我没有使用 volatile
版本的变量,而这是我最初的意图。这个疏忽是个小错误,但需要修正。
其次,更重要的问题是,这个自旋锁应该仅在我们尝试进行即时加载时使用。如果我们并不要求即时加载,那么就不应当等待这个资产的加载。也就是说,自旋锁的使用条件并不正确,这与我们的初衷不符。
因此,我打算修改代码,移除这个不恰当的自旋锁逻辑,确保只有在需要即时加载时才使用它。这样,代码就能按照预期更合理地运行。

回到字体部分
回到字体的部分,可以看到我们之前调试时,字体的图形上出现了黑色背景,而不是像现在这样干净的背景。我们当时的目标是去除这些背景,以便更清晰地查看字体本身。如果要继续做这项工作,接下来想要做的是打开测试资产构建器,这是我们一直在做资产文件规范的工具。
在这个资产构建器中,我们有一个预处理指令,可以选择是否在构建过程中使用库。你可以选择是否在资产构建器中完全不使用任何库,设置为1。如果你想使用stb truetype
,也可以设置为0并将其编译进来。这是之前我展示过如何使用这个库的方式。

获取Windows下的抗锯齿字体
在 Windows 版本中,我们之前没有完全完成字体的抗锯齿处理。如果仔细看会发现字体并没有启用抗锯齿,这也是我们在直播中停下的地方。所以现在值得花点时间来修复 Windows 版本的抗锯齿问题,因为这应该不会太难。
当我们使用 Windows 字体时,路径是这样的。其工作原理是,当我们需要加载字体时,系统会通过一定的方式处理字体的渲染,我们需要检查是否能够在这个过程中启用抗锯齿效果。
也许创建一个颜色兼容的DC能让我们得到抗锯齿效果
在处理字体抗锯齿的问题时,创建了一个设备上下文(DC),并使用了兼容的位图。有人在论坛上猜测,可能由于使用了某种单色位图,导致没有启用抗锯齿。具体来说,CreateCompatibleDC(0)
可能和GetDC(0)
不同,后者会返回屏幕的设备上下文,而前者可能会有默认的行为,导致创建了一个没有颜色信息的位图,因此无法进行抗锯齿处理。
查看字体渲染效果时,字体确实没有抗锯齿效果,这是我们停留的地方。为了测试这个问题,重新编译并运行测试资产构建工具,这会重新提取字体数据,但观察渲染效果时,似乎没有看到抗锯齿有任何改进,显示效果与之前相同。
因此,似乎需要做一些额外的工作,确保位图设置合理,才能真正启用抗锯齿。不过,具体的解决方法尚不清楚,可能需要进一步的调试和测试。

使用CreateDIBSection来更好地控制我们创建的位图
为了能够更好地控制位图,决定创建一个能够直接读取的位图。目标是通过使用 CreateDIBSection
来创建一个位图,这样可以直接访问位图的像素数据,而不是依赖每次获取像素的操作(GetPixel
),因为后者非常慢,每次都需要进行操作系统调用。
CreateDIBSection
会使用一个 BITMAPINFO
结构,结构中的内容可以与之前加载位图时使用的结构相同。具体来说,我们可以设置图像的宽度、高度、位深度等参数,确保生成的位图符合要求。这样,我们就可以验证是否正确设置了位图,且能直接访问其数据。
在 CreateDIBSection
中,我们需要传入设备上下文(DC)句柄,它会是之前创建的兼容设备上下文。我们还需要传入 BITMAPINFO
结构体以及一个指向位图数据的指针,使用该指针我们可以直接访问位图的像素数据。
通过这种方式,我们不仅可以绕过不高效的 GetPixel
,还可以为进一步的抗锯齿渲染提供基础。总体来说,目标是确保位图能够正确创建,并且可以有效地读取位图数据,避免不必要的性能损耗。
初始化传递给CreateDIBSection的BITMAPINFO
为了正确创建 DIBSection
,需要初始化 BITMAPINFO
结构,并确保其中的字段设置合理。BITMAPINFO
结构由 BITMAPINFOHEADER
组成,因此我们必须正确填充这些字段,以便后续使用它创建位图。
首先,我们需要设置 BITMAPINFOHEADER
结构的大小,即 biSize
,通常可以直接使用 sizeof(BITMAPINFOHEADER)
。然后,必须确定位图的宽度 (biWidth
) 和高度 (biHeight
)。由于当前代码尚未明确宽度和高度的定义,因此暂时使用一个最大尺寸(如 1024)作为 MaxDim
,以确保能够适应任何字体字符的渲染。
接着,biPlanes
必须设为 1,这是 Windows GDI 规定的标准值。biBitCount
需要设为 32,因为希望使用 32 位位图格式(每个像素 4 字节,包含 Alpha 透明通道),这样可以更方便地进行像素操作。biCompression
设为 BI_RGB
(即 0),表示不进行任何压缩,这样可以直接访问原始像素数据。
对于 biSizeImage
,如果 biCompression
设为 BI_RGB
,则可以直接设为 0,系统会自动计算。biXPelsPerMeter
和 biYPelsPerMeter
用于指示像素密度,但在当前情况下不太重要,因此可以设为 0。biClrUsed
和 biClrImportant
主要用于调色板索引,但我们不使用调色板,因此也设为 0。
完成 BITMAPINFO
结构的初始化后,接下来会调用 CreateDIBSection
来创建位图,并返回一个可直接访问像素数据的指针。这样,我们可以绕过 GetPixel
这种低效的像素读取方法,直接操作内存,提高渲染性能。不过,目前还无法确定是否所有设置都是正确的,因此需要运行测试来验证是否能够正确创建和访问位图。
最终,我们成功地实现了抗锯齿的字体渲染。现在,字体显示已经变得平滑,没有了之前的锯齿感,这表明问题出在原始位图的创建方式上。
之前的问题可能是由于 Windows 认为位图的每像素位数不足,导致无法正确执行抗锯齿。而通过手动创建 DIBSection
,确保位图具有足够的位深度(如 32 位),Windows 便能够正确地进行抗锯齿处理,使字体呈现更清晰和顺滑的效果。
目前,字体的渲染效果已经明显改善,说明新的位图创建方法是正确的,接下来可以继续推进字体的其他相关功能。
直接获取位图的内容,而不是为每个像素发出操作系统调用
我们尝试优化位图数据的访问方式,使其更加高效,避免调用 GetPixel
这样的低效 API。理论上,既然已经创建了 DIBSection
,那么应该可以直接访问 bits
指针中的数据,而无需逐个调用 GetPixel
。
主要调整:
- 存储指针
- 通过
DIBSection
获取bits
指针,并在外部存储它,以便可以直接访问位图数据。
- 通过
- 遍历像素数据
- 遍历
bits
指针时,按照行扫描方式读取像素。 - 由于位图是 32bpp(每个像素 4 字节),所以可以假设每行的步幅(stride)是
width * 4
。 - 这样可以避免调用
GetPixel
,直接通过指针访问像素数据。
- 遍历
- 确保步幅正确
- 由于
DIBSection
没有显式提供stride
,但 Windows 设备上下文通常会进行对齐,所以需要检查是否有额外的字节填充(通常是 DWORD 对齐)。
- 由于
- 调试问题
- 发现
star pixel
和ref pixel
的数据不匹配,可能是bits
指针的数据未正确初始化,或者DIBSection
没有正确地存储像素数据。 - 通过断点和
assert
进行检查,确认X=11, Y=26
处的数据不符合预期,可能是bits
数据未正确映射或stride
计算有误。
- 发现
下一步行动:
- 验证
bits
指针的数据 :检查bits
是否正确指向DIBSection
内存。 - 检查
stride
计算:确保每行数据的步幅计算正确,没有额外填充字节。 - 确认
SelectObject
是否生效 :确保DIBSection
作为当前位图被正确选入DC
。 - 调试
assert
失败的点 :逐步检查X=11, Y=26
处的数据,看看ref pixel
与star pixel
的具体值。
整体来说,这一步的优化是为了提升性能,使得位图数据可以被直接访问,避免 GetPixel
造成的性能开销。目前仍需进一步调试,以确保 DIBSection
被正确初始化,并且 bits
指针能正确映射像素数据。
我们的像素指针显示的全是零,为什么会这样?
在调试过程中,我们尝试通过 CreateDIBSection
创建一个位图,并希望直接访问其中的像素数据。然而,当前获取到的像素数据全部为零,导致位图显示为空白。我们怀疑 bits
指针并未正确指向有效数据,因此进行了多种排查。
首先,我们确认 bits
指针是否真的无效,尝试遍历像素数据,但发现所有像素值始终为零。接着,我们考虑了数据是否可能是上下颠倒的,但进一步检查后发现并非如此。我们还尝试在遍历像素时添加 assert
断言,以检查像素值是否真的被正确写入,但依然未能找到问题所在。
我们回顾了 CreateDIBSection
的官方文档,并查阅了一些示例代码,发现我们的代码和其他成功示例基本一致,例如:
- 调用
CreateDIBSection
创建位图。 - 使用
SelectObject
将位图选入设备上下文(DC)。 - 执行
TextOut
绘制文本到该 DC。 - 通过
bits
指针访问像素数据。
然而,尽管我们确认 GetPixel
方法可以正确获取绘制的内容,但直接访问 bits
指针时却仍然只得到全零数据。这让我们怀疑 TextOut
是否确实影响了 CreateDIBSection
所创建的位图,或者是否有其他未正确初始化的地方。
进一步检查代码逻辑:
- 位图的创建 :
CreateDIBSection
的调用方式看起来是正确的,bits
指针也成功返回了一个地址。 - 位图的选入 :
SelectObject
也被正确调用,使 DC 绑定到了我们创建的位图。 - 绘制文本 :
TextOut
运行后,我们可以通过GetPixel
正确获取像素值,说明 DC 的内容是正确的。 - 像素数据访问 :遍历
bits
指针时,所有数据均为零,可能说明CreateDIBSection
返回的bits
缓冲区未实际存储 DC 渲染的内容。
由于 CreateDIBSection
允许直接访问像素数据,我们推测:
- 可能 DC 并未真正渲染到
CreateDIBSection
所提供的位图内存,而是仍然写入了默认的设备表面。 - 可能需要使用
BitBlt
或GetDIBits
等 API 从 DC 复制像素数据到CreateDIBSection
的内存。
为了验证这一点,我们考虑缩小位图尺寸,以便更容易观察数据的变化。此外,我们希望找出 CreateDIBSection
内部是否有额外的初始化要求,以确保数据能够正确写入 bits
指针指向的缓冲区。
在代码逻辑和 API 方面,我们仍然在寻找可能的疏漏,以确定为什么 bits
指针中的数据不会随着 TextOut
而更新。
我们想要理解我们的代码
在调试 CreateDIBSection
生成的位图时,我们发现 GetPixel
方法可以正确获取像素数据,但直接访问 CreateDIBSection
返回的 bits
指针时,数据却始终为零。虽然 GetPixel
可以用于 Asset Builder
,但这种做法并不符合代码的理解原则,我们需要真正弄清楚 CreateDIBSection
为什么无法正确提供数据,而不是仅仅接受 GetPixel
作为一个可行的替代方案。
从目前的分析来看:
-
CreateDIBSection
似乎正确创建了位图- 代码调用了
CreateDIBSection
,并成功返回了bits
指针。 - 设备上下文(DC)也成功地将该位图选入,说明位图确实与 DC 相关联。
TextOut
成功执行,且GetPixel
也可以获取到正确的像素值,这表明 DC 里确实有正确的图像数据。
- 代码调用了
-
问题出现在
bits
指针访问数据时bits
指针本应指向CreateDIBSection
分配的像素数据区域。- 但在遍历
bits
指针时,所有像素值均为零。 - 这说明
TextOut
绘制的内容似乎并未写入CreateDIBSection
分配的内存,或者bits
指针指向的区域并未正确更新。
-
可能的原因分析
CreateDIBSection
分配的内存可能未被TextOut
正确写入。- 设备上下文(DC)可能仍然在写入默认的设备表面,而不是
CreateDIBSection
的位图内存。 - 可能需要显式使用
BitBlt
或GetDIBits
来确保bits
指针所指向的内存正确更新。
为了更进一步确认问题,我们可以尝试:
- 检查
CreateDIBSection
生成的位图是否正确
例如,使用GetObject
检查DIBSECTION
结构,看看dsBm.bmBits
是否与bits
指针一致。 - 尝试强制刷新位图数据
例如,在TextOut
之后,使用GdiFlush
或BitBlt
强制将 DC 内容写入bits
所指向的内存。 - 缩小位图尺寸,以便更容易检查数据的变化
通过创建更小尺寸的位图,可以更快验证bits
指针是否正确返回了数据。
我们需要深入理解 CreateDIBSection
的行为,而不是简单接受 GetPixel
的可行性。下一步的重点是验证 bits
指针的有效性,并检查 DC 是否真的将数据写入了 CreateDIBSection
分配的内存区域。
擦除位图,看看这种变化是否通过我们的像素指针可见
在调试 CreateDIBSection
生成的位图时,为了确认 bits
指针是否真的指向有效的像素数据区域,我们尝试在位图初始化时使用 memset
将其填充为全白 (0xFFFFFFFF
),然后再让 Windows 进行绘制,观察绘制后的结果。
实验过程如下:
-
将
bits
指针指向的内存全部填充为白色- 使用
memset
将bits
指针指向的整个位图区域填充为0xFFFFFFFF
。 - 这样做的目的是确保初始状态下,位图中的所有像素都是白色,以便观察 Windows 是否会正确修改这些像素。
- 使用
-
执行
TextOut
进行文本绘制- 代码调用
TextOut
进行绘制,理论上 Windows 应该在bits
指针指向的位图区域中写入文本的像素数据。 - 期望结果是
bits
指向的内存中应该出现文本的像素数据,而不是全白。
- 代码调用
-
检查
bits
指针的内容- 运行代码后,检查
bits
指针指向的内存,发现内容仍然保持全白 (0xFFFFFFFF
),完全没有被修改。 - 这表明
TextOut
并没有实际写入CreateDIBSection
返回的内存区域。
- 运行代码后,检查
结论:
- 这次实验明确证明,
TextOut
并未修改CreateDIBSection
返回的bits
指针所指向的内存。 - 可能的原因包括:
CreateDIBSection
生成的位图未正确绑定到DC
,导致TextOut
仍然在绘制到默认DC
,而不是DIB
位图。TextOut
绘制的内容仍然停留在DC
,但并未同步到bits
指针所指向的内存。
下一步可能的尝试:
- 使用
GetDIBits
读取DC
中的像素数据 ,看看 Windows 是否实际上已经绘制了文本,只是没有正确同步到bits
指针。 - 尝试
BitBlt
复制DC
的内容 到CreateDIBSection
的位图,确保数据能够正确传递到bits
指针指向的内存区域。 - 检查
SelectObject
是否正确 将CreateDIBSection
生成的位图选入了DC
,如果SelectObject
失败,可能意味着DC
仍然在绘制到默认目标,而不是CreateDIBSection
的位图。
这个实验帮助我们进一步缩小了问题范围,接下来的关键是弄清楚 TextOut
为什么没有修改 bits
指针的内容,并找到正确的方法将 DC
的数据同步到 CreateDIBSection
的位图内存中。
位图是从下往上存储的!
在调试过程中,发现位图的指针可能处于错误的位置,导致图像的绘制方向不符合预期。推测位图的渲染顺序可能是从下到上,而我们期望的是从上到下绘制,这造成了显示问题。
问题分析
-
绘制方向错误
位图的指针可能是从位图的底部开始,而不是从顶部开始,这导致图像呈现出来的方向与预期相反。位图在渲染过程中没有按照期望的顺序更新。
-
解决方案猜测
为了修正这个问题,考虑到绘制顺序的不同,可以通过调整位图指针的处理方式来模拟正确的绘制顺序。例如,尝试反向处理位图的行数据,逐行从下往上进行绘制,这样可以匹配底部到顶部的绘制顺序。
直接访问像素,而不是通过GetPixel
在解决位图绘制问题时,首先尝试了调整位图处理的逻辑。通过设置正确的行指针,并确保逐行正确处理位图的像素数据。具体做法是将指针从位图的底部开始,并通过对像素行的操作来确保渲染顺序正确。
问题发现与处理
-
行指针调整
最初在处理位图时,行指针的步进方向不一致。为了处理这种情况,尝试将源行指针向上移动,但在某些步骤中,发现了一个bug,即
x
和y
值没有按照预期的方式调整,这影响了图像渲染的正确性。 -
修正代码
通过进一步调整位图中的最小
x
和y
值的预处理(称为 "pre-step"),确保在读取像素数据时可以准确地对齐并正确处理每个像素。这一步是解决渲染错误的关键。 -
逐步调整并验证
在解决了前面的问题后,继续进行调试,确保在位图渲染过程中没有遗漏任何重要的步骤。随着程序的修正,逐渐恢复了正常的绘制流程。
最终结果
- 在做完这些修改后,成功解决了位图渲染的方向问题,位图从正确的方向开始绘制,并且字符能够正确显示。
- 最终通过在程序中调整源指针、步进方向以及相应的像素数据处理,达到了预期的渲染效果,确保图像准确地显示出来。
此时,经过这些修改,位图绘制问题得到解决,程序也开始按照预期正常运行,显示出了正确的字符和图像内容。

移除调试中的黑色背景
在处理图像和图形渲染时,之前我们选择将 alpha 通道与背景分开处理,这样可以在背景上加上黑色以便更清晰地显示图像。然而,这种做法并不是最理想的,现在我们已经采用了更为准确的处理方式,不再需要这样单独处理 alpha 通道。
通过使用正确的 alpha 渲染方法,图像的透明部分可以更加自然地与背景融合,而不再显示黑色背景。这种方法能够确保渲染出的图像具有更好的视觉效果,背景也会更加清晰和真实。因此,重新构建图像资产时,应该使用更新的 alpha 渲染方法,这样我们可以得到更理想的透明效果。
经过这种改进,现在图像看起来更加专业,透明效果得到了优化,背景不再干扰显示,整体效果更加自然。
重新加入字符周围的1像素边框
目前还需要给图像添加一个边框(围裙),但是由于之前编写位图处理时,我们默认每个图像四周都有一个1像素的透明边框,以保证图像的采样能够正确进行。因此,我们仍然需要在现有的图像处理中加入这个1像素的透明边框,确保渲染效果。
为了做到这一点,可以在处理位图的宽度和高度时考虑到这一点。具体来说,处理时需要在图像四周加上一个1像素的白色边框。在拷贝图像的过程中,可以先清空整个区域,然后确保在实际写入像素时留出空间,具体做法是将目标位置预先偏移1像素。通过这种方法,能够正确处理图像边缘的透明度,避免图像出现被截断的现象。
在代码实现上,尝试将两个相似的代码路径合并,这样可以简化代码,并提高维护性。虽然目前合并可能有些急躁,但可以计划在未来的时间里进行优化。通过调整代码,可以在图像操作时,确保每次拷贝都不会覆盖边缘区域,从而保留预留的1像素边框。
另外,在调试时也发现了一些问题,导致程序崩溃。问题出在尝试预偏移1像素时,导致了内存溢出或访问错误。通过进一步检查,发现是预步进(pre-stepping)过程中,对内存地址的处理不当导致了崩溃,尤其是在处理图像高度时的操作不符合预期。因此,修复这个问题的关键是在处理高度时,确保正确地使用和计算图像的高度,而不是错误地使用错误的值。
解决这个问题后,预期图像渲染应该可以正确地显示带有透明边框的效果。
测试今天的更改
目前看起来,字体的渲染效果已经有所改善,尤其是字母"O"看起来更加平滑了。然而,对于字形(glyph)是否仍然有些微的截断问题,仍然不确定,因此建议查看实际的字形,确认它们是否按预期显示。
虽然目前看起来已经有了一些进展,但仍然无法完全确定所有字形的对齐是否完美。比如,字母"G"是否仍然被截断,可能需要进一步检查,以确保所有字形都被正确地渲染和对齐。
总的来说,现阶段可以认为已经完成了大部分工作,字体的平滑度和准确性得到了提升,虽然可能还有一些细节需要进一步调整。至于字体的种类,如果确认是 Arial 字体,接下来可能需要对比实际效果,进一步确认字形的显示是否完全符合预期。
将我们的结果与Wordpad的字体渲染进行比较
在检查字体效果时,发现字体显示并不是预期的 Arial 字体,而是被意外切换到了 Times New Roman 或 Courier New 字体。通过对比,可以发现字母"G"在 Courier New 字体中显示得比较平坦,这与预期中的 Arial 字体有所不同。不过,这个问题看起来并不严重,因为 Courier New 的"G"本身就是这样的形状。
虽然字形的显示在某些情况下可能和预期不完全一致,但目前来看,这个问题并不会对整体效果造成太大影响。然而,最终还是建议进一步检查字体的准确性,以确保未来在使用不同字体时,能够完全符合预期的显示效果。
你应该将GetDC(0)传递给CreateCompatibleBitmap,而不是CreateCompatibleDC。 但是没关系,你仍然需要使用另一种方法来有效访问位图数据
提到创建兼容位图时,实际上并不是指使用 CreateCompatibleBitmap
函数,而是应该使用一个不同的方法来提高效率。这里讨论的是如果不关心像素获取(GetPixel
),那么就不需要使用 CreateDIBSection
,可以直接使用 CreateCompatibleBitmap
来创建一个兼容的位图。
如果选择不使用 GetPixel
,则可以避免需要像 CreateDIBSection
这样的方法,而是通过 CreateCompatibleBitmap
来直接获得所需的位图。这样的方法可能会更加高效,但会依赖于不同的访问方式。
为什么字形位图需要任意的填充? 获取实际字形大小的方法是正确的吗?
在处理字形位图时,通常需要一些"任意填充"。这个填充是为了确保每个字形在位图中能正确存储和显示。所谓"任意填充"是指在字形位图周围或字形之间加入一定的空白区域,以便进行正确的采样和绘制,尤其是在显示时防止像素错误或重叠的情况。这种填充并不是字形本身的一部分,而是为了适应图像处理、显示和对齐等需要。
关于"实际字形大小"的问题,获取字形大小时需要使用适当的方法,比如从字体或位图中提取字形的边界框。若使用的方法不正确,可能无法准确地提取字形的实际大小,导致显示和存储上的问题。
总的来说,任意填充是为了确保在渲染或处理字形时,能够避免边界问题和对齐错误,从而提高图像处理的准确性。
"任意" = 宽度/高度额外加2
在讨论字形位图时,所谓的"任意填充"其实并不是任意的,而是指根据规范所要求的额外宽度和高度。这个填充是为了确保图像能够正确地进行线性采样,避免在渲染时出现问题。填充的目的是为了保证位图在进行双线性采样时,不会因为边界问题导致采样不准确,特别是在处理图像边界和内存对齐时,填充使得图像能够更高效地进行处理。
在实现渲染器时,提到了使用一个"围裙"(apron)来帮助进行无缝的双线性平铺。这种方法让图像采样变得更加高效,因为它避免了每次处理边界时需要做额外的判断。通过这种填充,图像能够正确地平铺并渲染,而无需在每次处理边界时都增加额外的逻辑判断。
总结来说,这个"填充"是规范要求的,并不是随意的,它的目的是提高图像渲染效率,特别是在双线性采样和处理边界时。
我应该停止使用模板来做容器,而永远使用void*吗?
关于是否应该停止使用模板容器而改用 void*
,讨论的关键在于如何高效地管理容器。在某些情况下,比如在特定的游戏引擎开发中,可以采用元编程的方式来处理容器。这种方式比使用模板和 void*
更具优势,因为它避免了 C++ 中模板和 void*
的复杂性和限制。
在这个环境下,元编程被认为是一种更高效、可控的做法。通过元编程,可以生成专门为特定任务定制的代码,而不是依赖通用的模板或者 void*
,这些往往带来不必要的复杂性和性能问题。对于普通的游戏开发,虽然可能不需要使用元编程,但如果能够掌握元编程技巧,能够为未来更复杂的任务打下基础。
然而,在一些较为简单的开发环境下,直接使用 void*
可能会比复杂的模板方案更容易实现,特别是在需要处理大量不同类型数据时。对于游戏开发的核心技术,可以通过自定义编程方式,避免依赖模板和 void*
,通过减少不必要的抽象和复杂性来提高效率。
总体来说,模板和 void*
的使用都被认为是有局限性的,而元编程作为更高层次的技术手段,能够带来更好的控制和效率,因此如果要进行更复杂的开发工作,掌握元编程技术是必不可少的。