当前位置: 首页 > news >正文

游戏引擎学习第153天

仓库:https://gitee.com/mrxiao_com/2d_game_3

回顾

目前正在进行的是一个比较大的系统调整,原本预计今天会继续深入这个改动,但实际上在昨天的开发中,我们已经完成了大部分的代码编写,并且运行之后几乎一切都能正常工作,只出现了一些小问题。因此,今天的主要任务是进行一些优化和调整,以确保所有部分都能顺利运行。

当前的工作重点是迁移到统一的资源文件系统。之前,游戏是直接从磁盘上随机加载位图(bitmap)和音频(wav)文件,采用的是较为简单的资源管理方式。而新的目标是将这些资源整合到一个统一的资产包中,每个资产包可以包含任意数量的游戏资源,同时包含它们的元数据,例如资源的用途、加载时机等信息。

在游戏启动时,它会扫描指定目录下的所有资源文件,并将它们合并为游戏运行所需的最终资源集合。这种方式的优势在于,游戏的所有资源都可以被打包在一起,便于分发和管理,同时还能提高加载效率。

昨天的主要进展是完成了这一资源管理方式的基础架构,原本的文件 API 只能一次性读取完整的文件,现在已经调整为可以分块读取文件的内容。这部分工作已经全部完成,接下来的任务是进行一些调整和修正,以确保整个系统能够稳定运行。

今天的计划

现在要做的事情是回到代码中进行一些修正,因为在资源管理的过程中,资产数据的排列方式可能存在一些问题,同时可能还存在一些小的 bug。虽然之前的代码在第一次运行时基本上能够正常工作,但仍然有部分逻辑可能不太正确,因此需要深入调试,确保所有内容都按照预期运行。

目前还没有真正使用调试器进行逐步检查,因此今天的主要任务是回到代码中,清理并修正所有可能的问题,确保所有部分都能够顺利运行。完成这些调整后,下一步的目标是进行更深入的测试,具体来说,就是测试多个资源文件的合并。

现在已经有一个测试程序,它能够写入一个测试用的资源文件。接下来的改进是在这个测试程序的基础上,使其能够写入多个独立的资源文件,并确保游戏能够正确地加载和合并这些资源文件,而不会出现任何错误。这是当前系统优化的下一步逻辑目标,因为虽然代码已经写好了,但在实际运行之前,无法确定它是否真正可行,因此需要进行验证。

猜测上次流的错误来源

目前的情况是,运行游戏时发现了一些异常,虽然整体上看起来是正常的,声音也能够正确播放,但仍然有一些细节不太对劲。比如,当游戏运行时,声音数据能够被正确地流式加载和播放,所有音效似乎都正常工作。然而,画面上却出现了一些奇怪的现象,例如阴影完全消失了。

根据现象进行推测,可能的原因是加载资源文件时,忽略了 asset 0 这个特殊的空资源(null asset)。通常情况下,asset 0 作为一个特殊标识,不会被正常使用,而阴影可能被错误地分配到了 asset 0 这个位置。因此,当程序请求阴影资源时,返回的是 asset handle 0,但系统知道 asset 0 是空资源,因此不会返回任何东西,导致阴影无法显示。

除了阴影的问题,其他资源似乎都能正确加载并识别,包括角色的头部、躯干、腿部,以及地面的贴图和树木等所有位图资源。因此,目前的主要问题就是确定阴影丢失的具体原因,并修正 asset 0 的分配错误。

从昨天的运行情况来看,初步判断可能确实是因为忽略了 asset 0,但仍需进一步确认并修复问题。接下来的步骤是深入检查资源加载流程,并确保所有资源都能正确分配到合适的索引位置。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

检查测试资产构建器

接下来的工作是重新检查 test_asset_builder,重点是回顾资产文件的创建过程,特别是 asset 0 的处理方式。目前对之前的代码细节没有完全记忆清楚,因此需要快速浏览一遍,确保一切按照预期执行。

从代码来看,当前的实现是将 AssetCount 设为 1,这意味着会预留 asset index 0 的位置,实际上不会存放任何资源数据。这就导致 asset 0 为空资源(null asset)。不过,这样的设计是否合理需要进一步思考。

最初的想法是,不应该让资源打包器(asset bundler)保留 slot 0 为空,因为资源打包器本身并不需要这样做。然而,考虑到文件内部的资源引用机制,如果某些地方需要引用 null 资源,它们必须有一个明确的 null 位置,所以 asset 0 的空缺可能是合理的。因此,当前的结论是,这个位置应该继续保留,而 asset 0 需要被明确标记为一个无效资源,不能被加载或使用。

这也意味着,在 game_asset 相关的代码中,需要确保正确处理 asset 0,不能误将其当作正常资源使用。同时,所有逻辑都要意识到 asset 0 是一个特殊的无效资源,以免错误地加载或引用它。

回到代码分析,从 test_asset_builder 的实现来看,可以大致推测当前存在的问题:

  1. 资源计数错误:资产文件的 AssetCount 设置可能存在问题,导致 asset 0 位置的处理不当。
  2. 加载逻辑缺陷:在资源加载时,可能没有正确考虑 asset 0,导致某些资源错误地被存放在这个位置,例如阴影资源丢失的问题。

接下来的步骤是深入检查 test_asset_builder 的实现,确认 asset 0 的位置是否被正确跳过,并调整 game asset 代码,确保加载资源时能够正确识别并处理 asset 0
在这里插入图片描述

资产数量少了 1,且没有加载空资产

当前代码中的一个问题是,在处理资产文件时,实际加载的资源数量比预期的少了一个,这个问题已经可以明确原因,无需进一步调查。

