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

游戏引擎学习第77天

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

回顾昨天的 bug

今天我们继续开发进度,进行调试昨天代码的问题,主要是关于如何跟踪玩家和敌人在世界中的高度位置。虽然我们做的是一款 2D 游戏,但我们希望能够处理多层的房间,玩家可以上下走动,这需要处理与三维位置相关的问题。

昨天我们开始调整实体的 Z 坐标,确保它们有完整的高度信息,并且应该从地面开始,位置会从地面向上延伸。然而,在调试时,发现玩家的角色似乎比预期低,应该碰到树木的位置时,角色却没有停下来,显得像是角色下沉了。我们也观察到角色在楼梯处的碰撞没有按预期进行,可能是因为角色的 Z 坐标没有正确计算其高度。

因此,有人猜测问题出在没有修正站在地面上的代码,忘记考虑实体的高度。也就是说,虽然角色的底部位置被设置在地面上,但角色的高度应该从该位置向上浮动。因此,调整这个问题,确保角色位置正确是接下来的重点。

黑板:实体的基点与地面位置之间的差异

有人提出了一个很好的猜测,问题可能出在实体的位置计算上。我们来看一下实体的高度问题。假设实体是这样的形状(侧面图),它的 Z 维度代表它的高度。如果我们把实体的高度表示为 Z 维度,那么它的中心位置应该在地面上方半个 Z 维度的高度。也就是说,实体的实际地面接触点应该是它的中心位置减去它的一半高度。

因此,假设地面是某个高度,那么实体应该从地面加上它的高度一半来确定其实际的位置。这就意味着,我们不能简单地把实体的位置设置为地面,而是要加上它的一半高度,才能确保它的底部位置正确。换句话说,地面实际上应该在中心点下方半个 Z 维度的位置。

这个建议看起来很有道理,可能正是导致问题的根本原因。

查看当前如何指定这些概念

在处理这个问题时,首先发现了实体的位置计算没有考虑到实体的尺寸,尤其是高度(Z 维度)。具体来说,地面高度的计算没有考虑到实体的高度,这导致了实体的位置不正确。

我们在处理重叠(overlap)时,地面高度是通过一个插值(lerp)计算得出的。为了修复这个问题,计划在进行重叠测试后,根据实体的尺寸调整地面高度。也就是说,在计算出重叠后的地面高度后,需要再调整它,使其考虑到实体的实际尺寸,特别是其高度(Z 维度)。这应该能解决当前问题,确保实体的底部能正确地与地面对齐。

game_sim_region.cpp: 将 0.5 * Entity->Dim.Z 加到地面位置

要解决这个问题,计划将地面高度调整为原本的地面高度加上实体高度的一半。也就是说,在计算地面高度时,需要将原本的地面位置上移,移动的距离是实体高度的一半。这就是在之前图示中提到的做法,通过这种方式确保实体的位置正确。
在这里插入图片描述

运行游戏,发现问题还没完全解决

调试过程发现当前的碰撞行为有些不合理,看起来可能是已经到了顶部楼层,导致上下碰撞变得异常。此时需要进一步调试碰撞检测代码,尤其是在绘制方面。为了更清楚地理解问题,首先可能需要添加一些调试代码来检查当前的碰撞情况,确保问题出在哪里。

调试:进入计算地面位置的代码

通过调试代码,发现碰撞系统中的地面计算已经修复了之前的错误,角色的位置现在正确地悬浮在地面上,符合预期的高度(0.62的实体高度的一半)。这解决了之前在预演阶段提到的bug。不过,问题可能还在于绘制部分的代码没有完全处理好,因此需要继续修复绘制代码。

game.cpp: 查看当前的绘制代码

绘制代码当前使用了一个占位符方法,导致调试变得有些困难。具体来说,在绘制位图时,传入的是位图的左上角位置,而不是位图的中心。因此,绘制代码中的 DrawBitMap 调用使用了最小角落位置,而这与预期的中心对齐有所不同。代码实际上对位图的位置进行了偏移,但并未考虑位图的实际大小,导致绘制时的对齐问题。虽然目前的代码中已经通过偏移量修正了这个问题,但这种方式比较粗糙,存在不一致的问题。最终需要决定是修复这个对齐bug,还是重新整理代码来改善渲染系统。在不确定时,决定暂时不对渲染系统做大幅改动,保持现有代码结构。

引入 EntityBaseP

为了正确对齐实体的绘制位置,应该将实体的位置调整为基于地面对齐,而不是基于其中心位置。建议将实体的当前位置重新命名为 EntityBaseP,其位置应为当前实体位置加上实体在 Z 轴上的一半尺寸。这样,绘制时就能够与地面对齐,因为当前地面位置的对齐是基于这个偏移量的。虽然目前这种方式对大多数实体来说是合理的,可能对于飞行类实体不适用,但这可以作为初步解决方案,未来如果需要,可以进一步引入自定义对齐方式。

此外,绘制影像时的透明度计算(ShadowAlpha)也应与此对齐,以确保绘制的一致性,即影像的透明度应基于调整后的 EntityBaseP 来计算。

在这里插入图片描述

运行游戏,发现问题似乎已经解决

目前已经解决了绘制和碰撞检测中的一些问题,特别是在位置计算和停止点的处理上,似乎达到了预期的效果。玩家可以正确地在环境中移动,碰撞和停止位置的逻辑也符合预期。

然而,仍然存在一个问题,就是阶梯的碰撞检测。阶梯不会正确与玩家发生碰撞,因为阶梯的高度只达到了地面上方的高度,并未覆盖到玩家可能需要攀爬的区域。因此,需要解决阶梯的碰撞问题,使得玩家能够正确地与阶梯交互。

下一步计划是在阶梯上添加两个矩形,一个位于阶梯的底部,一个位于顶部。这样做是为了能够更好地控制阶梯的碰撞范围,并确保玩家只会在特定的位置与阶梯发生碰撞,而不是轻易穿越阶梯的侧面。这个问题的解决需要对当前的碰撞代码进行一些修改和调试。

game.cpp: 给楼梯添加两个矩形

