游戏引擎学习第80天

news/2025/1/20 4:43:46/

Blackboard:增强碰撞循环,循环遍历两种类型的 t 值

计划对现有的碰撞检测循环进行修改,以便实现一些新的功能。具体来说,是希望处理在游戏中定义可行走区域和地面的一些实体。尽管这是一个2D游戏,目标是构建一些更丰富的三维结构,例如楼层上方的房间,可以看到下面的房间,或者跳上跳下的台阶等。

进行这些修改并非因为游戏设计需要这些功能,而是为了避免回避解决这些更复杂的问题。虽然不一定会在游戏设计中大量使用这些功能,但依然要确保引擎技术是顶尖的,能够支持这些三维构建,尤其是如果未来需要使用到这类技术时,能够确保它们无缝集成,不会遇到因为忽视这些问题而产生的特殊情况。

昨天讨论了相关的解决方案,因此今天会直接开始编写相关代码。昨天我们为这些功能添加了基础架构,但还没有进行实际的计算处理。今天的任务就是写出这些计算逻辑,并进行实验,看看它是否能按预期工作。

接下来将集中精力查看碰撞检测例程,尝试在其中进行简单的修改,虽然可能未来还会对这个循环进行更大规模的优化和提升。但目前的重点是理解如何在现有循环基础上进行扩展,并增加新的功能。具体来说,就是要将原本只循环一个 t 值的循环,修改为同时处理两个 t 值,一个是最小 t 值,用于碰撞实体,另一个是最大 t 值,用于表示空旷空间的实体。这个处理是为了实现一种类似构造性实体几何(Constructive Solid Geometry)的方式,合并不同的空间实体。因此,接下来会着重改进 t 值的处理逻辑。
在这里插入图片描述

game_sim_region.cpp:引入 tMax

在循环的每次迭代中,可以看到当前的 t 值(tMin),这是我们之前用来表示碰撞发生的时刻。接下来,需要引入另一个 t 值——tMax,表示到达某个最大距离前不碰撞的区域。最初,tMax 的值为 0,因为在开始时,我们并不知道能够在不碰撞的情况下移动多远。

tMax 的引入是为了处理在碰撞检测时,能够更好地描述最大可以移动的距离。最初,tMax 的值为 0,因为在循环开始时没有任何信息可以用来预测接下来能移动的距离。随着循环的进行,tMax 会根据碰撞检测逐步更新。
在这里插入图片描述

game_sim_region.cpp:考虑如何最好地修改此例程

在修改碰撞检测逻辑时,首先需要关注的是实体的碰撞检测,目前已有的 tmin 处理很好,但现在还需要处理 tmax。为了做到这一点,首先需要检查哪些实体会影响 tmax,然后在遍历过程中进行碰撞检测。如果实体能够碰撞,接着就进入进一步的碰撞计算。

在这个过程中,首先需要做两个检查。第一个检查是确认是否有可能发生碰撞,第二个检查是识别碰撞的类型。对于碰撞计算,当前的做法是测试四个边界,接下来需要根据这些边界计算 tmintmax,然后选择合适的值。

目前的方案是,在测试每个边界时,如果检测到的碰撞时间早于预期,就更新 tmin,如果大于 tmax,则更新 tmax。为了实现这一点,可能需要对代码进行重复操作,但考虑到当前的性能需求不高,可以接受这样的做法。

为避免代码重复,可以将这些逻辑封装成数据结构,通过循环来处理。这种方法有助于简化代码,使得逻辑更加清晰,而且不会在当前的性能考虑下造成问题。

最终目标是确保碰撞检测能够正确处理两个时间点(tmintmax),从而更加精确地计算实体的碰撞情况。

game_sim_region.cpp:循环遍历墙壁,获取 TestWall 使用的所有数据

为了优化碰撞检测的代码,决定将之前手动重复的部分改为循环结构。这涉及到将每个墙壁的测试数据转化为数据结构,并通过循环来处理所有的墙壁。这样可以避免代码冗余,便于维护和修改。具体做法是通过循环遍历每个墙壁,获取对应的碰撞检测参数,并调用测试函数进行计算。

首先,将每个墙壁的相关参数(如位置、大小等)存储在数据结构中,这样可以避免重复书写相同的代码。通过数据驱动的方式,可以让测试函数更灵活地处理不同的墙壁情况。具体的做法是:每次遍历墙壁时,将相关的测试数据传递给测试函数,并执行碰撞计算。

在这个过程中,添加了 tmintmax 的检查。通过这种方式,能够同时处理两种类型的碰撞检测,一种是最小确认(tmin),另一种是最大确认(tmax)。在初步实现时,重点放在确保代码结构合理、易于修改,而不特别关注性能优化,认为在当前阶段,优化结构和清晰度更为重要。