问题分析

  1. 资源数量计算偏差
    在读取 .HHA 资产文件时,程序会计算 AssetCount,但这个 AssetCount 实际上是 实际资产数量 +1,因为它包含了 asset 0 这个特殊的空资源(null asset)。例如,如果游戏中实际有 50 个资源,那么 AssetCount 会显示为 51,因为 asset 0 也被计入其中。

  2. 资产加载过程中跳过 asset 0
    在真正加载资源时,程序会遍历所有资源,但只加载那些具有有效类型的资源(valid asset types)。合并资产时,asset merge 逻辑默认会忽略无效类型的资源,而 asset 0 并没有被归类到任何有效的资源类型中,因此它不会被加载。

  3. 导致的结果
    由于 asset 0 在合并过程中被跳过,最终加载的资源数量总是比 AssetCount 少 1。换句话说,如果 AssetCount 是 51,那么最终加载的资源数只有 50,而 assert 语句会检测到这个不匹配,并导致断言失败。

解决方案

修正 AssetCount 的计算,确保预期加载数量与实际加载数量匹配。

  • asset merge 逻辑中,需要明确跳过 asset 0,但同时调整 AssetCount 计算方式,使其反映真正应该加载的资源数量。
  • 或者,在执行 assert 检查时,考虑 asset 0 的特殊情况,避免误报错误。

接下来的任务是修改 test_asset_builder 以及资源加载逻辑,以确保 asset 0 被正确处理,同时不会影响其他资源的加载。

修正资产数量

问题分析与修正方案

在当前的 HHA 资产管理逻辑中,asset count 计算方式存在问题,导致加载的资源数量与预期不符。这主要源于 asset 0(空资源,null asset)的处理不当。

问题 1:文件中的 asset count 需要调整
  • 由于 HHA 资产文件的第一项始终是 null asset,所以 asset count 计算时应当减去 1,以排除 asset 0
  • 例如,若 HHA 文件声明了 51 个资产,其中 asset 0 是无效的空资源,那么实际需要加载的资源数应为 50。

修正方案

  • 在计算 asset count 时,明确减去 1,以确保最终合并计算出的 asset count 只包含有效资源。
  • 这样,如果存在多个 HHA 文件,就不会因为每个文件都包含一个 null asset 而导致最终计数错误。例如,如果有 3 个 HHA 文件,错误的计算方式会导致 asset count 多 3 个,而正确的方法确保 null asset 只计算一次,不随文件数量增加。

问题 2:资产加载起始索引错误
  • 代码中当前的加载逻辑是从 asset 0 开始加载,但 asset 0 是空资源,不应被加载。
  • 结果导致每个 HHA 文件都额外添加了一个 null asset,从而导致资源数组出现多个 null asset,而非只保留一个。

修正方案

  • 调整索引起点:在处理资产加载时,从 asset 1 开始,而不是 asset 0,确保 null asset 仅存在一个,不随 HHA 文件的数量增加。
  • 保证唯一性:不管有多少个 HHA 文件,都确保只存在一个 null asset,避免多个 null asset 影响资源管理。

最终修正措施

  1. 调整 asset count 计算方式,从 HHA 文件读取 asset count 时减去 1,以排除 asset 0
  2. 修改资源加载逻辑,确保 null asset 只出现一次,而不是随着 HHA 文件数量增长而增加多个 null asset
  3. 调整索引起点,从 asset 1 开始加载有效资源,避免误加载 asset 0

预期结果

  • 资源数量计算准确,避免因 null asset 额外增加导致计数错误。
  • 资源数组中仅包含 一个 null asset,而不是每个 HHA 文件都产生一个。
  • 资源加载顺序正确,不会因错误的索引导致资源丢失或排列错误。

接下来,需要修改代码并进行测试,确保修正后的 asset count 计算和资源加载逻辑符合预期。
在这里插入图片描述

在这里插入图片描述

构建空资产

当我们真正开始加载资源时,会遇到一个问题:资源计数从零开始,但实际上我们需要保留这个位置给空资源(null asset)。因此,我们首先需要创建一个空资源。具体来说,我们应该在这里生成一个空资源,执行一个零初始化操作。

我们的目标是确保第一个资源,即 assets[asset + asset_count],被清零。无论该资源是什么,我们都要将其内容全部清除,使其变成一组全零的数据。理论上,程序运行时不应该真正访问这个空资源,但为了安全起见,我们确保它是空白的。

在完成清零之后,我们需要将资源计数 asset_count 增加 1,以保证所有后续资源的索引正确对齐。因此,我们要明确地保留一个空资源作为占位符,确保所有资源在文件中的排列符合我们的预期。这将解决之前的问题,使资源的存储和访问更加一致、合理。
在这里插入图片描述

在这里插入图片描述

一切正常

现在阴影已经恢复显示,并且不会再触发断言错误,因此当前的状态相比之前更稳定,可以继续进行后续的开发和测试。

之前在运行时,阴影缺失的问题让我们意识到资源加载过程中可能存在索引偏移的错误。经过分析,我们发现每个 HHA 资源文件的第一个槽位是预留的空资源(null asset),但在合并多个资源文件时,我们错误地计算了资源索引,导致阴影资源被错误地映射到空资源的位置。

为了解决这个问题,我们调整了资源计数和索引的计算方式:

  1. 正确计算资源总数

    • 由于每个 HHA 文件的第一个槽位是空资源,因此在计算总资源数时,我们需要减去这些额外的空槽位,以确保正确分配资源索引。
  2. 正确初始化空资源

    • 在加载资源之前,我们手动创建一个空资源,并确保它被正确清零,以防止程序访问时出现未定义行为。
    • 这样做的目的是保证空资源始终存在,但不会干扰实际游戏资源的加载和使用。
  3. 修正资源索引偏移

    • 在合并多个 HHA 资源文件时,我们确保只使用一个全局的空资源,而不是每个文件都保留一个空资源,这样可以避免索引错位的问题。

经过这些调整后,阴影资源得到了正确加载,所有其他资源也都能正确地识别和使用。这样,我们就可以更加顺利地继续开发,确保游戏的资源系统运行稳定。

测试资产合并

现在资源系统的代码看起来是正常工作的,但目前仅加载了一个 HHA 资源文件,因此我们还不能确定资源合并机制是否真的稳定可行。一旦增加第二个 HHA 文件,合并过程可能会出现问题,甚至可能完全崩溃。因此,接下来的重点是测试多个 HHA 资源文件的合并,以确保系统能够正确处理多个文件,而不会导致数据错乱或加载失败。