计划在阶梯上添加两个矩形,一个位于阶梯底部,另一个位于顶部,以便更好地处理阶梯的绘制和碰撞。在绘制时,需要对这两个矩形的位置进行偏移,确保它们准确地定位到阶梯的上下部分。为了实现这一点,需要利用已经实现的偏移机制。

在现有的 PushRect 函数中,已经支持对矩形进行偏移,但是遇到了一些问题。偏移量应该应用于第二个矩形,这样可以确保它与第一个矩形不同,并且根据 Z 轴的高度进行相应的调整。为了便于辨识,底部的矩形会用不同的颜色显示。

然而,当前遇到的问题是,矩形的偏移似乎没有正确应用,导致它们没有按预期位置移动。这可能是因为 Z 轴偏移的处理没有在绘制时被正确使用,虽然代码上看起来已经允许了偏移。

下一步需要检查 Z 偏移的计算是否正确,并确保在绘制时正确应用这些偏移。这可能需要对现有代码进行一些调试和修改,确保偏移量能正确影响绘制过程。

在这里插入图片描述

处理 ZFudge

当前存在的问题是,ZFudge 只用于计算地面点,但没有真正将其应用到 X 和 Y 坐标的偏移上,这导致物体在 Z 轴上的位置被抬高,但 X 和 Y 坐标没有受到影响。为了更好地处理阶梯和其他物体的绘制,想要尝试将 Z 偏移直接应用于 X 和 Y 坐标。

尽管代码的结构比较混乱,但希望通过一些调整,能在现有代码的基础上获得更多的灵活性,而不必深入修改整个系统。为此,考虑将 Z 偏移与 EntityBaseP 结合使用,使得偏移能直接影响物体的绘制。

实验步骤包括去除现有代码中的某些部分,并在需要的位置手动添加 Z 偏移的影响。这可能会导致一些问题,尤其是当 Z 偏移被直接应用时,可能会引入额外的复杂性,因此需要进一步评估这种方法是否合适,并决定是否继续使用该方案。
在这里插入图片描述

检查对 Familiar 的影响

当前遇到的问题是,黄色物体的显示位置不对,导致它似乎消失了。这并不是预期的行为,因此需要调试和找出原因。尽管尝试了多种方案,但仍然没有找到问题的根源,正在进一步检查并尝试解决这个问题。

MetersToPixels 被 OffsetZ 预乘

当前问题的原因在于坐标转换中的错误,特别是“米到像素”的转换方式。问题出在“偏移Z”值与“米到像素”转换的顺序,导致了值被重复乘以“米到像素”,这影响了图形的渲染。为了避免这种重复乘法,应该在处理 Z 偏移时将“米到像素”的转换推迟,确保在正确的位置进行乘法操作。这是当前代码的一大问题,进一步的解决方案可能需要重构这部分渲染代码,避免继续积累更多的“临时修补”方式。
在这里插入图片描述

运行游戏,看到效果更接近正确

当前的问题是在楼梯代码的实现上,特别是在使用地面位置计算时,楼梯的位置仍然不正确。尽管图形渲染已经接近预期,但楼梯的渲染和碰撞检测依然存在问题,导致其显示位置不准确,应该位于玩家角色上方,并且在屏幕中心对齐。需要进一步调试楼梯的代码,并确保其正确使用地面位置的计算结果。这个问题可能涉及到楼梯的碰撞检测逻辑以及如何正确应用地面坐标的偏移。

game.cpp: 不再添加 OffsetZ

在尝试去除偏移量并直接使用 Z 偏移时,图形的显示效果变得更加正确。不过,这种方法可能会在长期的绘制过程中引发一些问题,特别是在处理等距艺术风格时,因为这要求所有的绘制计算必须适应等距视角。尽管目前去除偏移后的结果看起来比较合理,但不确定这种方式是否能长期保持稳定,需要进一步验证和调试。
在这里插入图片描述

在这里插入图片描述

黑板:ZFudge 的作用

Z 偏移量的作用是根据物体在 Z 轴上的位置对其进行缩放,目的是让物体在 Z 轴上越高时,离摄像机的距离越远,从而产生一种透视拉伸效果。这个缩放效果有助于使远离摄像机的物体看起来更远,但也使原本近距离的物体被放大。由于游戏采用等距视角,这种处理方式与实际的 Z 轴深度有所冲突,因为在等距视角下,物体并不直接在 Z 轴上绘制,而是以一定角度呈现,这就导致了视角上的不匹配。

尽管这种视角匹配存在一定的问题,但它是实现特定艺术风格的必要条件,并且是 2D 游戏中常见的挑战之一。当前,角色可以正常地跳跃到不同的 Z 轴高度,且整体效果不错。接下来的工作是继续完善楼梯的碰撞检测,确保它能够正确延伸到天花板以上,以便玩家可以在楼梯上上下行。这项任务是可实现的,且应是当前工作重点。

game_sim_region.cpp: 查看 SpeculativeCollide

为了确保角色只能从楼梯的底部或顶部进入,而不能从楼梯的侧面直接进入并跳到任何位置,使用了一个名为 SpeculativeCollide 的机制。这个机制的作用是限制角色只能在特定条件下与楼梯发生碰撞,确保角色只能沿着楼梯的上下方向行进。

在碰撞检测过程中,结合了 Ground tight 信息,这有助于判断角色是否接触到楼梯的有效部分。这样可以避免角色从楼梯的侧面进入,确保楼梯的碰撞处理仅在角色位于楼梯的底部或顶部时才生效。
在这里插入图片描述

引入 GetEntityGroundPoint

为了简化代码并避免重复计算,决定引入一个名为 GetEntityGroundPoint 的调用函数。这个函数将返回一个实体的地面位置,并且通过将实体的Z维度偏移一半来调整该位置,确保地面位置正确。这样一来,所有需要计算实体地面位置的地方都可以统一调用这个函数,避免在多个地方重复计算,提升代码的可维护性。

例如,在需要获取某个实体的Z位置时,直接调用 GetEntityGroundPoint,这个函数会自动处理位置的偏移。通过这种方式,可以更方便地修改和管理地面位置的计算方式,而不需要在代码中逐一修改所有相关部分。
在这里插入图片描述

使用 GetEntityGroundPoint 设置 EntityBaseP 和地面位置