一旦结构调整完成,后续可以根据性能需求进一步优化代码,减少冗余操作。最终的目标是使得碰撞检测功能更加灵活、可扩展,并为未来的性能优化留出空间。
在这里插入图片描述

game_sim_region.cpp:引入 test_wall

接下来需要定义测试墙函数(test wall),这个函数将使用之前提到的所有参数,包括墙壁的坐标(RelX,RelY)、位置变化(delta xdelta y),以及最小和最大值。还需要确保添加法线(normal),这是当前代码中未传递的部分。通过这些参数,能够进行正确的碰撞检测计算。最终目的是确保碰撞检测过程所需的所有数据都能够正确传递和使用。
在这里插入图片描述

运行游戏并确保其仍然正常工作

一切似乎都在正常运行,没有发现问题,测试过程顺利。所有的功能都按预期工作,没有遇到任何障碍。检查了一下各个方面,确认了没有异常,能够顺利进行后续操作。

game_sim_region.cpp:将 TestWall 直接嵌入碰撞循环中

将“TestWall”移动到新的位置,不再直接调用它,而是直接嵌入代码中。接下来,将进行一些修改,移除不必要的部分,并将操作指针的代码简化。所有的墙体相关内容已经调整,并且不再需要指针引用,可以直接使用实际的值。计算结果 tMinTest 也直接作为值使用,避免了使用指针。整体结构简化,清理了冗余的部分,确保代码更加简洁明了。最终调整后的代码看起来非常符合预期。
在这里插入图片描述

运行游戏并测试碰撞

通过简化代码,将相关逻辑合并为一个小循环,目前看起来效果不错,功能仍然正常运行。测试结果显示大部分功能都保持良好状态,但在检测与怪物的碰撞时似乎出现了问题。当前的命中检测可能存在异常,尚未验证其是否与最近的改动有关。这可能是由于修改了整体系统的结构或逻辑,导致武器(如剑)在穿过怪物时不再正确触发碰撞检测。虽然这一问题需要进一步调查,但目前重点仍然放在其他功能的调整和测试上。

game_sim_region.cpp:测试 tMax

在此部分中,需要对被认为是内部实体(如空白区域实体)的测试进行调整。测试逻辑被分为两种类型:一部实种针对内体,另一种针对不透明的外部实体。为此,引入了一个额外的循环,用于处理内部实体的测试。具体逻辑包括以下几点:

  1. 测试分类

    • 对于内部实体,计算的是 tMax 测试值,确保结果大于零,同时记录当前 tMax 的值。
    • 对于不透明实体,依然使用之前的 tMin 测试值。
  2. 逻辑调整

    • 在内部实体测试中,判断是否存在比当前已记录的 tMax 更远的命中点。
    • 相较于之前测试近距离的命中点,现在需要测试距离更远的命中点。
  3. 边界约束

    • 为了确保实体始终处于合法范围内,需要在检测结束后对位置进行修正,保证不会超出内外边界。
    • 在处理内部实体时,对结果进行微调(如通过 epsilon 值),以避免与墙体完全重叠。
  4. 变量跟踪

    • 引入了 TestWallNormalMinTestWallNormalMax 分别用于追踪内侧和外侧的法线信息。
    • 初始值的设置为 tMax = 0,通过循环更新最终的测试结果。
  5. 测试计算流程

    • 每次循环中计算新的 tMax 测试值,并在结束时输出最终结果。
    • 确保测试点在合法范围内,同时跟踪内部和外部边界的法线,以便进行必要的修正。

总体逻辑旨在对不同类型的实体进行分类处理,确保每种实体的测试结果准确,同时维持边界约束,避免异常情况发生。
在这里插入图片描述

game_sim_region.cpp:优化例程

当前的逻辑处理了两种情况:一种是会停止移动的碰撞,另一种是允许继续移动的碰撞。对于这些情况,分别进行了处理。

  1. 两种碰撞的处理

    • 停止移动的碰撞:更新相关的变量来表示碰撞信息,包括法线方向和碰撞位置。
    • 允许移动的碰撞:判断是否发生了碰撞,如果发生,更新相关变量,例如最大法线方向、碰撞实体和碰撞位置。
  2. 移除冗余逻辑

    • 判断后发现部分测试逻辑是重复的,因此移除了多余的变量和测试步骤。
    • 合并了 TestWallNormal 的处理逻辑,将最大值和最小值的计算合并到统一的流程中,减少了重复代码。
  3. 次级循环的优化

    • 针对次级循环中的逻辑,决定将处理移入其中,同时简化变量命名,使代码结构更加清晰。
    • 仅在需要的情况下定义 MinMax 的处理逻辑,减少了无用的初始化。
  4. 初始化调整

    • 针对最小值和最大值的初始化,将其设置为正无穷和负无穷,便于后续的比较逻辑。
    • 确保在循环开始时重置相关变量,以防止遗留上一次循环的状态。
  5. 后续逻辑规划

    • 在当前逻辑的基础上,需要进一步思考根据不同碰撞情况的具体处理方式。
    • 确保碰撞计算结果在符合物理逻辑的前提下,对相关实体的行为进行正确约束或调整。
      在这里插入图片描述