目前的资源合并逻辑仍然比较基础,实际上它仍然是按照原来的方式逐个加载资源,而没有进行真正的合并操作。因此,如果在多个 HHA 文件之间存在相同资源的情况,我们需要检查系统是否能够正确处理这些重复资源,确保资源不会被错误地覆盖或遗漏。

此外,在使用开发设备时,意外触碰到了 Wacom 数位板的触控区域,导致滚动异常。可能需要考虑禁用该功能,以避免开发过程中发生类似的误操作,从而影响工作效率。

什么是Wacom 数位板
Wacom 数位板是一种用于数字绘画、设计和手写输入的专业输入设备。它通过一个平板和一支专用的触控笔来实现高精度的手写或绘画操作。Wacom 数位板常被艺术家、设计师、插画师等创意专业人士使用,因为它提供了比传统鼠标更自然的绘图体验。

Wacom 数位板的工作原理是,当触控笔在板面上移动时,它会感应到笔尖的位置和压力变化,从而实时转换成数字信号。这使得使用者能够在屏幕上进行精确的绘图、上色、修图等操作,同时也可以用来进行文字输入等任务。Wacom 的产品通常具有非常高的精度和响应速度,适合需要高精度输入的创意工作。
在这里插入图片描述

考虑空标签

在处理资产时,遇到了类似的情况,即需要为标签保留一个“空标签”。与处理资产文件类似,需要确保第一个标签槽位是空标签(即保留槽位),并且在计算标签数量时,不计算这个空标签。因此,标签的计数应该从1开始,而不是从0开始。

在文件处理过程中,发现需要首先为每个标签生成一个空的标签,并将其清零,确保它不会被实际加载。然后,在处理标签时,标签数量需要减去1,因为第一个标签实际上是一个空标签。此时,代码中的处理逻辑并不完全正确,因为标签的总数在实际加载时应该是减去空标签的数量。

为了修正这个问题,需要做出几个修改:

  1. 标签计数的调整:首先确保标签的计数不包括空标签,因此标签计数需要减去1。
  2. 跳过空标签:在读取标签时,需要跳过第一个标签,即空标签。
  3. 标签重定位:当标签的基址被调整时,空标签的特殊情况需要额外处理。如果第一个标签是空标签,则将所有标签映射到空标签的位置;如果不是空标签,则根据标签基址重新定位标签。

由于这种复杂性,标签的处理在加载时可能会有一些不太直观的情况,但这在数组合并时是常见的,需要特别注意处理空标签的特殊位置。

总体来说,虽然这种处理方法有些复杂,但它在加载时不会影响正常的操作,而且只需要在加载时仔细验证和测试就可以确保其正确性。因此,虽然在实现上有些繁琐,但整体来说这是可以接受的,并且在后续的测试中可以进一步验证其稳定性。
在这里插入图片描述

将测试资产文件拆分以测试合并过程

在进行资产测试时,首先决定将一个HHA文件拆分成两个文件,以便验证是否能够正确处理和合并它们。为了实现这一点,首先提取了写文件的代码,并将其抽象为一个函数,这样就可以在需要时多次调用它。通过这种方式,可以将重复的文件写入操作提取成函数,简化后续的测试。

接下来,将文件拆分为两个部分,分别处理其中不同的资产。例如,将某些资产分配到一个文件中,而将其他资产分配到另一个文件中。特别地,有人提议将所有声音资源放在一个文件中,因此决定将所有声音放入一个单独的资产文件中,而将其他资源(如音乐)分配到不同的文件中。

这样做的目的是测试资产合并的过程,确保多个资产文件能够正确加载和合并。在此过程中,还对一些初始化操作进行了抽象,使得代码更加整洁和可维护。通过初始化资产的功能,简化了每次测试所需要的准备工作。

完成代码编写后,运行了测试资产构建器,生成了三个测试文件(test1, test2, test3)。然后,删除了原有的测试文件,并运行了新生成的代码,检查是否能够成功生成这些文件。最后,验证这些生成的文件是否能够正确加载,并进行资产合并测试,确保功能按预期工作。

通过这些步骤,确保了拆分和合并资产文件的功能正确实现,并为后续的调试和验证提供了有力支持。
在这里插入图片描述

只加载其中一个文件

首先,决定不进行第一次完整的测试,而是仅加载其中一个文件进行测试。目标是检查在该文件中加载的资产是否能正常显示,而其他文件中的资产不应显示。具体来说,在加载的文件中包含英雄的头部、披风、上身和四个方向的模型,因此期望只看到英雄及其相关部分(如披风、上身)显示,而不显示其他内容,如环境或阴影。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

test_asset_builder.cpp中未初始化 变量读出来可能是随机值

测试合并代码。仍然存在错误

现在,尝试调试合并代码。表面上看似一切正常,但并没有完全确认,特别是在加载声音的过程中出现了问题。出现了一个无效的ID,这意味着在资产文件中,程序认为有一个有效的ID,但是实际并没有这么多的资产,显然是加载代码中的问题。

问题发生在加载声音的预取过程中,错误显示的ID完全无效,可能是因为音乐资产没有被正确处理。分析后认为可能的原因有两个:首先,在合并资产时,相关的ID并没有更新。其次,问题可能出在创建声音资产时,相关的ID没有正确初始化。虽然从代码中看,NextIDToPlay->NextIDToPlay 值似乎已经正确初始化,但在添加声音时,代码中其他部分的初始化可能出了问题。

接下来,重点检查加载资产文件的部分。特别是,声音的“NextIDToPlay”这个值的映射问题。因为在合并多个文件时,这个ID需要重新映射,而当前系统并没有办法处理这种情况。通过这个分析,确认问题确实正如最初所猜测的那样,错误的值正是由于在合并过程中未正确处理ID导致的。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

重新映射下一个播放 ID 以考虑多个资产文件