当前正在考虑如何使用 GetEntityGroundPoint 来计算实体的偏移量,并调整实体位置与地面位置的关系。具体思路是通过获取实体的位置,然后根据其 Z 值计算地面位置,再调整以实现正确的偏移。
在这里插入图片描述

黑板:计算地面位移

这段内容的核心思想是,通过将实体的位置与地面位置进行比较,计算出它们之间的偏移量,从而确保地面正确对齐实体的位置。具体步骤如下:

  1. 实体位置与地面位置的差值:为了避免在不同地方重复计算地面位置,决定使用 GetEntityGroundPoint 函数来获取每个实体的地面位置。然后,通过计算实体位置与地面位置的差值(即实体位置减去地面位置)来得到偏移量。

  2. 计算偏移量:这个偏移量是一个向量,表示从当前地面位置到实体位置的距离。通过这个偏移量,地面高度可以被正确调整。

  3. 通过向量运算调整位置:使用向量减法来计算从地面到实体位置的偏移量,确保实体与地面正确对齐。

总结来说,目的是通过集中计算地面位置,简化代码中的多个计算,并确保以后修改时能一致地应用。

运行游戏,发现现在可以上楼了

现在,修复了上楼的代码,但下楼的问题依然存在。这是因为碰撞检测部分已经正确工作,或者至少已经调试了尽可能多的已知问题。修复后,碰撞检测不再与那些最大值位于地面上的物体发生碰撞,因为它们实际上处于我们下方的地面层。这意味着在地面层上方的物体不会再被误判为碰撞对象。

game.cpp: 使楼梯延伸到地面之上

目前,楼梯的碰撞检测已经正常工作,但存在一个问题:我们无法从上方进入楼梯。问题可能出在楼梯的高度设置上,楼梯被设置得太高,导致我们无法顺利进入。为了改进这一点,计划是让楼梯稍微超出地面层的一定高度,这样可以确保我们在移动过程中能够与楼梯发生碰撞,避免无法进入的情况。

此外,之前提到的“步高”问题也需要处理,考虑到这是影响楼梯交互的一个因素。现在楼梯的顶部虽然可以与玩家正确碰撞,但仍然存在一些小的高度差,可能导致玩家不能顺利进入。这些细节需要进一步调整。
在这里插入图片描述

黑板:理解 StepHeight

目前,楼梯的碰撞检测存在一些问题,特别是在上下楼梯时的交互表现。现有代码的逻辑是,如果玩家在接近楼梯时,步伐与楼梯的高度差大于一定值(例如0.1米),就不能直接跳上楼梯,而必须从合适的高度进入。然而,这个高度差和玩家与楼梯的交互方式存在一些问题,尤其是当玩家尝试从楼梯侧面接近时,碰撞和过渡效果并不理想,造成了一些“跳跃”或不平滑的过渡。

为了解决这个问题,计划对现有的楼梯模型进行调整。当前的楼梯实际上是以坡道形式实现的,而不是传统的阶梯。这意味着楼梯的碰撞矩形应该具有更大的范围,以覆盖整个坡道区域,从而避免因碰撞区域不够大而导致的跳跃或穿透现象。然而,计算地面位置时,并不应该使用整个楼梯的碰撞矩形,而应仅使用一个较小的参考值,例如楼梯的单层高度。这样就能确保玩家能够更加平滑地与楼梯交互,避免过高或过低的触发问题。

这种方式能够让楼梯的碰撞检测更具灵活性,也能为未来的调整提供更多可能性。

game_sim_region.h: 在 sim_entity 中添加 WalkableHeight

为了更好地处理楼梯的交互,考虑了根据不同的楼梯高度变化来调整碰撞检测。当前的方案是通过调整最小Z值来确定“可行走高度”,这意味着在不同楼梯区域,玩家与楼梯的交互将根据楼梯的高度变化来确定是否可以通过。这种方法的目标是确保玩家能够在不同的楼梯高度之间平滑过渡,而不受不必要的碰撞限制。

为了避免在不同楼梯区域之间有太多重复计算,建议引入一个“可行走高度”的概念,这个高度可以通过结合当前楼梯区域的最小Z值与楼梯的实际高度来计算。通过这样的方式,楼梯的碰撞检查就变得更加高效和一致。同时,在实际开发中,这一机制也便于日后的调整,因为只需要在某些区域对“可行走高度”进行修改即可,无需重新编写碰撞逻辑。

这种方法能使得楼梯的交互更加灵活且符合实际需求,尤其是在多层楼梯或不规则楼梯的情况下,可以避免由于碰撞体积设置不当导致的玩家行为问题。

在这里插入图片描述

game.cpp: 在 SpeculativeCollide 中使用 WalkableHeight

我们决定在添加楼梯时,能够指定其上升的高度,这样可以确保楼梯的碰撞区域与可行走区域分离。具体来说,我们会将 entity_sim 结构中的 walkable_height 设置为游戏状态中世界瓦片的深度(以米为单位)。这样,楼梯的碰撞矩形高度就与可行走区域的高度分开了,这有助于在处理楼梯时更好地控制玩家的行为。
在这里插入图片描述

运行游戏,尝试楼梯

在进行楼梯调试时,虽然楼梯的上升部分正常工作,但在尝试下楼时出现了问题。具体来说,存在一个明显的台阶突起,导致无法顺利下楼。尽管其他部分的碰撞检测已经正常,但在楼梯的最底部仍然有些问题。需要进一步检查并修复这个 bug,以确保下楼时不再遇到这种障碍。
在这里插入图片描述

在这里插入图片描述

game_entity.h: 引入 GetStairGround

在进行代码调试时,发现了两个不同的地面计算方式,这可能是导致问题的根源。需要创建一个函数来统一计算地面高度。通过改进现有代码,可以避免不一致的计算,减少潜在的 bug。

进一步的计划是完善实体系统,逐步增加更多的实体特定数据,这样在后续改进和维护时能够更容易地处理各种不同类型的实体。尽管目前的实体系统尚未完全构建,但现有的基础已经具备扩展的潜力。为了避免重复的错误,代码中的一些假设需要被固化,保证系统的一致性和稳定性。