game_sim_region.cpp:实现 tMin 与 tMax 的逻辑

当前的目标是确定在哪个时刻碰撞会停止,从而决定如何更新碰撞状态和变量。

  1. 判断碰撞发生的时刻

    • tMintMax 比较:通过比较 tMintMax,确定哪个碰撞先发生。如果 tMin 小于 tMax,说明碰撞发生在可阻挡的实体上(即不透明的墙体),导致移动停止。
  2. 引入 tStop 变量

    • 初始化 tStop:根据碰撞先后的不同,决定碰撞停止的时刻。如果是 tMin 较小,则设置 tStoptMin;如果是 tMax 较小,则设置为 tMax。这个值决定了移动的停止位置。
  3. 碰撞停止实体和法线

    • 碰撞实体:根据碰撞停止的时刻,确定发生碰撞的实体,并设置为“停止实体”。
    • 法线更新:根据碰撞的位置,更新碰撞法线。此时,WallNormalMinWallNormalMax 需要更新为当前碰撞面对应的法线。
  4. 变量定义和位置更新

    • 变量的重新定义:某些变量(如 HitEntityWallNormal)之前在代码顶部定义,现在需要移动到实际使用的地方。这样可以避免冗余的定义,使代码更加清晰。
  5. 待填补的部分

    • 当前逻辑中有一些部分尚未完成(例如两个 if 变量),需要进一步填充以完善测试逻辑。
  6. 代码编译状态

    • 当前代码能够成功编译,接下来只需要完善未完成的部分,添加适当的测试逻辑。

在这里插入图片描述

game_sim_region.cpp:为 Overlap 和 EntityFlag_Traversable 编写测试

当前的任务是处理空地实体和重叠检测的逻辑,并确保在碰撞检测中正确地处理这些情况。

  1. 测试是否为空地实体

    • 空地实体检测:通过检查实体的可遍历标志(EntityFlag_Traversable flag),可以非常简单地判断该实体是否为空地实体。如果该标志被设置,说明该实体是可以穿越的空地。
  2. 在测试前确认实体位置

    • 位置验证:在进行移动测试之前,需要确认实体确实位于目标实体的边界框内。也就是说,必须先检查实体是否在空地实体的范围内,才能进行后续的移动测试。
  3. 重叠检测的改进

    • 重叠测试移入循环:原本的重叠检测逻辑需要被移入循环中,并在每次迭代时检查当前实体是否与其他实体发生重叠。这种做法本来应该在循环中进行,而不是在其他地方进行。通过这样做,重叠检测会更加智能和高效。
  4. 处理所有重叠情况

    • 全范围重叠影响:所有与当前实体重叠的对象都应该对当前实体的运动产生影响。因此,重叠检测不应仅限于某些特定情况,而是要涵盖所有的重叠对象,以确保运动的准确性。
  5. 运动逻辑的复杂性

    • 运动处理的复杂性:正确地处理游戏中的运动是一项非常复杂的任务。尽管这部分工作在游戏开发中占据了大量时间,但它是必不可少的,特别是在处理复杂的碰撞和运动检测时。
      在这里插入图片描述

鼓励我们不要害怕解决复杂问题