在处理多个资产文件时,标签(tags)数组会被合并,原本在不同文件中的标签可能会映射到不同的编号。例如,标签0的内容可能会在合并后变成多个标签0、标签1、标签2,依此类推,这就涉及到了标签的重新映射。合并后,资产中的标签会对应新的编号,确保资产指向正确的标签位置。合并操作能够确保所有资产指向正确的标签。

然而,问题在于资产之间的引用没有完全被考虑到。虽然标签映射是正确的,但如果一个资产指向另一个资产,这种引用关系并没有得到处理。比如,当资产A引用资产B时,经过合并后,可能会指向错误的位置。特别是对于声音(sound)资产,它们有一个指向下一个声音ID的指针,这个指针也需要被重新映射,否则会发生错误。

在原始文件中,声音ID可能是指向一个有效的声音资源,例如ID为16的声音指向ID17的声音。合并后,这些ID会重新分配,因此它们需要进行映射,以确保指针指向新的有效位置。如果没有重新映射,就会出现指向错误资源的问题,可能会加载一个完全不同的资产(如图像或其他类型的资产),这就是加载时出现垃圾值的原因。

为了修复这个问题,需要在加载资产时进行指针的重新映射。加载代码必须能够判断一个资产是否为声音类型,并且知道它的指针指向哪个新的资产。例如,通过检查资产类型ID,确定当前资产是否属于声音类型,并根据这一信息对“下一声音ID”进行重新映射。

具体来说,代码可以通过检查一个资产类型ID是否属于声音类别来决定是否需要重新映射。如果是声音资产,那么就需要根据新的基础偏移量对“下一个声音ID”进行调整,以确保它指向正确的声音资源。这样,所有的声音资源就会按照正确的顺序加载,而不会出现错误指向。

然而,这种方法存在一个局限性。如果一个资产的“下一声音ID”指向的资产属于其他类型(如图像),这种重新映射就会失效。为了更好地处理这种情况,可以引入一个资产映射表,将不同类型的资产映射到正确的位置。通过这个映射表,在加载过程中根据类型进行准确的指针调整,避免了指向错误资源的问题。

尽管这种方法相对简单,但它可能带来性能问题,特别是在需要频繁查找映射表时,这种额外的查找操作会增加复杂性。因此,虽然这个方法可以解决问题,但并不是最佳的解决方案。
在这里插入图片描述

在这里插入图片描述

决定不重新映射下一个播放 ID,而是显式地循环和链接声音

在处理声音资产时,为了避免复杂的指针重映射,可以采用一种更简单的方式来管理声音的播放和循环。原本通过“NextIDToPlay”来处理声音的播放链,但这会引入复杂的重映射过程。为了解决这个问题,可以设计一个新的方法,使得“NextIDToPlay”变得更为简洁和专用。

新的方法不再使用复杂的ID重映射,而是通过一个枚举值来指定声音操作的类型。这个枚举值可能包括几种操作:例如“无操作”(none)、“循环播放”(loop)、“继续播放下一声音”(advance)等。这样,在声音播放时,根据这些枚举值来决定如何播放下一个声音,避免了以前那种复杂的指针重映射。

具体来说,在文件格式中,可以替换“NextIDToPlay”为一个新的枚举值,比如“HHA->Sound.Chain”。通过这种方式,声音播放操作可以更直接地表达为播放、循环或继续播放下一个声音。例如,当音乐播放完成时,如果需要播放下一个音效,可以通过设置操作为“advance”来指示播放下一个声音。这样,代码的结构更加简洁,也避免了复杂的资产间引用问题。

此外,为了实现这个功能,程序可以检查当前播放的声音是否为最后一个音效。如果不是最后一个音效,就通过设置操作为“advance”来播放下一个音效。这种方式可以使得声音的处理更加流畅,并且在不需要复杂重映射的情况下实现连续播放的效果。

在实现过程中,可以简化音乐和声音处理的混合器(mixer)。如果声音链操作指示需要“继续播放”或“循环”,程序可以根据枚举值来进行处理,而无需依赖复杂的ID映射。通过这种方式,声音的管理变得更加直观和清晰,代码也变得更加易于维护。

总之,改进后的方法通过使用枚举值来简化声音播放的控制,避免了原本复杂的ID重映射过程,使得系统更加高效且容易管理。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

实现 GetNextSoundInChain

在这里插入图片描述

现在需要做的主要工作是修复一个函数,使它能够返回一个声音 ID。具体来说,程序会接受一个声音 ID,然后获取该 ID 对应的声音信息。如果没有找到对应的声音,可以假定返回值为空,表示没有声音跟随当前的声音。如果提供的 ID 无效,程序会验证这个 ID 是否有效,然后获取该 ID 对应的声音信息。

对于获取到的声音信息,接下来会根据不同的链式操作类型进行处理。使用条件判断(如 ifswitch)来根据不同的链式操作类型(如 “无操作”、“循环” 或 “前进”)来决定返回何种操作。如果是“无操作”,程序什么都不做;如果是“循环”,则返回当前的声音;如果是“前进”,则将当前的 ID 增加 1,返回下一个声音 ID。

通过这种方法,程序就不再需要处理复杂的资产重映射。声音加载和播放将按链式规则正常工作。接下来需要调试这一部分代码,确保不会出现新问题。由于数据结构发生了变化,需要重新运行导出器(exporter),以确保新的数据结构能够正确导出并设置。

修复这些问题后,程序变得更为简洁和高效,不再需要大量的手动书写和复杂的操作,避免了不必要的繁琐工作。现在,程序能够按预期进行工作,避免了此前资产重映射所带来的复杂性。

接下来计划的是进行 QA 测试,确认程序是否按预期运行,并且没有出现更多的问题。QA 测试会检查程序的稳定性和是否存在其他潜在的问题。至于接下来的工作,会集中在实现一个新的功能,处理 Win32 系统中的文件操作,这对于文件管理和操作非常重要。由于这部分工作相对复杂,开发人员希望以合适的方式实现它,因此需要更多的准备和规划。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

可以先做advance然后再做循环声音吗?