同时,涉及地面点计算的问题也得到了一些澄清,发现并不是 bug,而是代码在某些情况下由于假设不一致导致的暂时性错误。在重构时,需要将 GetEntityGroundPoint 和相关计算步骤整合,确保所有计算使用一致的地面点。通过这些改进,整体的实体系统和地面计算方法将更加健壮,后续的开发和调试也会变得更加高效。

在这里插入图片描述

game_sim_region.cpp: 将 HandleOverlap 和 SpeculativeCollide 改为使用 GetStairGround

在这段内容中,代码的目标是将现有的重叠处理逻辑简化为调用 GetStairGround 函数来获取楼梯的地面高度,并保留原有的 GetEntityGroundPoint 函数调用作为备份,以防未来需要对 X 和 Y 方向进行调整。以下是详细总结:

  1. 简化代码:原本有多个处理重叠的代码段,现在决定使用 GetStairGround 来计算楼梯的地面高度。这样可以避免重复代码,并集中处理楼梯地面的计算。

  2. 保留备份:尽管不太可能,仍然保留对 GetEntityGroundPoint 函数的调用,以防未来需要在 X 和 Y 方向进行位置调整。这样做可以增加代码的可扩展性和容错性。

  3. 移除冗余代码:在楼梯的重叠处理部分,移除了不再需要的代码,特别是与重叠处理无关的内容,如检查两个条件的代码。这些检查似乎是多余的,因为处理楼梯的唯一标准应该是“需要跨越的高度”。

  4. 确认类型:为了避免发生不必要的错误,增加了类型检查,确保调用 GetStairGround 时,传入的实体确实是楼梯类型。这样可以防止错误调用其他类型的实体并导致程序崩溃。

  5. 待处理问题:代码中提到还存在一些可能没有完全实现的部分,并标注为需要进一步工作的地方。这可能是为了后续的优化和功能扩展做准备。

整体来说,目的是通过精简和重构现有的重叠处理逻辑,让代码更加简洁、清晰,并提高其可维护性,同时为将来可能出现的需求留有余地。
在这里插入图片描述

运行游戏,发现问题得到解决

目前的情况看起来进展不错,已经有很多功能能够正常工作,虽然仍有一些不完美的地方。地面高度的计算是一个主要问题,但整体效果已经有了显著的改善。不过,仍然出现了一些异常,尤其是某些地方的表现并不符合预期,可能是存在bug。比如在角色下楼梯时,某些动作没有完全按照预期进行,需要仔细检查并修复。

game_sim_region.cpp: SpeculativeCollide 需要知道是上楼还是下楼

当前遇到的问题是关于处理楼梯的碰撞和上下楼梯的地面类型。需要解决的核心问题是如何让碰撞系统能够正确处理从楼梯上移开或走上楼梯的情况,确保能够识别楼梯之外的地面类型。这涉及到对地面高度的规范化,并且在碰撞循环中考虑高度变化,避免不合适的高度变化导致物体无法正确移动。

接下来计划解决的问题是:在碰撞系统中加入处理地面层级的概念,使得碰撞可以正确处理跨越楼梯等地形的情况。同时,还需要进一步确保不同的地面高度在不同的区域能被正确处理,确保碰撞系统能准确判断和限制物体的移动范围。

总的来说,今天完成了预期的一些任务,但仍有一些细节需要进一步完善,尤其是在碰撞和地面处理方面。计划在明天继续深入解决这些问题,并对地面层级进行更细致的设计,以确保系统能够正确处理不同高度的过渡。

问答环节

问:你在 Linux 上使用 Clang 吗?

在Linux系统上使用clang编译器,在Windows上则使用Visual Studio的编译器。同时,虽然他们曾经在Mac上进行开发,但目前已经不再频繁使用Mac进行项目发布,因此对Mac的开发环境不再熟悉。

问:从零开始自学 C++ 的最佳方法是什么?

关于如何从零开始自学C++,程序员建议最好的方法是通过大量的编程实践来学习。首先,可以从一些基础的教材入手,比如《C程序设计语言》这本书(K&R),这本书对于理解C语言及其思想非常有帮助。除了阅读书籍,观看相关的编程直播,观察别人是如何编程的,尝试模仿和理解这些操作也是一种很好的学习方式。

程序员提到,自己学习C++的经历已经过去很多年,因此不太记得具体的学习材料,且也不清楚现在是否有特别推荐的入门教程。不过,持续编写代码和解决问题是自学C++的核心。

问:你知道 Voxpel 编程吗?

对于Vox pel编程,程序员表示自己不太清楚这个术语的含义,推测它可能与Voxel(体素)有关。虽然不熟悉Vox pel引擎的编程,但他知道如何编写体素引擎。

问:你打算把家里的楼梯换成坡道吗?

我们在游戏设计中加入了一个能够平滑上下来回滑动的楼梯,感觉非常好,甚至比传统游戏中的楼梯更顺畅。最初并没有打算加入坡道,但由于这一滑动体验太令人满意,我们决定保留这种设计,并在未来进一步完善。我们也注意到游戏中常见的2D楼梯处理方式,通常角色会触发固定动画并转屏切换,而我们的设计则没有这种切换感,而是通过平滑的滑动让玩家能够自如上下楼层,带来更好的体验。尽管现实生活中不会实现类似坡道,但我们决定在游戏中继续沿用这一创新设计。

问:你是怎么让 Visual Studio 调试视图的右侧垂直分割的?

如何在 Visual Studio 调试器中将窗口分割成垂直布局。方法很简单,只需将窗口(如模块窗口)拖动到屏幕上。当拖动窗口时,会看到一个类似指南针的指示符,若将窗口放置在其中一个区域,窗口会自动对齐。如果放置在其他区域,则会分割窗口。这样可以根据需要自由调整窗口布局,例如创建多个窗格,或者将窗口分为上下或左右不同的布局。

然而,在旧版本的 Visual Studio(如 2008 版)中,存在一个严重的 bug:尝试对窗口进行停靠时会导致程序崩溃,而微软在其知识库中明确表示该问题不会修复,建议用户避免使用这一功能。但在较新的版本(如 2013 版)中,这个问题已经解决,不会再发生崩溃。

问:为什么你在代码中使用这么多魔法数字?

这里的“魔法数字”指的是代码中未经过清晰命名的常量值,这些值往往在代码中没有解释其含义,导致代码不易理解和维护。