在处理复杂代码时,面对混乱和复杂性是不可避免的,但通过坚持和深入思考,最终可以简化问题。

  1. 应对复杂性

    • 在开发过程中,复杂的代码常常变得越来越难以管理,特别是处理复杂问题时。然而,正是通过深入了解并解决这些复杂性,可以逐渐找到简化的办法。
    • 复杂的代码虽然会导致混乱,但这不应成为退缩的理由。相反,应该继续推动,直至解决问题,之后才有可能找到简洁有效的解决方案。
    • 很多时候,通过艰难的路径走过复杂的阶段,最终能够收获更简洁、更优雅的解决方案。
  2. 面对挑战时的思维方式

    • 鼓励在遇到复杂问题时,继续推进解决,即使解决方案不完美。一旦问题被解决,就会为之后的优化提供清晰的视角和理解,帮助设计更精简、更高效的解决方法。
    • 在开发过程中,很多时候对问题的理解来自于对问题的深入思考,面对复杂代码时,应关注最终目标,而不是被眼前的难题所吓倒。
  3. 重叠检测与优化

    • 在进行重叠检测时,需要逐步迭代,检查每一轮重叠的实体,确保每个迭代都能正确地判断实体是否重叠。
    • 对于那些封闭空间的实体,应仔细观察它们在检测中的作用。这些实体可能会触发某些事件,但可能不应该同时作为触发器使用,封闭空间实体和触发器应该是两个独立的概念。
  4. 提取重叠测试

    • 为了避免重复执行重叠测试,可以将重叠检测逻辑提取成一个单独的函数。这样,重叠检测就不必在多个地方重复执行,提升了代码的可维护性和清晰度。
    • 通过提取重叠测试,能够更容易地管理和检查重叠情况,确保逻辑的简洁与高效。
  5. 临时调整和修复

    • 在测试过程中,发现了一个临时的问题——tMax 被设为零时,实体无法移动。因此,暂时需要将 tMax 设置为一个非零值,以便进行有效的测试和验证。

通过这些步骤,可以逐步简化复杂的逻辑,并为之后的优化和简化打下基础。处理复杂问题时,重要的是不要因眼前的困难而放弃,最终会通过深入分析和迭代得出更简洁的解决方案。
在这里插入图片描述

game_sim_region.cpp:改进重叠测试

  1. 重叠检测的实现

    • 为了检查重叠,需要将实体的 EntityRect 状态移到循环内。这样,便可以对两个实体的体积进行检测,使用两个嵌套循环的方式。这种双重循环逻辑与之前进行的检测方法相似。
    • 在代码中,我们检查了两个不同的体积,进行重叠测试。如果发生了重叠,就处理这个重叠。为了提高效率,在检测到重叠时,可以立即跳出循环,不再继续进行多余的重叠检测。
  2. 优化和提取重叠检测

    • 通过将重叠测试从原有的检测中提取出来,可以避免多次重复进行相同的操作,从而提升代码的清晰度和效率。
    • 通过将 overlap 设置为 true 后,跳出所有循环,这样就可以在检测到重叠时立即结束检测,避免不必要的重复检测。
  3. 避免冗余操作

    • 在进行重叠检测时,避免使用总的体积,直接使用之前定义的两个不同体积,简化了检测过程。
    • 如果重叠发生,就在测试时立即跳出循环并完成处理。
  4. 细节和编译器优化

    • 在代码中遇到了一个小问题:强制赋值给 false 时,由于代码中错误地输入了 bool 类型的变量,而编译器会发出警告,这种警告是因为编译器在处理布尔类型时进行了一些不必要的优化。
    • 对此进行了修正,避免了编译器进行不必要的优化,确保代码更为严谨和高效。

通过上述优化,重叠检测被提取成了一个相对简洁且高效的功能,避免了重复计算和多余的检查,提高了代码的可维护性。
在这里插入图片描述

game_sim_region.cpp:引入 EntitiesOverlap 用于此重叠测试

  1. 重构和简化代码

    • 目标是让所有操作无论如何计算,都能顺利通过。首先进行了一些测试,确保当前的功能仍然有效。
    • 随后,决定将代码提取成一个函数,以便更简洁和可复用。函数名为 EntitiesOverlap,接收两个实体作为参数来进行重叠检测。
    • 通过提取这个函数,简化了代码,使其更具可读性和易用性。
  2. 引入压缩导向编程风格

    • 采用压缩导向编程(Compression-Oriented Programming)的方式,即在代码中通过重用已有的逻辑来引导设计。
    • 重点在于通过需求驱动设计,而不是提前进行复杂的设计。通过重复使用某些功能或代码块,逐步改进和优化代码。
  3. 增强代码的可读性和简洁性

    • 通过提取重复使用的代码块,增强了代码的简洁性,使循环和逻辑更加清晰。
    • 对函数进行简化和命名优化,使得代码更加易读,逻辑更加明确。
  4. 最终效果

    • 代码变得更加简洁易读,循环结构清晰,体积也变小了。
    • 功能在简化后仍然能正常工作,并且易于进一步扩展和修改。

总体来说,通过提取函数和优化结构,代码变得更加简洁、可维护,并且具备了更高的重用性,符合压缩导向编程的理念。
在这里插入图片描述

game_sim_region.cpp:让 EntitiesOverlap 接受一个 Epsilon 扩展区域