可以实现“advance”和“循环”声音的组合。每个声音都可以独立设置这些值,因此可以自由组合,不存在任何限制。如果没有特定的需求,单纯地想要尝试一些新的功能,完全可以进行实验。比如,在进行学习时,不必总是专注于完成具体的任务或目标,反而可以通过尝试不同的功能,探索更多的可能性,这有助于提高自己的编程能力。

一种可能的做法是,可以将“链式操作”更具体化,而不仅仅是用一个 uint32 值表示。可以将其拆解成两个部分:一个是命令类型(比如“无操作”、“循环”或者“前进”),另一个是计数器。例如,如果设置为“循环”,则可以设置一个循环计数器,在声音播放的代码中,每次播放相同的声音时,都会增加计数器的值。每次播放时,检查声音的当前循环次数,如果超过预定次数,则执行“前进”操作。

通过这种方法,可以实现更复杂的功能,比如“前进-前进-循环-循环-前进”这样的音频序列。虽然这样做可以实现一些非常有趣的功能,但通常在实际开发中并没有太多的实际需求。这种实现方式更多是为了实验和探索。如果只是为了学习和理解编程原理,这样的尝试是非常有价值的。

如果你做 id.value += 1,你最终不会循环到最后一个声音资产吗?

这个问题的关键是防止在播放完最后一个音频资源时出现无限循环。实现的思路是:在播放每个音频时,先设置为“前进”状态,不断播放下一个音频,直到最后一个音频。当播放到最后一个音频时,状态会被设置为“无操作(none)”,从而结束循环。这样可以避免无限循环播放。

如果出现循环未结束的问题,那么可能是资产构建时出现了bug,因为音频播放控制逻辑是设置为“前进”直到最后一个音频,最后才结束。而如果存在多个bug,可能会导致播放逻辑没有正确终止,尤其是当音频播放速度加快时,问题可能更容易复现。

检查在音调偏移的声音中,当 SamplesPlayed 超过 SamplesCount 时引发的断言

目前遇到的问题是关于声音播放结束时的精度问题。样本播放的位置设置为结束样本位置,但实际上样本位置并没有准确到达音频的结尾,通常会稍微短一些。经过查看,发现这是由于在计算总混音块时,使用了浮点数精度问题,导致在某些情况下音频没有完全播放完毕。具体来说,当计算音频的总混音块时,存在一些舍入和截断的误差,导致最终结束的位置稍微提前了。

这个问题尤其在进行音高调整时更为明显,但通常不会对音效产生太大影响。尽管如此,它还是带来了一些小的瑕疵,可能会导致音频播放的结束点不完全正确。为了解决这个问题,可能需要回头重新审视和优化音频块的计算方式,确保在每次播放时都能精确地处理这些细节,避免任何潜在的误差。

此外,当迁移到新的资源文件处理系统时,也引入了一些新的小故障,尤其是音频结束处理的部分。这些问题还需要进一步修复和优化,以确保音频处理的稳健性,并确保音效的结尾部分正确无误。因此,接下来可能需要更多时间来清理这些问题,确保声音系统的每个环节都能够无误地运行。
在这里插入图片描述

下一步计划是什么?

接下来计划做的事情主要集中在两个方面。在处理完资产系统之后,接下来的工作将是实现调试功能和灯光系统。

首先,调试功能是目前任务列表中的一个重要内容。随着游戏复杂性的增加,调试功能变得非常必要。这包括能够绘制调试信息、显示调试输出以及开发调试用的HUD(用户界面显示)。这些调试基础设施将帮助开发过程中更容易地发现和解决问题。

第二个重要的技术任务是实现灯光系统。灯光对于游戏的视觉效果和氛围非常重要,因此需要在此阶段加以完善。

完成这两项任务后,团队将进行一些清理工作,修复现有的bug,并进一步巩固和优化引擎。这将确保引擎已经足够稳定,可以开始游戏原型的开发。接下来就可以着手进行游戏的核心内容开发,例如游戏的介绍部分、地图生成、战斗系统等功能的实现。

一旦这些基础工作完成,便可以进入更具体的游戏开发阶段,准备好开始制作游戏的各个部分。

你如何决定是修复一个 bug 还是继续前进?

在处理是否修复一个bug或者继续前进的问题时,实际的答案并不完全如在直播中展示的那样。最理想的做法是“立即修复bug”,这是生产环境中的最佳实践。通常在生产编程中,一旦发现bug,就应立即修复,除非:

  1. 代码正在被删除:如果你正处于删除某段代码的过程中,修复bug就没有意义,因为这段代码即将被移除。
  2. 正在修复其他bug:如果你正在处理另一个更紧急的bug,可能暂时无法解决当前的bug,但这是唯一可以不立即修复bug的情况。

除了这两种情况外,其他情况下应该始终立即修复bug。这是一个明确的规则。如果决定不修复bug,必须确保这段代码不再使用,或者会被删除。

然而,有时为了教学需要,会做出一些妥协。由于时间和内容的限制,有时会将一些事情推迟处理,而不遵循最佳的编程实践。直播的目标是教学,但也需要考虑如何更好地安排每一部分的内容。因此,有时候虽然发现了bug,但为了不打断教学进程,可能会暂时不修复,而选择将其放在稍后的时间处理。

例如,在音效代码中,虽然发现了bug,但为了继续教学资产管理代码的部分,暂时不会处理音效的bug。教学过程中需要做出一些妥协,以确保观众能够跟得上当前的教学进度,但这并不意味着这种做法是最佳的开发实践。

如果我决定将来攻读博士学位,能否获得你写关于压缩导向编程(Compression-Oriented Programming)的祝福?

对于未来的博士研究,关于压缩或编程相关的内容,完全不需要我的许可。压缩导向编程是我非常希望更多人去做的事情,我很高兴听到有人愿意在这方面写作并进行研究。希望更多人能从事这类工作。

相关文章:

游戏引擎学习第153天

仓库:https://gitee.com/mrxiao_com/2d_game_3 回顾 目前正在进行的是一个比较大的系统调整,原本预计今天会继续深入这个改动,但实际上在昨天的开发中,我们已经完成了大部分的代码编写,并且运行之后几乎一切都能正常工作&#x…...