问:你怎么看待友元类?

在开发中,认为使用 friend 类是多余的,觉得会浪费打字。由于不使用 private,因此也没有必要使用 friend

问:这是不是变成了反向 Doom?几乎是 2D 渲染 3D,而不是 3D 渲染 2D?

在讨论游戏渲染时,提到了一种“2D渲染在3D中”的设计方式,类似于经典的《DOOM》中的“2.5D”视角,但方式有所不同。《DOOM》采用了近似的3D效果来表现墙面,实际上仍然是2D渲染,而我们则是通过精灵分割来实现,精灵本身没有倾斜,而是采用了3D定位系统。这种设计可以理解为“反向DOOM”或“2D渲染在3D中”。

我们认为,确保3D基础结构的稳固非常重要,因为这可以避免开发过程中出现意外问题,减少临时处理的需求。虽然2D渲染方式可能有点“hacky”,但考虑到实现成本相对较低,这种方法仍然是值得尝试的。通过提前实现扎实的3D基础结构,能够确保后续开发中不会频繁遭遇问题,避免不断进行临时的解决方案。

问:如果你上楼进入一个封闭的房间,最上层会不会渐变显示?

在讨论游戏中的楼梯和房间的渲染时,提出了一个问题:当玩家从楼梯上走到一个封闭的房间时,最上层是否应该渐变显示。对此,猜测可能会采用渐变效果来解决这个问题,但也表示目前还不确定具体的实现方式。由于这个问题还需要进一步的实验和调整,因此暂时没有最终的解决方案,仍然需要一些尝试和探索。

问:你计划什么时候对精灵进行 Z 排序?

在讨论精灵的Z排序时,表示计划在渲染器实现时进行,但预计这一部分的工作不会在短期内完成,可能还需要一段时间,几个月后才会开始着手。

问:你为什么在代码中使用这么多魔法数字?为什么有这么多 #define?