以下是对内容的中文总结:

  1. 引入epsilon(精度容差)

    • 提出了在重叠检测中引入一个epsilon(精度容差)值的想法。通过在重叠测试时增加一个epsilon值,可以在测试是否重叠时允许一定的“宽容”,即扩大重叠区域。
    • 默认情况下,重叠测试不使用epsilon,但可以通过在使用的体积上添加epsilon来实现这一点,从而使重叠区域略微增大,提供一些容差。
  2. 在三维空间中的应用

    • 认为epsilon可以在所有三个维度上应用,尽管这种做法有点不常见,但这种“放大区域”的方法可以在精确的停止和定位上提供帮助。通过增加epsilon,可以允许对象稍微穿过某些边界,这对于某些情况下的物体运动检测非常有用。
  3. 精确停止与容忍重叠

    • 这种方法的优势在于可以精确地停止物体与房间边界的碰撞,同时也能更容易地确定物体是否在一个区域内。
    • 这种“宽容”的重叠检测方式对于碰撞系统可能会更有效,因为它允许物体稍微穿过边界,而不是直接停在边界上,从而避免了过度的碰撞。
  4. 决定继续实施该方案

    • 最终决定继续实施这一想法,即在重叠检测时引入epsilon值,使得检测过程更具灵活性和容错性,从而改善碰撞处理和物体位置判断。

通过这种方式,可以在物体碰撞检测中实现更灵活的处理,既能保证精度,又能容忍一定的误差,从而提高系统的容错能力和稳定性。

在这里插入图片描述

修复一个问题
在这里插入图片描述

game_sim_region.cpp:重新启用 EntityFlag_Traversable 测试,并使用 EntitiesOverlap

以下是对内容的中文总结:

  1. 实现重叠测试

    • 目前的实现将重叠测试移到了一个更简洁的函数中,函数通过传递实体进行重叠检测。通过使用EntitiesOverlap,可以确定实体可以在重叠区域内移动的最大范围。
  2. 引入重叠精度(epsilon)

    • 在重叠检测中引入了一个重叠epsilon(精度容差)值,用于对重叠区域进行“放大”,以便更加宽容地处理碰撞。
    • 该epsilon值目前设定为一个较小的值,具体数值需要进一步调整和验证,可能会在后期根据需要进行细化。
  3. 需要创建辅助函数

    • 提到可能需要创建一个辅助函数,将epsilon值应用到所有检测体积中,从而更有效地扩展每个体积,统一处理重叠检测的容差问题。
  4. 桌面设置与效率

    • 在编程过程中,遇到桌面空间不够的问题,觉得工作环境有些局促,需要更合适的打字和操作空间,以提高工作效率。

总结:通过将重叠检测的过程模块化,并引入epsilon进行容错处理,可以提升碰撞系统的灵活性。此外,重叠测试中可能需要进一步优化epsilon值的设定,并考虑创建辅助函数来简化代码。
在这里插入图片描述

运行游戏并发现我们无法通过 tMax

以下是对内容的中文总结:

  1. 调试问题

    • 在进行调试时,遇到问题,尤其是在tMax测试时,发现一直无法通过测试。这个问题需要仔细排查并解决。
  2. tMax测试的逻辑

    • 在进行tMax测试时,应该将tMax设置为零,假设这是实体能够移动的最小值,确保测试的起始状态是合理的。
  3. 调试过程的反思

    • 在调试过程中,需要进行初步的检查,以确认测试是否按照预期工作,同时避免引入不必要的复杂性。

总结:遇到的调试问题主要集中在tMax测试逻辑上,需要确保在测试前正确设置其值,并进行详细的检查和调试。

game_sim_region.cpp:将 tMin、tMax 和 HitThis 移动到循环内

  1. tMax测试调整

    • tMax测试(即最大时间测试)实际上是内部测试,不需要在外部进行处理。它们可以移动到合适的位置以避免冗余。
  2. tMax测试的目标

    • 目标是测试哪些测试的值最大,并确保在执行时获得预期的结果。
  3. 问题定位

    • 不确定问题出在哪里,可能是EntitiesOverlap函数没有正常工作。
  4. 代码循环优化

    • 在遍历两个体积(volumes)时,代码的循环方式存在问题。当前的循环方式不太合适,应该进行优化以避免不必要的重复检查。
      在这里插入图片描述