CentOS7下安装MongoDB

步骤 1:创建 MongoDB Yum 仓库文件 你需要创建一个 MongoDB 的 Yum 仓库配置文件,以便从官方源下载 MongoDB。打开终端并使用以下命令创建并编辑该文件: sudo vi /etc/yum.repos.d/mongodb-org-7.0.repo 在打开的文件中,输入以下…...

Elasticsearch-07-Elasticsearch Java API Client-Elasticsearch 8.0 的高阶api

文章目录 es8 API基础配置和bean注入高阶使用1:引入elasticsearchClient2:查询所有索引3:查询某个索引4:创建索引5:删除指定索引6:查询索引的映射7:创建索引指定映射8:创建文档使用HashMap作为数据存储容器使用自定义类作为数据存储容器使用外…...

【性能优化】MySQL 生产环境 SQL 性能优化实战案例

🚀 MySQL 生产环境 SQL 性能优化实战案例 🏗️ 背景介绍 最近在处理一个项目时,发现在生产环境的工作流相关接口中,某些查询的执行时间异常缓慢,尽管数据量仅为 2 万条。经过分析,发现以下 SQL 语句执行非…...

Docker容器安装软件(完整版)

文章目录 一、安装Docker1.1 docker 相关的命令1.2 配置镜像加速 二. 安装es2.1 创建网络2.2 拉取镜像2.3 创建挂载点目录2.4 部署单点es,创建es容器2.5 编写elasticsearch.yml2.6 重启es容器2.7 测试Elasticsearch是否安装成功 三. 基于Docker安装Kibana3.1 拉取镜…...

DeepSeek-进阶版部署(Linux+GPU)

前面几个小节讲解的Win和Linux部署DeepSeek的比较简单的方法,而且采用的模型也是最小的,作为测试体验使用是没问题的。如果要在生产环境使用还是需要用到GPU来实现,下面我将以有一台带上GPU显卡的Linux机器来部署DeepSeek。这里还只是先体验单…...

11. Pandas :操作Excel文件(Excel报表的案例研究)

从一个装有各种 Excel 文件的文件夹开始,这些文件需要被整合到 Excel 报表中。 它们包含了虚构的电信运营商在全美各营业厅的套餐(金、银、铜)销售情况。每个月有两个文件,子文件夹 new 中的是新用户,子文件夹 existin…...

Qt开源控件库(qt-material-widgets)的编译及使用

项目简介 qt-material-widgets是一个基于 Qt 小部件的 Material Design 规范实现。 项目地址 项目地址:qt-material-widgets 本地构建环境 Win11 家庭中文版 VS2019 Qt5.15.2 (MSVC2019) 本地构建流程 克隆后的目录结构如图: 直接使用Qt Crea…...

freeswitch(多台服务器级联)

亲测版本centos 7.9系统–》 freeswitch1.10.9本人freeswitch安装路径(根据自己的路径进入)/usr/local/freeswitch/etc/freeswitch使用场景: 使用服务器级联需要双方网络可以ping通,也就是类似局域网内,比如A服务器IP 192.168.1.100 B服务器 192.168.1.101,通过C设备注册…...

【大模型统一集成项目】让 AI 聊天更丝滑:WebSocket 实现流式对话!

🌟 在这系列文章中,我们将一起探索如何搭建一个支持大模型集成项目 NexLM 的开发过程,从 架构设计 到 代码实战,逐步搭建一个支持 多种大模型(GPT-4、DeepSeek 等) 的 一站式大模型集成与管理平台&#xff…...

qt 多进程使用共享内存 ,加速数据读写,进程间通信 共享内存

Summary: 项目中我们有时需要使用共享内存共享数据,这样,数据不用进程IO读写,加进数据加载和落地; 程序退出时,再保存到本地;速度提升数十倍; Part1:QSharedMemory Windows平台下进程间通信…...

OpenHarmony-分布式硬件关键技术

前言: OpenHarmony是一款面向未来万物互联场景的操作系统,其设计采用了分布式架构。那么OpenHarmony相比于传统操作系统有哪些关键的分布式技术,本文主要介绍分布式硬件设计理念、跨端分布式硬件核心挑战、以及OpenHarmony分布式硬件平台关键…...

idea超级AI插件,让 AI 为 Java 工程师

引言​ 用户可在界面中直接通过输入自然语言的形式描述接口的需求,系统通过输入的需求自动分析关键的功能点有哪些,并对不确定方案的需求提供多种选择,以及对需求上下文进行补充,用户修改确定需求后,系统会根据需求设…...

深入Flink运行时架构:JobManager与TaskManager协作全解析

深入Flink运行时架构:JobManager与TaskManager协作全解析 一、Flink分布式执行模型剖析 1.1 运行时架构全景视图 核心组件交互关系: #mermaid-svg-tMSqMSsKP6vwUZi3 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-s…...

OSPF-单区域的配置

一、单区域概念: 单区域OSPF中,整个网络被视为一个区域,区域ID通常为0(骨干区域)。所有的路由器都在这个区域内交换链路状态信息。 补充知识点: OSPF为何需要loopback接口: 1.Loopback接口的…...

每日OJ_牛客_过桥_贪心+BFS_C++_Java

目录 牛客_过桥_贪心BFS 题目解析 C代码 Java代码 牛客_过桥_贪心BFS 过桥 描述: dd被困在了一个迷幻森林,现在她面前有一条凶险的大河,河中央有n个神奇的浮块,浮块按1∼n1顺序标号,但两两并不相接&…...

K8S学习之基础二十七:k8s中daemonset控制器

k8s中DaemonSet控制器 ​ DaemonSet控制器确保k8s集群中,所有节点都运行一个相同的pod,当node节点增加时,新节点也会自动创建一个pod,当node节点从集群移除,对应的pod也会自动删除。删除DaemonSet也会删除创建的pod。…...

79.ScottPlot的MVVM实现 C#例子 WPF例子