在讨论代码中的“魔法数字”时,解释了为什么有些数字没有使用宏定义(#define)。如果某个数字只在局部使用,且没有在其他地方引用,那么就没有必要将其定义为宏,否则会污染全局命名空间。如果某个数字在多个地方使用,那可能就是一个需要改进的地方,可以提出指出,看看是遗漏了还是有其他合理的原因。

问:你打算使用高级着色器技术吗?如果是,你打算使用哪些?

在讨论是否使用高级着色器技术时,表示计划使用一些高级着色器技术,但目前还为时过早,具体细节将在未来的开发中逐步实施。

问:看起来我错过了一集,你在其中实现了从高层看到低层。你记得那是在哪集吗?将来地板会保持透明吗?

在讨论渲染器时,提到地板不会保持透明,尽管目前地板是透明的,这样做比较方便。未来会添加地面,可能会首先加入一个占位符地面,而不是保持透明。同时,还需要处理如从上层下降到下层时,如何渐变处理上层的显示效果等问题。这部分的工作计划在接下来的开发中进行,但具体细节仍在考虑中。对于何时实现这个功能,也没有明确的记忆或时间点。

问:如果我没记错的话,早期我们开始使用角色底部中心位置进行碰撞检测,然后改为中心位置,并且在 X 和 Y 方向上有所偏移。现在似乎又回到了使用中心 X 和 Y,并继续计算底部中心位置。你认为是否需要将这一点整合起来?

在讨论碰撞检测时,提到最初使用的是角色底部中心位置来进行碰撞检测,后来调整为中心位置,偏移了x和y坐标。现在,似乎又回到了使用中心x和y坐标的方式,同时保留了底部中心的位置。关于是否需要将这些方法合并,认为目前的做法更合理,因为统一处理x、y和z坐标更加简洁,避免了不同坐标轴上采用不同的处理方式,这样可以简化数学运算,避免在处理复杂的碰撞检测时出现混乱。如果让碰撞检测的不同部分(如Minkowski和干涉测试)在x、y和z上使用不同的方式,可能会增加数学复杂度,影响效率。因此,统一处理所有坐标轴并单独处理与地面相关的偏移,似乎是更明智的选择。尽管如此,这个决定仍然有可能在未来被重新评估。

问:森林中间漂浮的头是怎么回事

森林中飘浮的头部是一个“伙伴”,它会跟随玩家四处移动。

问:能解释一下 game.h 中的这一行吗?ControlledHeroes[ArrayCount(((game_input *)0)->Controllers)];,看起来你在强制转换一个空指针并引用它

无法直接获取数组成员的大小,因此需要通过一些技巧来绕过这个限制。目标是计算数组的大小,但C语言不允许直接对类型或成员使用sizeof,必须使用实际的变量或值。因此,采取了一个技巧性的方法,使用一个空指针并将其强制转换为正确的类型,模拟对该数组的引用,从而间接计算数组的大小。这种做法虽然看似不太优雅,但由于C语言的限制,这是目前的解决方法。

问:为了绕过 Mischief 缩放问题,你能先找到想要的缩放级别,然后在四个角上画四个点,接着再回来对齐这些点到角落吗?

关于Mischief缩放问题的解决方案。提出了一种方法,即找到需要的缩放级别后,在每个角落绘制四个点,然后回来时通过对齐这些点来恢复视图。但这种方法被认为不太方便,因为每次都需要找到这些点。目标是找到一种可以直接设置缩放的方式,而不需要不断地定位这些点。

你可以使用 C++ 的 decltype 或 typeof 来找出 ArrayCount

在讨论C++中使用decltypetypeid等特性时,提到尽管这些功能可以帮助获取类型信息,但由于它们传统上并不总是得到很好的支持,因此尽量避免使用这些特性,尤其是对1990年代的C语言风格更为偏好。虽然decltype可能在某些情况下有用,但对于目前的需求,仍然更倾向于使用C语言的子集。对于如何准确获取类型信息,提出了一个假设的做法,可能通过decltype获取控制器数组的大小,但也承认这部分实现可能还存在一些未知的问题,决定将其作为读者的练习留待解决。

问:为什么你计划使用 OpenGL 或 DirectX 进行硬件加速?实现这一点需要了解实际的 GPU 架构吗?

在讨论为何选择使用OpenGL或DirectX时,指出这两个是唯一能够有效访问3D硬件的API。现代计算机的CPU无法高效地进行图形渲染,因此必须使用GPU来渲染游戏。虽然自己编写渲染器作为教育项目,但最终不会将其作为游戏的主要渲染方式,因为CPU渲染无法与GPU渲染的速度相比。

问:你怎么看待 Khronos 的 Vulkan?

对于Vulkan的看法,目前尚未收到其规格说明,因此无法做出具体评价。理想情况下,希望硬件接口尽可能简化,理想的状态是通过环形缓冲区与硬件直接交互,而不需要驱动程序。如果Vulkan比现代OpenGL更接近这一目标,那么它会是一个积极的进展。具体好处取决于Vulkan的设计质量,如果设计得当,将是一个显著的提升;如果设计不理想,则可能仍然是一个改进,但不那么显著。

问:当你知道如何编程但没有艺术技能时,做游戏的最佳方式是什么?找个艺术家来为你做吗?这是我的软肋,但我想自己做个游戏

如果有编程能力但缺乏艺术技能,最好的方法是雇佣一位艺术家来完成视觉设计。但如果预算不足,或者没有艺术技能,可以考虑制作程序生成的游戏。很多成功的程序员都通过简单的艺术风格获得了受欢迎的游戏。可以尝试制作3D游戏,利用光照来弥补艺术设计的不足,或者通过简化图形定义来减少对复杂艺术内容的需求。

例如,可以通过几何形状来创建游戏视觉,或者借用现有的视觉设计,比如《迷你地铁》这款游戏,它的视觉设计非常简洁,主要是基于地铁线路图。因此,即使没有高端的艺术制作能力,也可以通过借鉴已有的简单设计来构建游戏,避免被艺术内容所限制。总之,如果无法承担艺术制作,最好定义一个能够不依赖复杂艺术而依然能吸引玩家的游戏设计理念。

相关文章:

游戏引擎学习第77天

仓库: https://gitee.com/mrxiao_com/2d_game 回顾昨天的 bug 今天我们继续开发进度,进行调试昨天代码的问题,主要是关于如何跟踪玩家和敌人在世界中的高度位置。虽然我们做的是一款 2D 游戏,但我们希望能够处理多层的房间,玩家…...

Python编程实例-机器学习中的Hinge Loss编程实现

机器学习中的Hinge Loss编程实现 文章目录 机器学习中的Hinge Loss编程实现1、机器学习中的损失函数是什么?2、什么是 Hinge Loss?3、Hinge Loss如何工作?4、Hinge Loss的优缺点5、Python语言实现6、总结Hinge Loss(铰链损失)在分类任务中至关重要,广泛应用于支持向量机 …...

算法练习----2025/1/7

题目 计算素数函数f(N)代表素数的个数小于等于N例如 f(17)7 , 因为前7个素数为 2,3,5,7,11,13,17思路 1、首先创建一个布尔类型的数组(Python 中用列表模拟)来标记每个数是否为素…...

【C++】穿越编程岁月,细品C++进化轨迹,深化入门基石(续章)——揭秘函数缺省参数的魅力、函数重载的艺术、引用的奥秘与内联函数的效率

文章目录 一、函数缺省参数二、函数重载三、引用1.引用的概念和定义2.引用的特性3.引用的使用4.const引用5.指针和引用的关系 四、inline内联函数和nullptr1.inline2.nullptr 一、函数缺省参数 缺省参数其实就是默认参数,它是声明或定义函数时为函数的参数指定⼀个缺…...

1/7 Spring三级缓存

首先我们来spring创建bean首先通过反射创建bean原始对象,然后通过 填充里面的属性,然后如果有AOP的话,那么就会创建这个代理对象,最后将代理对象传入这个单例池中 如何解决循环依赖问题的 比如A依赖B,B依赖A 如果在单例池没有找…...

【RK3568笔记】Android修改开机动画

概述 Android 的开机动画是由一系列连续的 PNG 图片作为帧组成的动画形式,不是一张 GIF 图片。将各帧 PNG 图片以压缩方式进行保存(压缩方式要求是存储压缩),并将保存的文件名命名为 bootanimation.zip,这个 bootanim…...

牛客网刷题 ——C语言初阶(5操作符)——JZ15 二进制中1的个数

1.题目描述 题目OJ链接 描述 输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。 2.思路 求2进制中1的个数,可以转换为求每一位,1的个数,1&1还是1 所以判断如果该数值&1为真,我们就co…...

Lua语言中常用的字符串操作函数

string.sub(s, i, j) 功能: 截取字符串 s 中从位置 i 到位置 j 的子字符串。 local s "Hello, Lua!" print(string.sub(s, 1, 5)) -- 输出 "Hello" print(string.sub(s, 8, 11)) -- 输出 "Lua!" string.len(s) 功能:将字符串长度…...

SpringBoot 2.6 集成es 7.17

引言 在现代应用开发中,Elasticsearch作为一个强大的搜索引擎和分析引擎,已经成为许多项目不可或缺的一部分。Spring Boot作为Java生态中最受欢迎的微服务框架之一,其对Elasticsearch的支持自然也是开发者关注的焦点。本文将详细介绍如何在S…...

Elasticsearch:搜索相关性

这里写目录标题 一、相关性的概述二、自定义评分策略1、TF-IDF算法2、BM25算法 三、自定义评分策略1、Index Boost:在索引层面修改相关性2、boosting:修改文档相关性3、negative_boost:降低相关性4、function_score:自定义评分5、…...

nlp培训重点-2

1. 贝叶斯公式 import math import jieba import re import os import json from collections import defaultdictjieba.initialize()""" 贝叶斯分类实践P(A|B) (P(A) * P(B|A)) / P(B) 事件A:文本属于类别x1。文本属于类别x的概率,记做…...

Python判断、循环练习

01 02 03...

基于ROS先验地图的机器人自主定位与导航SLAM

2021年学习,当时参加科大讯飞的智能车大赛, 【语音交互启动-teb算法路径规划A*算法自动避障路径最短优化yolo5目标检测视觉结果判断分类终点指定点位自动泊车语音播报。】 【讯飞学院】http://www.iflyros.com/home/ 一、全局路径规划中的地图 栅格地图&…...

计算机网络与服务器

目录 架构体系及相关知识 三层架构: 四层架构: 常见的应用的模式: OSI模型 分层 数据链路层 TCP/IP模型 TCP和UDP都是传输层的协议 TCP三次握手、四次次分手 URL&HTTP协议详解 网址URL 结构化 报文行 报文头 空行 报文体…...

IP查询于访问控制保护你我安全

IP地址查询 查询方法: 命令行工具: ①在Windows系统中,我们可以使用命令提示符(WINR)查询IP地址,在弹窗中输入“ipconfig”命令查看本地网络适配器的IP地址等配置信息; ②在Linux系统中&…...

在 ASP.NET CORE 中上传、下载文件

创建 Web API 来提供跨客户端和服务器的文件上传和下载是常有的事。本文将介绍如何通过 ASP.NET CORE 来实现。 首先在 Visual Studio 中创建空的 Web API 项目,然后选择目标框架 .Net Core 3.1。 创建名为 FileController 的控制器,提供操作文件的接口…...

ETCD未授权测试

一、测试环境搭建 首先拉取etcd镜像 docker pull quay.io/coreos/etcd:v3.3.1 # 查看镜像 docker images创建自定义网络 docker network create --driver bridge --subnet172.16.1.0/16 --gateway172.16.1.1 mynet # 查看网络 docker network ls创建etcd节点 节点1: docke…...

ffmpeg将mp4等文件转mp3

安装ffmpeg 目录 安装ffmpeg macOS Windows 实现方法 Base Golang macOS 在macOS上,你可以使用Homebrew来安装FFmpeg,这是最简单和推荐的方法。以下是具体步骤: ‌安装Homebrew‌(如果尚未安装): 打开终端,执行以下命令来安装Homebrew: /bin/bash -c "$(c…...

python学习笔记—15—数据容器之列表

1. 数据容器 列表(list)、元组(tuple)、字符串(str)、集合(set)、字典(dict) 2. 列表 (1) 定义 tmp_list ["super", "carry", "doinb"] print(f"tmp_list {tmp_list}, tmp_list type is {type(tmp_list)}") tmp_list1 ["doi…...

基于MATLAB的汽车热管理模型构建

一、引言 汽车热管理系统对汽车性能、部件寿命及驾乘体验至关重要。它能确保发动机、电池等关键部件在适宜温度工作。MATLAB 功能强大,为构建高精度热管理模型提供有效途径,助力优化系统设计与控制策略。 二、汽车热管理系统构成 2.1 发动机冷却系统&…...

MySQL的主从复制

MySQL 主从复制详解 MySQL 的主从复制是一种用来实现数据同步的机制,可以将一个 MySQL 实例的数据同步到一个或多个从库(Slave)实例中。它广泛应用于数据备份、高可用架构、读写分离、负载均衡等场景。 1. 主从复制的基本概念 主库&#xff…...

playwright 录制

一、新建项目TestProject3 二、准备swagger 三、开始录制 打开PowerShell 7 (x64) cd D:\xxx\xxx\VS2022Projects\TestProject3\TestProject3\bin\Debug\net8.0 pwsh playwright.ps1 codegen --targetcsharp -b chromium localhost:5252/swagger/index.html #支持的语言 java…...

Azure主机windows2008就地升级十步

Azure上云主机的windows2008系统需要进行就地升级。 按着微软的升级路径:win2008-->win2012-->win2016-->win2022 第一步:创建快照备份,防止升级失败第二步:升级托管磁盘,在VM管理的地方将磁盘升级成托管磁盘…...

MySQL 主从复制 的原理、配置和如何实现 主从灾备

1. MySQL 主从复制原理与工作流程 MySQL 的主从复制本质上是一个 基于事件的日志传输系统。在这个系统中,所有对数据的修改(如 INSERT、UPDATE 和 DELETE)会在 主数据库 上记录到 二进制日志(binlog),然后…...

本地多卡(3090)部署通义千问Qwen-72B大模型提速实践:从龟速到够用

最近在做文本风格转化,涉及千万token级别的文本。想用大模型转写,在线的模型一来涉及数据隐私,二来又不想先垫钱再找报销。本地的7-9B小模型又感觉效果有限,正好实验室给俺配了4卡3090的机子,反正也就是做个推理&#…...

高级数据库系统 复习提纲

第一章 数据库技术的回顾与发展 简述三代数据库的发展历史及其对应特点: 新型数据库在“数据模型”上的创新: 简述数据库和什么相关技术结合,产生了什么新型数据库? 1. 数据库和并行处理技术结合,产生“并行数据库”…...

Python编程实例-特征向量与特征值编程实现

特征向量与特征值编程实现 文章目录 特征向量与特征值编程实现1、什么是特征向量2、特征向量背后的直觉3、为什么特征向量很重要?4、如何计算特征向量?4、特征向量Python实现5、可视化特征向量6、总结线性代数是许多高级数学概念的基石,广泛应用于数据科学、机器学习、计算机…...

十年后LabVIEW编程知识是否会过时?

在考虑LabVIEW编程知识在未来十年内的有效性时,我们可以从几个角度进行分析: ​ 1. 技术发展与软件更新 随着技术的快速发展,许多编程工具和平台不断更新和改进,LabVIEW也不例外。十年后,可能会有新的编程语言或平台…...

第6章——HTTP首部

第六章——HTTP首部 HTTP报文结构 ​ 都必有报文首部 HTTP请求报文 HTTP响应报文 HTTP首部字段 ###传递重要信息 首部字段结构 ​ 首部字段名:字段值(,字段值,字段值) 首部字段类型 ​ 通用首部字段 请求首部字…...

Java多线程

一、线程的简介: 1.普通方法调用和多线程: 2.程序、进程和线程: 在操作系统中运行的程序就是进程,一个进程可以有多个线程 程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念; 进程则是执行程序的一次执…...

C++ 复习总结记录四

C 复习总结记录四 主要内容 1、构造函数其它要点 2、static 成员 3、友元 4、内部类 5、匿名对象 6、拷贝对象时编译器的优化 一 构造函数其它要点 1.1 构造函数体赋值 创建对象时,编译器调用构造函数,给对象中各个成员变量一个合适初始值 cl…...

Oracle Dataguard 需要配置的参数详解

Oracle Dataguard 需要配置的参数详解 目录 Oracle Dataguard 需要配置的参数详解一、数据库名:DB_NAME二、数据库唯一名:DB_UNIQUE_NAME三、LOG_ARCHIVE_CONFIG四、LOG_ARCHIVE_DEST_1五、LOG_ARCHIVE_DEST_2六、LOG_ARCHIVE_DEST_3七、LOG_ARCHIVE_DES…...

Java 内部类与异常类

目录 1.Java 内部类 2.Java 匿名类 1. 匿名类继承一个父类 2. 匿名类实现一个接口 3.Java 异常类 4.Java 异常的分类 1. Throwable类 2. Error类 3. Exception类 5.Java 常见的异常 1. NullPointerException(空指针异常) 2. ClassCastException(类转换异常) 3. In…...

Matlab仿真径向受压圆盘光弹图像

Matlab仿真径向受压圆盘光弹图像-十步相移法 主要参数 % 定义圆盘参数 R 15; % 圆盘半径,单位:mm h 5; % 圆盘厚度,单位:mm P 300; % 径向受压载荷大小,单位&#xff…...

补偿电阻对ota零极点的影响

本文内容主要是关于补偿电阻对零极点产生的影响。 1.极点分析 该补偿电阻并不会影响在输出端的主极点,受影响的主要是镜像极点。 这里我们可以先单看电流镜部分,这个补偿电阻的作用在于将极点推向原来的两倍,从而达到增加带宽的目的[1]。 …...

C++单例模式跨DLL调用问题梳理

问题案例: 假设有这样一个单例模式的代码 //test.h header class Test { public:static Test &instance() {static Test ins;return ins;}void foo(); };void testFoo();//test.cpp source #include "test.h"void Test::foo() {printf("%p\n&q…...

Linux高并发服务器开发 第十天(man手册 系统调用 文件打开关闭 文件创建权限)

目录 1.文件IO 1.1man 手册 1.2系统调用 1.3操作函数 1.3.1打开文件 1.3.2关闭文件 1.4文件创建权限 1.文件IO 1.1man 手册 man man 可以查看。man手册共 9 卷。 可执行程序、shell命令。系统调用函数。(内核提供的函数)库函数第 5 卷。查看特殊…...

用CRD定义未来:解锁机器学习平台的无限可能

Kubernetes CustomResourceDefinition(CRD)详解 一、CRD 概述 CRD(CustomResourceDefinition,自定义资源定义)是 Kubernetes 提供的一种机制,用于用户自定义新的资源类型。CRD 扩展了 Kubernetes API&…...

A second-price auction

第二价格密封拍卖(A second - price auction)是一种常见的拍卖形式,以下是一个用收益矩阵(Payoff Matrix)来说明第二价格密封拍卖的例子: 假设有三个竞拍者:A、B、C,他们对一件古董…...

MacBook_Xcode_Swift雨燕

Swift Swift Swift Swift是苹果公司开发的现代化编程语言, 专为Apple平台设计。其简洁语法、类型安全、Optionals处理、Playgrounds交互式环境、泛型编程、协议与扩展、闭包功能、枚举与关联值、结构体与类的高效内存管理、异步编程的async/await语法、Swift Packa…...

力扣面试题 - 08.07.无重复字符串的排列组合 C语言解法 回溯递归dfs深度优先

题目: 无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。 示例 1: 输入:S "qwe"输出:["qwe", "qew", "wqe", "…...

数值分析速成复习笔记

请确保你有10hour的有效学习时间,保你拿90 证明部分 编程部分...

1.07 标准IO

1.思维导图 2.先编写以下结构体 struct Student { char name[20]; double math; double chinese; double english; double physical; double chemical; double…...

单片机实现模式转换

[任务] 要求通过单片机实现以下功能: 1.单片机有三种工作模式(定义全局变量MM表示模式,MM1,2,3表示三种不同的模式) LED控制模式 风扇控制模式 蜂鸣器控制模式 2.可以在某一个模式下通过拓展板KEY1按键控制设备 (按…...

JVM实战—OOM的定位和解决

1.如何对系统的OOM异常进行监控和报警 (1)最佳的解决方案 最佳的OOM监控方案就是:建立一套监控平台,比如搭建Zabbix、Open-Falcon之类的监控平台。如果有监控平台,就可以接入系统异常的监控和报警,可以设置当系统出现OOM异常&…...

GolangWeb开发- net/http模块

文章目录 Golang开发-案例整理汇总一、net/http介绍二、HTTP客户端Get请求Post请求三、HTTP服务端总结Golang开发经典案例,点击下方链接 Golang开发-案例整理汇总 一、net/http介绍 Go语言内置的net/http包提供了HTTP客户端和服务端的实现。 文档链接: https://pkg.go.dev/n…...

算法:线性查找

线性查找算法是一种简单的查找算法,用于在一个数组或列表中查找一个特定的元素。它从数组的第一个元素开始,逐个检查每个元素,直到找到所需的元素或搜索完整个数组。线性查找的时间复杂度为O(n),其中n是数组中的元素数量。 实现原理 从列表的第一个元素开始,逐个检查每个…...

基于 Boost.Asio 和 Boost.Beast 的异步 HTTP 服务器(学习记录)

已完成功能: 支持 GET 和 POST 请求的路由与回调处理。 解析URL请求。 单例模式 管理核心业务逻辑。 异步 I/O 技术和 定时器 控制超时。 通过回调函数注册机制,可以灵活地为不同的 URL 路由注册处理函数。 1. 项目背景 1.1 项目简介 本项目是一个基于…...

『SQLite』常见函数的使用

摘要:主要讲解SQLite中的常见函数,有聚合函数、数字函数、字符串函数、日期函数、类型转换函数等。 主要函数 聚合函数:count()、sum()、avg()、min()、max()字符串函数:length()、upper()、lower()、substr()、trim()日期和时间…...

win下搭建elk并集成springboot

一、ELK 是什么? ELK 实际上是三个工具的集合,Elasticsearch Logstash Kibana,这三个工具组合形成了一套实用、易用的监控架构,很多公司利用它来搭建可视化的海量日志分析平台。 ElasticSearch ElasticSearch 是一个基于 Lucen…...