game_sim_region.cpp:重新思考碰撞例程的逻辑

  1. 简化重构

    • 在处理实体碰撞时,不需要对每个体积进行循环检查。应该一次性检查实体是否重叠,而不是逐个体积进行检查。
  2. 重新组织代码结构

    • 需要将碰撞检测的逻辑移动到顶部进行判断。首先判断是否是一个“EntityFlag_Traversable”的实体,并检查实体是否重叠。如果两者都符合条件,则进行碰撞处理。
  3. 碰撞处理逻辑

    • 如果实体可以碰撞且重叠,就开始碰撞处理。这是需要进行的两个主要检查条件。
  4. epsilon检查

    • 在进行这些判断之前,需要引入epsilon(精度范围)检查,这样可以增加容错范围,避免精度问题。
  5. 最终调整

    • 代码重构后的结构更加简洁,且按照逻辑顺序安排检查和处理,使得处理过程更清晰易懂。

总结:通过简化和重新组织碰撞检测逻辑,减少不必要的循环,确保代码更加高效且易于维护。
在这里插入图片描述

运行游戏并发现它运作得稍微更正常了

  1. 调试过程

    • 当前的代码已经开始正常工作,但还没有测试的地方可以与“蓝线”进行对比验证。
  2. 返回世界创建部分

    • 为了进一步调试,将回到创建世界的部分进行检查和调整。

game.cpp:仅在第一个房间中创建墙壁,以测试新的世界定义

  1. 墙体添加逻辑
    • 在添加墙体时,决定仅在第一个房间添加墙,而不会在其他房间添加墙。
    • 如果流的索引为零,则添加墙,否则不添加墙。

在这里插入图片描述

运行游戏并测试碰撞检测

  1. 墙体和碰撞

    • 在初始阶段,世界只包含第一房间的墙体,其他地方没有墙。
    • 在与墙体碰撞时,系统表现正常,无法越过蓝线,这符合预期。
  2. 滑动和粘滞问题

    • 在测试过程中,发现存在一定的粘滞现象,角色似乎能做一些不应该做的事情,可能与epsilon处理有关。
    • 粘滞问题可能是由于没有正确处理epsilon,导致角色在空间内滑动时出现不正常行为。
  3. epsilon处理和修复

    • 系统需要重新考虑如何处理epsilon,避免这种不正常的滑动现象。可能需要一些时间来解决这一问题。
  4. 边界穿越问题

    • 发现角色无法穿越某些边界,特别是tEpsilon与重叠epsilon相同,导致无法正确穿越,应该将它们设置为不同的值。
    • 穿越边界的行为不一致,在一个方向可以通过,另一个方向则不行,这表明系统中存在bug。
  5. 楼梯相关问题

    • 楼梯的处理方式也存在问题,可能涉及到上下楼层的稳定性,具体原因仍需要进一步排查。
      在这里插入图片描述

game_sim_region.cpp:增大重叠 Epsilon 的大小

  1. 穿越方向问题

    • 遇到一个问题,角色无法向后穿越,但可以从早期实体到达后期实体,反之则不行。这个问题可能与添加顺序有关。
    • 这个问题可能是由顺序依赖引起的,可能存在一个bug,导致某些情况无法正确处理。
  2. 重叠测试

    • 尝试让重叠测试更宽松,增加重叠epsilon的值,以便更容易通过边界。但即使重叠epsilon非常大,仍然无法通过边界。
    • 不明白为什么在这种情况下,团队最大值(tMax)无法找到更大的值,这个问题非常奇怪。
  3. 逻辑问题

    • 在测试过程中,发现当前的tMax测试与预期不符。当墙体的tMax测试结果较小时,仍然接受了这个结果,这不符合逻辑,无法解释。
      在这里插入图片描述

调试器:逐步进入碰撞例程

  1. 调试和检查过程

    • 进行调试,逐步查看程序中的情况,可能是因为早晨的困倦导致没有看清楚问题的所在。
    • 剩余时间不多,因此决定仔细查看问题,看看能否找出原因。
  2. tMax 测试

    • 执行tMax测试时,首先发现测试结果非常大,这看起来是正常的,因此接受这个结果并继续执行。
    • 随后进行碰撞检测,并找到与墙体的碰撞。当前测试通过后,进行下一次碰撞检测。
  3. 碰撞处理

    • 在进行另一次tMax测试时,发现一个更近的碰撞,理论上应该接受该碰撞为tMax值。
    • 然而,根据预期,这个碰撞应该被忽略,而不是作为有效的碰撞结果。

game_sim_region.cpp:将 tMaxTest 初始化为当前的 tMax


  1. 问题发现

    • 发现问题是因为没有将当前的最大值初始化为已找到的最佳值,而是使用了下一个碰撞结果,这导致了错误的行为。
  2. 修正

    • 修正后,确保将值初始化为当前找到的最大值,从而解决了该问题。
  3. 进一步检查

    • 对于是否仍然需要使用过于宽松的重叠测试进行了疑问,并决定进行进一步的检查,以确认是否仍然需要该测试。

