游戏引擎学习第80天

news2025/1/18 20:15:52

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.coloradmin.cn/o/2278625.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2025.1.15——四、布尔注入

题目来源:ctfhub技能树 目录 一、基本操作:整理已知信息,得到本题为布尔注入 方法一:手工盲注(不推荐) step 1:判断具体形式 step 2:查询字段数 step 3:通过回显判…

PE文件:节表-添加节

在所有节的空白区域都不够存放我们想要添加的数据时,这个时候可以通过添加节来扩展我们可操作的空间去存储新的数据(如导入表、代码或资源)。 过程步骤 1.判断是否有足够的空间添加节表 PE文件的节表紧跟在PE头之后,每个节表的…

【前端动效】HTML + CSS 实现打字机效果

目录 1. 效果展示 2. 思路分析 2.1 难点 2.2 实现思路 3. 代码实现 3.1 html部分 3.2 css部分 3.3 完整代码 4. 总结 1. 效果展示 如图所示,这次带来的是一个有趣的“擦除”效果,也可以叫做打字机效果,其中一段文本从左到右逐渐从…

Python基于Django的图像去雾算法研究和系统实现(附源码,文档说明)

博主介绍:✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&#x1f3…

了解 BM25:一种高效的文本检索算法

什么是 BM25? BM25(Best Matching 25)是一种在信息检索领域非常著名的算法,它属于 TF-IDF 的改进版本,是许多现代搜索引擎和文本检索系统的核心算法之一。BM25 基于概率检索模型(Probabilistic Informatio…

PenGymy论文阅读

这里发现idea被人家先发了,没办法,资料收集的不够全面,现在来学习一下这个项目 这篇论文的贡献如下: 总的来说,他的主要工作是构建逼真的仿真环境,然后根据这个仿真环境生成真实的靶场,使得这个…

猫贫血吃什么能快速补血?

各位铲屎官们,看到自家猫咪无精打采、小脸苍白,是不是特别心疼?贫血可是猫咪健康的大敌,今天就来给大家支支招,哪些食物和方法能让猫咪快速补血,恢复活力! 一、红肉及内脏类 红肉是补血的“主力…

Redis 性能优化:多维度技术解析与实战策略

文章目录 1 基准性能2 使用 slowlog 优化耗时命令3 big key 优化4 使用 lazy free 特性5 缩短键值对的存储长度6 设置键值的过期时间7 禁用耗时长的查询命令8 使用 Pipeline 批量操作数据9 避免大量数据同时失效10 客户端使用优化11 限制 Redis 内存大小12 使用物理机而非虚拟机…

wireshark抓路由器上的包 抓包路由器数据

文字目录 抓包流程概述设置抓包配置选项 设置信道设置无线数据包加密信息设置MAC地址过滤器 抓取联网过程 抓包流程概述 使用Omnipeek软件分析网络数据包的流程大概可以分为以下几个步骤: 扫描路由器信息,确定抓包信道;设置连接路由器的…

在 Fluent 网格划分中使用薄网格特征

薄体模型的网格划分策略 薄体网格划分对于有效模拟薄壁结构或厚度明显小于其他尺寸的几何形状非常有利。当使用此类几何结构时,传统的体积网格划分技术可能会导致单元数量增加,因为它们试图捕获具有许多不必要单元的薄尺寸。薄体网格划分通过专门沿薄方…

大模型WebUI:Gradio全解11——Chatbot:融合大模型的多模态聊天机器人(6)

大模型WebUI:Gradio全解11——Chatbot:融合大模型的多模态聊天机器人(6) 前言本篇摘要11. Chatbot:融合大模型的多模态聊天机器人11.6 为LLM Agent构建UI11.5.1 使用代理构建1. 使用transformers.agents的实际示例2. 使…

Linux-----线程同步(资源竞争和同步锁)

目录 资源竞争(背景) 锁(解决方式,实现同步) 互斥锁 读写锁 自旋锁 资源竞争(背景) 竞态条件 当多个线程并发访问和修改同一个共享资源(如全局变量)时,…

vue2 web 多标签输入框 elinput是否当前焦点

又来分享一点点工作积累及解决方案 产品中需要用户输入一些文字后按下回车键生成标签来显示在页面上&#xff0c;经过尝试与改造完成如下&#xff1a; <template><div class"tags-view" click"beginInput"><el-tag :key"index" …

Python学习(十)IO编程(文件读写、StringIO和BytesIO、操作文件和目录、序列化)

目录 一、什么是IO编程&#xff1f;二、文件读写1&#xff09;读文件2&#xff09;file-like Object3&#xff09;二进制文件4&#xff09;字符编码5&#xff09;写文件 三、StringIO 和 BytesIO1&#xff09;StringIO2&#xff09;BytesIO 四、操作文件和目录1&#xff09;操作…

5、docker-compose和docker-harbor

安装部署docker-compose 自动编排工具&#xff0c;可以根据dockerfile自动化的部署docker容器。是yaml文件格式&#xff0c;注意缩进。 1、安装docker-compose 2、配置compose配置文件docker-compose.yml 3、运行docker-compose.yml -f&#xff1a;指定文件&#xff0c;up&…

JS宏进阶: 工厂函数与构造函数

一、构造函数 在JavaScript中&#xff0c;构造函数是一种用于创建和初始化对象的特殊函数。构造函数的名字通常以大写字母开头&#xff0c;以区分于普通函数。通过new关键字调用构造函数&#xff0c;可以创建一个新的实例对象&#xff0c;并自动执行构造函数内部的代码来初始化…

uniapp 微信小程序 editor 富文本编辑器

<view class"inp boxsizing"><view class"contentBox"><!-- 富文本编辑器 --><view classwrapper><view classtoolbar tap"format"><view :class"formats.bold ? ql-active : " class"iconfon…

Python根据图片生成学生excel成绩表

学习笔记&#xff1a; 上完整代码 import os import re from openpyxl import Workbook, load_workbook from openpyxl.drawing.image import Image as ExcelImage from PIL import Image as PilImage# 定义图片路径和Excel文件路径 image_dir ./resources/stupics # 图片所…

在VMwareFusion中使用Ubuntu

在VMwareFusion使用Ubuntu 在VMwareFusion使用Ubuntu背景在VMwareFusion虚拟机里使用Ubuntu1、集成桌面工具2、主机和虚拟机之间共享剪贴板内容3、设置root用户密码4、设置静态ip4.1、静态ip和动态ip的区别4.2、查看当前ip4.2、linux网络配置文件所在位置4.3、基于ubuntu22.04.…

农业农村大数据应用场景|珈和科技“数字乡村一张图”解决方案

近年来&#xff0c;珈和科技持续深耕农业领域&#xff0c;聚焦时空数据服务智慧农业。 珈和利用遥感大数据、云计算、移动互联网、物联网、人工智能等先进技术&#xff0c;搭建“天空地一体化”监测体系&#xff0c;并创新建设了150的全球领先算法模型&#xff0c;广泛应用于高…