如何通过数据绑定在 WPF 中实现动态图像显示 在 WPF 应用程序中,通过数据绑定实现动态图像显示是一种高效且优雅的方式。以下是一个简单的教程,展示如何使用 ScottPlot.WPF 库和 MVVM 模式来实现这一功能。 第一步:安装必要的 NuGet 包 首…...

第44天:WEB攻防-PHP应用SQL盲注布尔回显延时判断报错处理增删改查方式

时间轴: 44天知识点总结: 1.mysql的增删改查功能 2.根据源码sql语句的三种sql注入:布尔盲注(必须要有回显) 延时判断(都可以) 报错回显(必须要有报错处理机制) 3.两个cms…...

说说人工智能

1. 人工智能与机器学习 核心进展 人工智能(AI)与机器学习(ML)已从理论研究全面渗透到实际应用中。深度学习模型如Transformer架构在自然语言处理(NLP)和计算机视觉(CV)领域实现突破…...

懒加载(Lazy Loading):原理、实现与优化策略

懒加载(Lazy Loading) 是一种优化网页性能的技术,主要用于延迟加载非关键资源(如图片、视频、脚本等),直到它们真正需要被使用时才加载。懒加载可以显著减少页面初始加载时间,降低带宽消耗&…...

HTML5(Web前端开发笔记第一期)

p.s.这是萌新自己自学总结的笔记,如果想学习得更透彻的话还是请去看大佬的讲解 目录 三件套标签标题标签段落标签文本格式化标签图像标签超链接标签锚点链接默认链接地址 音频标签视频标签 HTML基本骨架综合案例->个人简介列表表格表单input标签单选框radio上传…...

Linux学习(十五)(故障排除(ICMP,Ping,Traceroute,网络统计,数据包分析))

故障排除是任何 Linux 用户或管理员的基本技能。这涉及识别和解决 Linux 系统中的问题。这些问题的范围包括常见的系统错误、硬件或软件问题、网络连接问题以及系统资源的管理。Linux 中的故障排除过程通常涉及使用命令行工具、检查系统和应用程序日志文件、了解系统进程&#…...

SVN 拉取,文件冲突 解决办法

情景 svn 在拉取代码时 提示 已跳过,其余有冲突 ,警告至少还有一个的文件处于冲突状态 导致文件拉取失败 一、原因 版本库和本地工作副本之间存在文件冲突,导致文件无法正常拉取。 二、 Terminal 窗口解决办法 1.查看冲突文件 在 Termin…...

【实战ES】实战 Elasticsearch:快速上手与深度实践-8.1.1基于ES的语义搜索(BERT嵌入向量)

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 基于Elasticsearch与BERT的语义搜索架构设计与实战1. 传统搜索的局限性与语义搜索的崛起1.1 关键词搜索 vs 语义搜索1.2 Elasticsearch向量检索演进历程关键版本特性对比 2.…...

【Node.js】--- win11安装 Node.js

在编程的艺术世界里,代码和灵感需要寻找到最佳的交融点,才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里,我们将共同追寻这种完美结合,为未来的世界留下属于我们的独特印记。 【Node.js】--- win11安装 Node.js 开发环…...

【技海登峰】Kafka漫谈系列(九)SpringBoot整合Kafka多数据源配置

【技海登峰】Kafka漫谈系列(九)SpringBoot整合Kafka多数据源配置 Kafka官方提供了基于Java实现的客户端kafka-clients,用于提供生产者和消费者的基本能力。在此基础上,Spring for Apache Kafka(spring-kafka)项目对该原生客户端进行了基于Spring特性的抽象与封装,实现了基…...

【MySQL篇】基本查询实战OJ