在这里插入图片描述

运行游戏并发现一切看起来还不错,但仍然有些不流畅

  1. 修正后的结果

    • 修正后,程序可以正常通过边界,并在边界处停止,达到了预期效果。
  2. 状态评估

    • 尽管过程有些不稳定,但已经接近目标,系统现在能够正确地作为边界工作。

Q&A

你能解释一下 LengthOf(array) 宏和 sizeof 指针的区别吗?


  1. 数组长度宏与指针大小

    • 在C语言中,经常需要定义一个数组,尤其是当数组大小已知且固定时。例如,处理鼠标按钮时,已知鼠标按钮数量固定为五个,那么定义一个固定大小的数组更加高效,而不需要使用灵活大小的数组,这样可以避免不必要的开销。
    • 为了避免手动设置数组的大小并保证代码灵活性,通常会用一个宏来自动计算数组的大小。这样,代码可以根据数组的实际大小进行调整,而无需在运行时修改。
  2. 宏的工作原理

    • 使用 sizeof 关键字可以获得数组的总大小(以字节为单位),但它不能直接告诉数组包含多少元素。为了计算数组元素的数量,需要将数组的总大小除以单个元素的大小。
    • 通过编写宏,传入数组并直接计算其元素数量。宏通过 sizeof 获取数组的总大小,并通过 sizeof 获取数组第一个元素的大小,从而计算出数组的元素数量。
    • 这种方法可以确保在使用数组时能够动态地根据数组的实际大小进行调整,而不依赖于事先定义的常量或宏。
  3. 指针与数组

    • sizeof 是一个编译时指令,可以返回数据类型或变量的大小,而不是其存储的值。在使用指针时, sizeof 会返回指针本身的大小,或者根据类型返回相关数据的大小。
    • 由于 sizeof 不能直接用于数组元素的数量计算,因此在使用指针时,需要模拟一个实际的值来计算数组的大小。通过虚拟化值类型的方式,可以避免引用空指针的问题。
    • 这种方法通过构造一个虚拟的值类型来计算指针指向的数据类型的大小,而不会实际解析空指针或引用错误。
  4. 总结

    • 通过使用 sizeof 关键字和自定义宏,能够动态计算数组的大小和元素数量,从而避免手动设定固定的数组大小。指针和数组的大小计算方法虽然略显复杂,但通过模拟类型和值,可以避免编译时错误,并确保代码的灵活性和可维护性。

以上总结了数组宏、指针大小及 sizeof 在C语言中的使用,以及如何通过宏和指针处理数组元素数量的问题。

你之前提到过的碰撞优化(O(n^2)之类的)会使用空间实体吗?

讨论了用于碰撞检测的空间和之前提到的 O(n^2) 的问题。原本的方案可能并不适合,因为它们更多的是用来定义物体的位置,而不是直接进行碰撞检测。因此,虽然可以考虑采用不同的方法,但如果采取这种方式,可能需要将现有的结构进行拆分,虽然这种调整并不一定是坏事。

其中一个考虑的方向是,可以重新构思世界的结构,将空间分割的方式进行调整。与其使用现有的实体作为空间分区的方式,不如考虑将这些空间分区看作一种超级结构,并将其作为专门用于空间划分的结构。这种方法可能会使原来的实体结构不再适用,而需要新的专用结构,这也是一种可行的选择。

总的来说,这是一种探索不同方式来优化空间划分的想法,但无论如何,调整的方向是灵活的,可以根据需求调整方案的实现方式。

sizeof(game_input::Controllers) 在我使用 g++ 时有效

C++的新扩展解决了一些逻辑问题,应该能够支持这些功能,但实际上在常规C++中并不能直接实现。这是一个值得改进的地方,虽然新的C++扩展提供了一些不错的功能,但某些预期的行为还是没有实现,特别是在处理某些功能时,可能存在一些问题,这些问题导致本应正常工作的功能未能如预期那样发挥作用。

像投射物这样的东西,我们会扩展它们在 Z 轴上的边界框,使它们总是能击中下面的敌人吗?还是我们会以某种方式在屏幕空间中处理这个问题?

关于投射物体的处理,是否将它们的包围盒在z轴上扩展以确保它们能够击中下方的敌人,还是通过屏幕空间来处理,这取决于是否希望子弹或特殊物体能够飞越或穿过其他实体。这个问题将作为游戏性的一部分,在实际游戏过程中根据情况来决定,并观察哪种方式最符合预期。此外,提到需要修复与弹道相关的bug,尤其是剑类碰撞的问题。目前,相关的谓词可能存在问题,清理谓词时需要一并解决这些问题,确保剑类碰撞能够正常工作。

你不喜欢模板吗?

对于模板的使用,表示不喜欢。原因是对于元编程的喜爱,模板在这方面的表现让人感到沮丧。模板的设计方式似乎不符合元编程的需求,反而以一种最糟糕的方式实现了很多可能的功能。这种设计让人感到愤怒,因为设计者显然没有从实际的元编程角度出发,而是从一种抽象的语言设计的视角考虑问题,这种视角并不是开发实际软件时的最佳思路。因此,决定不再使用模板,几乎完全放弃了它们。

像爆炸这种影响区域内所有物体的情况怎么处理?因为这不是一个实体与另一个实体的碰撞

对于像爆炸这种影响区域内所有事物的情况,处理方式依然是逐一操作。虽然在计算机中没有真正的“同时”影响多个事物的概念,操作只能同时针对两个变量进行,因此即使有一个实体影响多个实体,实际上也是逐个处理的。因此,处理爆炸时,仍然需要通过循环遍历所有被爆炸波及的实体,并对每个实体进行单独的碰撞检测和更新。这种方式与当前的处理方式类似,依然是逐一处理影响的对象。

你怎么看待新的 Vulkan API?

对于关于Vulkan API的问题,之前已经回答过了。简短的回答是,由于没有机会查看其实际设计,因此无法对其进行详细讨论。只有在能够评估其设计后,才能给出更好的意见。在此之前,无法提供更多的看法。现在问题已经接近结束,这也正好是直播结束的时刻。


http://www.ppmy.cn/news/1564586.html

相关文章

OpenVela——专为AIoT领域打造的开源操作系统

目录 一、系统背景与开源 1.1. 起源 1.2. 开源 二、系统特点 2.1. 轻量化 2.2. 标准兼容性 2.3. 安全性 2.4. 高度可扩展性 三、技术支持与功能 3.1. 架构支持 3.2. 异构计算支持 3.3. 全面的连接套件 3.4. 开发者工具 四、应用场景与优势 4.1. 应用场景 4.2. …

JavaScript,ES6,模块化,大程序文件拆分成小文件再组合起来

模块化 模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。 模块化的好处 模块化的优势有以下几点:1、防止命名冲突,2、代码复用,3、高维护性。 模块化规范产品,ES6 之前的模块化…

远程接口调用

目录 GET请求 案例1: 案例2: 案例3:查询新闻列表 POST请求 PUT请求 DELETE请求 通用 传json参数 在服务端使用java语言,向远程接口发起请求,得到响应数据的方法。实现远程接口调用方法很多,这里…

npm配置electron专属的淘宝镜像进行安装

nodejs的版本是22.13 npm配置electron专用的淘宝镜像,不配置会下载很慢 npm config edit在打开的文本编辑框里,在最下面空白的地方填写下面的信息 registryhttps://registry.npmmirror.com electron_mirrorhttps://cdn.npmmirror.com/binaries/electr…

【王树森搜索引擎技术】概要04:搜索引擎的链路(查询词处理、召回、排序)

搜素引擎的链路 分为查询词处理,召回,排序 查询词处理 分词 分词:冬季卫衣推荐 -> 冬季 / 卫衣 / 推荐为什么要做分词:文本召回根据词在倒排索引中检索文档倒排索引的 key 大多是 冬季,卫衣, 推荐这…

解决CSS中样式的优先级问题

在CSS中&#xff0c;有以下几种方式来确定优先级&#xff1a; 内联样式 - 直接在HTML元素的 style 属性中写样式&#xff0c;它的优先级是最高的。例如 <p style"color: red;">这是一段红色文字</p> 。 ID选择器 - 当在CSS中使用 #id 选择器来定…

深入剖析 Redis 过期删除策略

深入剖析 Redis 过期删除策略 在当今大数据和高并发的时代&#xff0c;缓存技术对于提升系统性能至关重要&#xff0c;而 Redis 作为一款广泛使用的高性能键值对存储数据库&#xff0c;其过期删除策略更是其中的关键一环。今天&#xff0c;就来和大家深入探讨一下 Redis 过期删…

集群内SSH免密登录及批处理

集群内SSH免密登录及批处理 一、背景二、操作步骤&#xff08;默认在主节点操作&#xff09;1. 为 root 用户设置密码并允许SSH登录&#xff08;在**每台主机**上操作&#xff09;2. 在主节点安装 pdsh&#xff0c;用于批量执行命令3. 创建集群主机列表4. 编写自动生成SSH密钥的…