本篇是基于上篇mysql基本查询的一些OJ题 MySQL基本查询传送门:【MySQL篇】MySQL基本查询详解-CSDN博客 批量插入数据_牛客题霸_牛客网 insert语句 insert into actor values (1,PENELOPE,GUINESS,2006-02-15 12:34:33); insert into actor values (2,NICK,WAHLBER…...

侯捷 C++ 课程学习笔记:C++内存管理机制

内存管理从平地到万丈高楼 内存管理入门(Memory Management 101) 需要具有动态分配并使用memory(存储(器),(计算机的)内存),使用过C标准库的容器&#xff0…...

java后端开发day31--集合进阶(一)-----Collection集合List集合数据结构1

(以下内容全部来自上述课程) 1.集合体系结构 List系列集合:添加的元素是有序、可重复、有索引。 Set系列集合:添加的元素是无序、不重复、无索引。 2.Collection集合 Collection是单列集合的祖宗接口(不可直接创建…...

TA学习之路——1.4 MVP矩阵运算

1.变换矩阵的意义 1.将3D物体转化到2D平面 2.为各个空间的运用做准备 2.MVP矩阵代表什么 MVP矩阵分别是模型(Model)、观察(View)、投影(Projecttion)三个矩阵。我们顶点坐标起始于局部空间(Local Space)…...

Java数据结构第二十期:解构排序算法的艺术与科学(二)

专栏:Java数据结构秘籍 个人主页:手握风云 目录 一、常见排序算法的实现 1.1. 直接选择排序 1.2. 堆排序 1.3. 冒泡排序 1.4. 快速排序 一、常见排序算法的实现 1.1. 直接选择排序 每⼀次从待排序的数据元素中选出最小的⼀个元素,存放在…...

【机器学习】主成分分析法(PCA)

【机器学习】主成分分析法(PCA) 一、摘要二、主成分分析的基本概念三、主成分分析的数学模型五、主成分分析法目标函数公式推导(梯度上升法求解目标函数)六、梯度上升法求解目标函数第一个主成分七、求解前n个主成分及PCA在数据预…...

perl、python、tcl语法中读写Excel的模块

perl、python、tcl语法中读写Excel的模块 perl、python、tcl语法中存在读写xls和xlsx格式的模块分别有: python ‌读取 Excel‌ ‌xlrd‌:支持传统 .xls 格式的读取‌ pandas‌:通过 read_excel() 方法支持 .xls 和 .xlsx 格式‌ ‌写入 …...

libwebsockets实现异步websocket客户端,服务端异常断开可重连

libwebsockets websocket客户端基本流程网上都有,我只额外优化了重连机制。 在服务器异常断开时不触发LWS_CALLBACK_CLOSED或LWS_CALLBACK_CLIENT_CONNECTION_ERROR,导致无法自动重连 通过定时检查链接是否可写入判断链接是否有效 // 判断wsi是否可用if …...

CAD球体密堆积3D插件V2.0

插件介绍 CAD球体密堆积3D插件V2.0版本可在AutoCAD内建立球体堆积模型,插件采取模拟球体在重力作用下的堆积行为,可生成超密堆积的几何模型及进行堆积过程的动态展示。 插件优化重力堆积物理引擎,新增堆积可视化界面,可直观查看…...

【Linux】线程池、单例模式、死锁

线程池 一.线程池1.日志和策略模式2.线程池1.Task.hpp2.Thread.hpp3.ThreadPool.hpp4.ThreadPool.cc 二.线程安全与重入问题三.线程安全的单例模式1.饿汉模式2.懒汉模式3.懒汉模式线程池1.ThreadPool.hpp2.ThreadPool.cc 四.死锁的概念1.死锁2.死锁的四个必要条件3.避免死锁 五…...

AI+视频监控电力巡检:EasyCVR视频中台方案如何赋能电力行业智能化转型

随着电力行业的快速发展,电力设施的安全性、稳定性和运维效率变得至关重要。传统视频监控系统在实时性、智能化及多系统协同等方面面临严峻挑战。EasyCVR视频中台解决方案作为一种先进的技术手段,在电力行业中得到了广泛应用,为电力设施的监控…...

centos8.0系统部署zabbix6.0监控

centos8.0系统部署zabbix6.0监控 一、部署过程1、确认系统版本2、主机基础环境设置3、安装MySQL 8.0数据库3.1 安装MySQL 8.0仓库3.2 安装软件3.3 设置root用户密码3.4 创建zabbix数据库,授权用户 4、配置zabbix6.0仓库5、安装zabbix服务端软件6、导入zabbix数据表7…...

江科大51单片机笔记【12】AT24C02(I2C总线)

写在前言 此为博主自学江科大51单片机(B站)的笔记,方便后续重温知识 在后面的章节中,为了防止篇幅过长和易于查找,我把一个小节分成两部分来发,上章节主要是关于本节课的硬件介绍、电路图、原理图等理论知识…...

电脑一直重启怎么解决 原因及解决方法

电脑一直重启的故障状态,不仅影响电脑的正常使用,还可能导致数据丢失或损坏。那么,电脑一直重启是什么原因呢?又该如何解决呢?下面将为大家介绍电脑一直重启的常见原因和解决方法,帮助您恢复电脑的正常工作…...

内网安全防护新思路 —— HFish + ELK 与 T-Pot 全面蜜罐系统比较分析

在当前网络安全环境日益复杂的背景下,企业和组织面临着来自外部与内部的多种威胁。为了更好地了解攻击者行为、捕获恶意活动并及时响应,部署蜜罐(Honeypot)系统已成为提升内网安全防护的重要手段。本文将重点介绍两种内网蜜罐防护…...

「 机器人 」扑翼飞行器通过总气动力控制四自由度运动方法

一、前言 在扑翼飞行中,总气动力(Total Aerodynamic Force)是指扑翼在运动过程中受到的所有空气动力作用的合力。它是由以下两种主要力的合成结果: 1. 升力(Lift, ):垂直于空气流方向的力,用于支持飞行器(或生物)的重量。 2. 阻力(Drag, ):平行于空气流方向的力,…...

写了一个二叉树构造函数和画图函数,方便debug

代码 class TreeNode(object):def __init__(self, val, leftNone, rightNone):self.val valself.left leftself.right rightdef construct_tree(nodes):if not nodes:return Noneroot TreeNode(nodes[0])queue [root]index 1while index < len(nodes):node queue.p…...

【prompt实战】知乎问题解答专家

本文原创作者&#xff1a;姚瑞南 AI-agent 大模型运营专家&#xff0c;先后任职于美团、猎聘等中大厂AI训练专家和智能运营专家岗&#xff1b;多年人工智能行业智能产品运营及大模型落地经验&#xff0c;拥有AI外呼方向国家专利与PMP项目管理证书。&#xff08;转载需经授权&am…...

元组(Tuple)详解——c#

在C#中&#xff0c;元组&#xff08;Tuple&#xff09; 是一种轻量级的数据结构&#xff0c;用于将多个值组合成一个单一的对象。元组非常适合在不需要定义新类或结构体的情况下&#xff0c;临时存储和传递多个相关的值。 C# 中的元组有两种形式&#xff1a; 传统元组&#xf…...

Maven工具基础知识(一)

第一章、Maven概述 一、概述 官网地址&#xff1a;Welcome to Apache Maven – Maven Maven是一个基于Java的项目管理工具&#xff0c;专注于项目构建、依赖管理和项目信息标准化。其核心目标 是简化开发流程&#xff0c;通过标准化项目结构和自动化构建流程&#xff…...

AI模型的构建过程是怎样的(下)

你好,我是舒旻。 上节课,我们讲了一个模型构建的前 2 个环节,模型设计和特征工程。今天,我们继续来讲模型构建的其他 3 个环节,说说模型训练、模型验证和模型融合中,算法工程师的具体工作内容,以及 AI 产品经理需要掌握的重点。 模型训练 模型训练是通过不断训练、验证…...

力扣hot100_二叉树

二叉树的建立与遍历 #include <iostream> #include <vector> #include <queue> using namespace std;// 定义二叉树节点 struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} };// 函数&…...

如何制作Windows系统盘、启动盘?(MediaCreationTool_22H2)

文章目录 每日一句正能量前言一、准备工作二、制作启动盘后记 每日一句正能量 每个在你生命里出现的人&#xff0c;都有原因。喜欢你的人给你温暖关心。你喜欢的人让你学会爱和付出&#xff0c;不喜欢你的人让你自省成长。你不喜欢的人教会你宽容尊重&#xff0c;没有人是偶然出…...