游戏引擎学习第79天

当前任务回顾

我们目前的工作重点是碰撞检测的更新,特别是将游戏的世界表示方式扩展到三维空间。尽管游戏本身是二维的,但我们希望它能够在三维空间中处理更多的内容,以支持那些需要考虑高度的游戏元素,如楼层、台阶等。我们的目标是避免在实现过程中加入过多的临时性解决方案,因此我们正通过一些简单的方式来逐步理解如何更好地实现这一目标,以便最终能形成一个更通用、更完善的代码结构。

目前,游戏的世界表示已经取得了不错的进展,但仍然存在一个重要问题:我们缺乏一个明确的理论基础来表示"地面"。在一个传统的二维游戏中,并不需要关心"地面"的概念,因为角色只是简单地在一个平面上移动。然而,在这个项目中,游戏的目标是更复杂和更具层次感,我们希望能够支持多层楼、台阶等元素的存在,并且实现无缝的游戏玩法和渲染。比如,玩家可能需要在楼梯上与敌人战斗,或者从高处攻击一个大怪物。为了支持这些设计,我们需要为这些层次上的"可行走区域"提供清晰的定义。

接下来的任务就是解决这个问题,找到一种合适的方式来表示不同层次的地面和可行走区域。虽然有多种方式可以解决这个问题,但目前还不确定最优方案是什么,因此今晚将开始探索这个问题并进行讨论。

game.h: 查看TODO列表

在开始之前,我们首先进行一些讨论,以便决定如何处理"地面"问题。尽管目前我们不需要启动编辑器,还是会先启动它,但大部分的讨论将在黑板上进行。我们需要先确定清楚地面到底是什么,以及如何在碰撞检测系统中有效地处理它。

首先,会快速查看待办事项清单,确保没有遗漏需要处理的其他任务。不过,经过检查,似乎并没有其他紧急事项需要优先处理。因此,接下来的重点是理清如何处理地面的问题。

目前的想法是,先解决地面概念和碰撞检测系统的相关问题,再开始细化其他内容。因为这些任务彼此之间并不直接关联,而地面概念在系统性层面的影响较大,所以处理地面的方式有助于顺利推进后续的碰撞检测工作。

Blackboard: 《Quake》与《Unreal》

开始讨论时,提到了一些游戏历史方面的内容,并表示这些内容可能对如何处理"地面"问题有所启发。讨论的核心是关于《Quake》和《Unreal》在构建游戏世界时使用的方法,而不仅仅是这两款游戏之间的对比。特别地,讨论了这两款游戏使用的"构造性实体几何"(Constructive Solid Geometry,简称CSG)模型。

CSG是一种通过将世界构建成多个"Brush"来创建的方式,这些"Brush"本质上是多面体(polytope),即在三维空间中的某种形状。创建世界时,通过在空间中放置这些"Brush",可以定义空间的填充或空旷区域。例如,通过将这些形状放置在不同的位置,可以在游戏中构建一个房间,里面有柱子等物体。

CSG的特点是,它明确区分了"内外"区域,构建的世界是一个封闭的几何体,这与现代游戏中常见的"多边形"模型不同。后者由一组三角形构成,没有清晰的内外定义,可能存在空洞、裂缝或者类似树枝等突出部分。这种多边形汤方式没有CSG那样的固体几何体的明确界定,而CSG则创建了一个更加稳健的世界模型,确保所有物体都有一致的"实心"与"空心"定义。

Polygon Soup 是一种常见的3D图形表示方式,尤其在现代游戏开发中使用。它指的是将物体的表面表示为一组不规则的多边形(通常是三角形)集合,而这些多边形之间没有明确的结构关系。具体特点包括:

  1. 缺乏封闭性:Polygon Soup中的多边形没有明确的"内外"定义,形状之间可能存在空隙、裂缝或不规则连接。这与构造性实体几何(CSG)形成对比,后者通过明确的封闭几何体定义空间。

  2. 灵活但不严谨:由于Polygon Soup的结构相对灵活,开发者可以自由地将多边形拼接成复杂的模型。然而,这种灵活性可能导致模型的几何形状不完整,或者存在一些物理和渲染上的问题(例如,无法清楚区分表面朝向或内部和外部空间)。

  3. 多边形集合:在Polygon Soup中,模型被表示为由多个不连接的三角形或其他多边形组成的"汤"------这些多边形有时可能只是独立存在的平面碎片,缺乏统一的物理空间定义。

这种表示方式虽然在性能和灵活性上有优势,但通常需要额外的计算和处理来确保正确的物理模拟(例如碰撞检测、阴影计算等)。它更多依赖于计算机图形学中的几何学算法,而不像CSG那样通过明确的几何约束来定义和构建世界。

Blackboard: 《Quake》的"构造性固体几何体"范式

《Quake》和《Unreal》这两款游戏都采用了构造性实体几何(CSG)方法,尽管它们使用了不同的方式来实现这一方法。在《Quake》的世界构建中,采用了"填充然后雕刻"的方式。具体来说,游戏世界的初始状态是一个完全填充的实体块,表示整个世界最初是实心的。然后,开发者通过"雕刻"的方式来定义空间。

可以想象,在二维的情况下,世界就像是一个巨大的实心方块。开发者首先从这个方块中雕刻出一个房间,再雕刻出另一个房间,甚至可以雕刻出连接这些房间的走廊。通过这种方式,空闲空间就被定义为雕刻出的区域,而未雕刻的部分则被视为实心区域。

值得注意的是,在《Quake》的构建过程中,雕刻不仅仅局限于移除空间。开发者也可以添加"刷子"来填补空间,进行增减操作。因此,尽管起始时一切都是实心的,后续也可以进行空间的增减操作,以创建复杂的环境。

Blackboard: 《Unreal》的"构造性固体几何体"范式

与《Quake》的"填充然后雕刻"方式相反,《Unreal》采用了"从空到满"的构建方法。具体来说,游戏世界从空的开放空间开始。如果要创建一个房间,开发者会首先在房间的四周放置墙壁刷子,然后通过这些墙壁刷子将房间填充起来。这样,最终得到的世界就是有一个空旷的区域,内部也是空的,外部则有一个实心的边界。

这种方式与《Quake》的方式有很大的不同。虽然这些方法是很久以前使用的,但它们在2000年代初期的开发周期中仍然是有效的。尽管如今《Unreal》引擎已经不再使用构造性实体几何(CSG)方法,并且许多游戏早在2005年左右就放弃了这种方法,但在一些经典的游戏引擎中,像《Half-Life》这样的引擎,CSG的概念仍然存在了一段时间,直到后来才完全转向基于多边形汤的表示方式。

Blackboard: 这两种模型的区别

讨论的重点是《Quake》和《Unreal》两种不同的构建世界的方法。首先,《Quake》的构建方法从填充整个世界开始,然后进行雕刻,只有雕刻出来的区域才是空的,而其余部分则是实心的。这种方法的优点是,整个世界始终是实心的,玩家无法无意间掉出世界外,因为没有"外部"存在。

与此相对,《Unreal》的构建方法则是从空的开放空间开始,通过添加墙壁来定义空间,空的部分是从内部开始的。这样,如果设计师不小心,可能会创建出一个看似正常的房间,但实际上存在一个小的缝隙,玩家可能恰好从这个缝隙跳出去,掉出游戏世界,陷入无限掉落,直到遇到某种"救援"机制或最终回到世界内。

《Quake》的方法确保了世界的实心性,玩家无法穿越没有雕刻出来的区域,而《Unreal》方法则可能因为设计疏忽,导致玩家意外地掉出世界。这种区别在早期的关卡编辑器中非常明显,尽管随着技术的发展,这些问题可能有所改变。

Blackboard: 稳定性与效率

讨论中提到,从游戏历史中可以学到一个重要的教训,即在设计中,首先需要关注游戏的稳健性,而不是单纯追求效率。尽管效率很重要,但如果这样做可能引入可能破坏游戏体验的 bug,那么优先确保游戏的稳健性更为关键。特别是当考虑到玩家可能会遇到会影响游戏进程的 bug时,必须优先考虑避免这些问题,而不是追求性能上的最优化。

这个观点反映了游戏开发中如何平衡性能和稳健性的挑战。虽然开发复杂的游戏难免会有 bug,但通过优先确保游戏的健壮性,减少让玩家遇到严重 bug 的可能性,可以大大提升游戏体验。因此,尽管可能会牺牲一些效率,重点还是应该放在确保玩家不会进入不该进入的情境,例如从游戏世界外掉出去。

Blackboard: 提议不再讨论"地面"或"楼层",而使用"房间"

在这个讨论中,提出了一种新的思路来定义和处理"地面"和"楼层"的概念。与其将地面看作固体或平面,建议将其视为一系列可以行走的"区域"。这些区域被定义为"空地",即可以移动的空间,而玩家站立在这些空地上。如果玩家进入不再是空地的区域,则表示他们已经越过了"地面"或"楼层"的边界。

具体来说,我们不再考虑地面或楼层,而是关注这些"空地"区域,并定义这些区域为玩家可以走动的空间。如果玩家越过空地的边界,就进入了一个"非空"区域,这就表示"地面"的位置。因此,地面实际上是指那些如果玩家穿过,玩家将掉落到非空区域的边界。

这种方法的关键在于,所有的空地区域都是重叠的,构成了玩家可以穿越的连续区域。玩家将被限定在这些区域内,任何移动都不允许使他们越过这些区域的边界。如果玩家尝试走出这些区域,系统会强制阻止他们的移动,以确保他们始终处于一个有效的空地区域内。

此外,地面的定义将被简化为一个非常基本的游戏风格探测方法:每次玩家移动时,系统都会检查玩家当前位置的下方,找到第一个玩家会进入的非空区域边界。如果玩家尝试穿过这个边界,系统将阻止其继续移动。

这种方法也提供了额外的安全保障。如果没有完全定义的空地区域,系统将设置一个隐形的墙壁,防止玩家进入虚空或无意义的区域。这个隐形墙壁可以通过显示某种模式(如树木或岩石)来提示玩家当前正处于问题区域,从而让问题显现出来。

在碰撞检测的实现上,如果玩家从一个空地区域移到另一个区域,系统将对这两个区域进行测试,确定玩家是否可以继续前进。如果玩家试图跨越多个区域,系统将根据与每个区域的接触情况,决定最远的有效区域并允许玩家继续移动。这一过程涉及到使用交集测试和进一步的碰撞检测来决定玩家的最终位置。

最后,关于玩家移动和碰撞处理的策略,讨论提到可能会使用一种更传统的方法来处理水平运动,并结合一定的竖直运动检测。虽然在一些复杂的地形,如坡道或坡度变化较大的地方,可能需要额外的逻辑来处理,但大多数情况可以通过简单的水平运动和下落处理来解决。

Blackboard: 从平台上走下来会发生什么?

当角色从一个坡道或楔形结构上走下时,会发生什么?这个问题的答案并不明确。考虑到现实中如果这种结构存在,角色通常会掉下去,因此可以让角色从坡道上掉下来。与构建一个有底无底的房间不同,这里不需要标记无底的区域为碰撞体,因为假设这不是一个底less pit,而是一个正常的场景。假如角色能够从某个位置掉下去,并且可以看到下方的景象,那么自然的处理方式是允许角色跳下去。

如果不希望角色跳下去,可以考虑通过添加一个合成的碰撞体来防止角色从这个位置掉下去。但是,直接让角色掉下去,落到下方的地面上,是一个更简单、合理的方案。对于这个问题,基本上并不需要过多的复杂处理。

因此,处理这种情况时,最合适的做法是:在角色从坡道或楔形结构上走下时,进行一次向下探测,找到角色将要落到的地面,并将角色位置设置到那儿。这样做既符合物理现实,也保持了碰撞检测的简洁性。

game_sim_region.h: 添加 EntityType_Space 实体类型

开始时,首先需要创建房间的切割区域,因为这是最合理的做法。为了让角色能够在房间中行走,必须先创建一个房间。因此,我们将这个区域称为一个实体类型,可能叫做"屋顶"或"空间",因为它本质上就是一个空间。

这个"空间"将成为一种非常特殊的实体类型,它将负责切割我们世界的大部分区域。这是一个有趣的概念,特别是在引入了复杂的碰撞体积后,单一的空间实体不仅可以作为一个房间,还能变形成类似洞穴的结构,甚至可以根据需求进行形状的调整。

这个设计非常有趣,但目前还不确定将会有多少实际应用,未来的开发过程中可能会逐步探索如何充分利用这一特性。

game.cpp: 实现创建 EntityType_Space 的功能

为了实现空间实体的创建,首先将定义一个特殊的空间实体类型,用于表示房间和其他区域。接下来,通过绘制简单的矩形来可视化这些实体,虽然初步的渲染可能不太美观,但目的是验证这些实体是否在预期的位置。为此,采用与之前处理楼梯时相同的方法,逐一绘制矩形。

在处理碰撞时,空间实体将拥有多个碰撞体积,针对每个碰撞体积,逐个绘制其区域。这需要对每个体积进行遍历,获取其碰撞范围并进行渲染。具体而言,每个碰撞体积的渲染会基于其在空间中的位置进行调整。

在访问这些碰撞体积时,原本打算进行一些偏移计算,但意识到实际上系统已经处理了这些偏移。因此,不需要手动进行位置调整,可以直接获取实体的实际位置并进行渲染。

为了进一步简化工作,决定使用直接的空间位置计算,而不需要额外的偏移处理。只需提供实体的基本维度(如x和y坐标),系统就能够自动处理其他参数。这种方法减少了不必要的操作,使得渲染变得更加直接有效。

在实施过程中,虽然有些预期的功能未能顺利实现,但通过调整代码,最终能够正确渲染实体,并验证它们的位置。

game.cpp: 引入 AddSpace

在设计房间的过程中,首先需要创建一些空的空间区域,用于在房间中进行布置。这个过程相对简单,关键是在房间内创建重叠的空间区域。当前并不需要对空间的具体布局进行精确计算,因为这种规划会在后续的世界生成中得到完善。

为了添加这些空间,首先需要通过设置具体的坐标范围来指定每个空白区域的范围。具体的做法是,定义一个范围,并以某种方式指定其边界值,例如指定一个区间的起始和结束位置。这些空白区域不需要非常复杂的定义,因为它们只是用于指示哪些地方是可以走动的区域。

定义空间时,可以指定一个中心点,并从该点向外延伸,来简化空白区域的创建。这比起使用角落坐标要更为方便,特别是在今后的世界生成时,这种方法会更为有效。对于高度的处理,也可以暂时设置为一个合理的固定值,例如九英尺,并且所有的度量单位都可以在"瓦片"单位下进行处理。

当前的重点是尽量保持简单,而不需要过多关注生成细节。虽然后期可能会对房间的空间和生成方式进行深入优化,但目前不需要过多投入精力。在这个阶段,关键是为房间预留一些空白空间,而这些空间将随着世界生成的推进变得更加复杂和合理。

在实现上,可以通过重用房间的碰撞数据,使得每个房间都能使用相同的碰撞体积。通过这种方式,可以避免重复创建碰撞体积,节省开发时间和资源,同时保持系统的灵活性和一致性。

最终,创建空间的方式和房间碰撞体的处理方式将会非常相似,通过添加相应的空间区域,并计算其绝对位置来完成。

game.cpp: 将 AddSpace 重命名为 AddStandardRoom,并添加 EntityFlag_Traversable

在进行房间的空间处理时,决定使用标准房间的碰撞体,并给该标准房间添加一个"可遍历"标志,表示该空间是可以通过的。这个标志的目的是在碰撞检测中标识出哪些区域是可以自由移动的。

添加该标志后,需要对碰撞体的结构进行清理,移除一些不再需要的字段。例如,EntityFlag_ZSupported(可能是之前的支持项)就不再需要了,collides(碰撞检测)字段也可以去掉,因为每个实体现在都有自己的碰撞体积,只需要通过设置体积数量为零来避免与其他对象发生碰撞。

为了设置标准房间的碰撞体,还需要调整碰撞检测的方式。现在,房间的碰撞体需要从一个中心点开始计算,而不是像之前那样从角落开始。具体来说,要计算房间的中心位置,并且加上半个单位的偏移量,使得碰撞体积的中心对准房间的中心。

此外,还需要在碰撞处理中设置房间的标准碰撞体。房间的墙壁将通过类似的方式进行处理,使用标准房间的碰撞体,并根据房间的尺寸来计算墙壁的深度和高度。墙壁的尺寸将基于"瓦片深度"的单位进行调整,调整后的大小适用于房间的宽度和高度。

最终,所有的碰撞体计算将依赖于这些调整过的标准房间碰撞体,并确保空间中可行走的区域被正确标识,避免不必要的碰撞或遮挡。

Blackboard: 相邻房间之间没有重叠

目前的实现方式下,如果有两个相邻的房间,它们之间不会有任何重叠,只有一个无限薄的线。这个设计在碰撞检测的计算上并不会造成太大的困难,但也不一定是最理想的做法。我们可以考虑做一些调整,比如允许房间之间有轻微的重叠,这样可以让数学计算更加宽松,过渡更加平滑。然而,暂时的计划是将房间的边界设置为完全接触,避免重叠。之后,当我们对碰撞检测的数学处理更加细致和全面时,可能会重新评估并优化这个设计。

game.cpp: 关闭 AddStandardRoom

在理论上,现在应该能够看到一些巨大的矩形,如果没有出错的话。然而,这也使得其他内容很难看到,但这正是预期中的效果。不过,矩形可能没有完全放置在正确的位置,尤其是在顶部,可能是由于z轴的原因。接着,尝试跳到下一层,看是否放置在更合理的位置,发现确实在一个合适的位置。接下来,问题是,为什么有时无法通过某些实体。尝试了一下,发现可以通过这些实体,这表明碰撞检测是有效的,尽管没有设置"collides"标志,这意味着可能存在一个bug,碰撞标志没有正确检查,因此需要进一步调试以找出问题所在。

game.cpp: 修正 sim_entity_flags 设置

经过检查,发现存在一个问题。首先,确认没有将"standard room"和"traversable"标志设置为相同的值。尽管标志的设置似乎没有问题,但仍然出现了意外的碰撞问题。进一步调试发现,碰撞标志没有被正确检查。实际上,这个标志被完全忽略了,没有被使用,而是直接跳过了该检查。这表明这是一个明确的bug,需要进一步查找为什么会发生这种情况,特别是在标准房间的碰撞检测中。

game_sim_region.cpp: 在 CanCollide 中检查 EntityFlag_Collides

在检查碰撞检测时,怀疑问题出在碰撞判定逻辑上。应该在进行碰撞判断时,检查"collides"标志是否为真。具体而言,若实体的"collides"标志为真,并且目标也可以碰撞,那么才进行碰撞判断。否则,默认假设实体可以碰撞。这样可以确保不会出现不该发生的碰撞,尤其是与某些对象的碰撞应被避免。

运行游戏并发现我们现在正确地不会与 StandardRooms 碰撞

在进行调试时,发现进入楼梯区域时,出现了更好的结果。

game.cpp: 引入 PushRectOutline

为了更好地查看区域,计划对现有的绘制调用进行简单修改。修改内容是使用多个矩形来绘制区域的边界,而不是填充一个大矩形,这样可以避免遮挡其他内容。这将通过绘制四个矩形的轮廓来实现,分别对应区域的四条边。虽然渲染尚未实现,但通过这种方法可以临时解决问题,直到有更完善的渲染处理。

Blackboard: 绘制 PushRectOutline

为了绘制围绕矩形的边界,计划创建多个矩形。这些矩形将分别位于原始矩形的四个方向。首先,计算矩形在y轴上的偏移量,并将其向上移动,然后再根据矩形的x轴尺寸绘制出左右两条边。通过调整矩形的y轴厚度和位置,可以绘制出轮廓线,确保它们正确地显示矩形的边界。

game.cpp: 继续编写 PushRectOutline

为了创建矩形的轮廓,计划调整矩形的偏移量,使用y轴的尺寸来移动矩形的上下边界,同时在x轴方向上使用相同的尺寸来绘制左右边界。为了确保轮廓线非常细,将厚度设置为厘米级别,确保它们不会太大,以便清晰地显示矩形的边界。这种处理将应用于矩形的四个边,并且通过修改矩形的厚度和位置,确保最终绘制出每个矩形的四条边,便于在没有完整渲染的情况下查看区域边界。

运行游戏并发现我们看不见轮廓

尝试绘制矩形轮廓时发现,矩形的线条过于细小,导致无法看到任何矩形。问题可能出在线条太细了,未能正确显示。

game.cpp: 增加 PushRectOutline 的厚度

尝试通过增加矩形轮廓线条的厚度来解决问题,同时确认是否正确应用了偏移。代码中的 push piece 方法和矩阵乘法处理偏移,理论上应该可以正常工作。为了验证效果,计划将线条厚度调大一些,观察显示的结果。

运行游戏并发现我们只绘制了一条线

在尝试调整矩形轮廓线条厚度后,结果显示仅绘制了一条线,明显不符合预期。这表明存在代码逻辑错误,需要进一步检查实现中的问题。当前确定的事实是,代码某处确实存在错误,需要仔细审查相关逻辑以定位问题所在。

调试: 步进到 PushRectOutline

问题描述了一种关于绘制矩形的调试过程,目标是查明为何某些矩形未能如预期显示。以下是对问题的详细总结:

  • 已经设定了厚度和维度,并执行了绘制操作,但结果中仅显示了左侧部分,其他部分没有如预期那样出现。这种情况被认为有些奇怪。
  • 当前存在的疑问是为什么某些矩形没有显示,而绘制时Push了四个矩形。
  • 通过代码检查发现,这些矩形有特定的 y偏移量,需要确认这些偏移量是否仍以米为单位。偏移量可能在某些步骤中被异常放大或调整。
  • 代码中偏移量的处理逻辑表明,它们应该被正确地倍增,因此逻辑上看似没有问题。
  • 在查看绘制的具体实现时,提到矩形的定义曾经出现问题,因此需要再次确认矩形的定义是否有误。
  • 当前的调试流程重点在于检查:
    1. 是否有对偏移量的错误计算或处理。
    2. 是否绘制逻辑中定义的矩形参数存在潜在问题。
    3. 推送到绘制管线的矩形数据是否正确匹配预期值。

总结来看,这一问题可能与矩形的偏移量处理或定义有关,调试的关键步骤包括验证数据的完整性以及绘制逻辑的正确性。同时提到,由于时间限制,未必能够在短时间内彻底解决问题,但希望避免遗留问题到次日处理。

game.cpp: 将维度乘以一半

问题描述了矩形绘制过程中发现的一个错误和可能的改进方向,具体如下:

  • 绘制矩形时,使用了中心点减去半维度(half dim)和中心点加上半维度的方式来计算矩形的范围。然而,发现在代码中忘记将维度(dim)乘以0.5来计算半维度。
  • 确认中心点的值应该是实体的地面位置点(entity ground point),从检查结果来看,该值是正确的。
  • 识别出忘记乘以0.5的问题,并计划修复此问题。但也提到,仅修复这一点可能无法完全解决当前的问题。
  • 后续计划包括修正此逻辑,并对矩形定义进行进一步检查和重新组合,以验证是否能解决问题。

总结来看,当前的主要问题在于矩形维度计算时未正确处理半维度,计划修复此错误后继续排查是否还有其他潜在原因导致绘制异常。

运行游戏并看到我们正确绘制的轮廓

问题描述了解决绘制矩形问题的过程,以及接下来的开发计划,具体如下:

  • 发现之前的问题确实完全源于忘记将维度(dim)乘以0.5计算半维度的错误,修复此问题后,矩形可以正确绘制。
  • 调试过程并不复杂,问题修复后,绘制的矩形与房间的边界能够很好地贴合,显示效果符合预期。
  • 在修复过程中,注意到顶部的绘制仍有问题,原因是缺少了 z 轴上的微调(zfudge)。修复此问题后,绘制在不同楼层的矩形也能正确显示。
  • 房间边界的绘制已经完成,设置工作为后续开发打下了基础。
  • 接下来的开发计划包括多阶段房间的创建和处理。若时间允许,将在当前流程中实现多阶段房间的功能,否则会将相关工作推迟到后续的开发中进行。
    总结来看,当前问题已经解决,矩形的绘制功能恢复正常,并为后续开发目标(如多阶段房间的实现)提供了良好的基础。

Q&A

在 Linux 上你使用什么调试设置?

内容主要描述了在 Linux 系统上进行调试的经验和遇到的问题,具体如下:

  • 在 Linux 上调试时,主要依赖 printf 方法进行调试,采用了较为传统的方式。
  • 调试器在 Linux 上的表现非常不理想,尤其是在笔记本电脑上,几乎无法正常工作。笔记本上的 Optimus 技术会导致进一步的问题。
  • 尝试使用过 Qt Creator 作为调试工具,但发现其变量检查功能经常无法正常运行,无法有效地帮助调试。
  • 使用 GDB 也经常遇到问题,整体体验较差,Linux 上的调试工具显得非常落后。
  • 提到早期编程时没有现代化的编辑器,因此习惯了依赖基本工具和手动调试方式来解决问题。
  • 强调目前 Linux 最大的缺陷之一是调试器体验较差,这在开发过程中是一个重大障碍。
  • 对未来可能出现功能完善的调试工具表示期待,这将极大改善 Linux 上的开发环境。目前其他语言可能拥有更好的调试工具(例如 Java 的调试工具),但 C++ 和 OpenGL 在 Linux 上的调试体验尤为糟糕。

总结来看,当前主要依赖基本方法(如打印日志)进行调试,而 Linux 的调试器整体表现欠佳,尤其是在 C++ 和 OpenGL 的开发场景中,需要更高效的工具支持。

墙壁会作为实体吗,还是仅仅是通过减去房间体积而生成的副产品?

内容讨论了墙壁的实现方式以及不同房间类型对边界处理的差异,具体如下:

  • 墙壁可以通过实体或简单的边界盒(bounding boxes)来表示,这取决于房间的类型,设计上会保留两种方法的灵活性。
  • 对于一些场景,例如森林,可能会采用实体的方式来表示墙壁。这是因为树木通常形成不规则的边界,通过实体可以更准确地捕捉这种复杂形状。
  • 对于更规则的房间类型,例如地牢房间,可能直接通过裁剪边界来表示墙壁,而不需要单独的实体。
  • 目前对具体场景的处理方式尚未完全确定,将根据不同类型的房间特点来选择合适的边界表示方法。

总结来看,不同房间类型的墙壁处理方式将灵活选择,复杂场景(如森林)可能依赖实体,而规则场景(如地牢房间)可能选择简单的边界裁剪方式。

如果你能处理命令行界面,LLDB 比 GDB 更好用

内容讨论了调试工具的使用体验及选择,具体如下:

  • 提到 lldb 相较于 gdb 来说可能更好用一些,但由于其基于命令行界面的特性,使用效率较低。
  • 在命令行环境下进行调试的速度通常较慢,因此相比之下,使用 printf 方法进行调试反而更快。
  • 调试器的主要优点在于快速可视化代码中的变量值和状态,但这一功能在 gdblldb 中表现得并不理想。
  • 这些调试工具难以提供一个清晰的快照或视觉化的代码运行状态,这使得在实际开发中它们的帮助有限。
  • 总结认为,在目前的情况下,依旧倾向于使用 printf 这种传统方法进行调试,效率更高且直观。

总结:虽然存在调试器工具(如 lldbgdb),但由于其在快速可视化和用户体验上的局限性,更倾向于依赖 printf 调试方法,以实现高效的开发流程。

现在你有了 Space Z 体积的 0.9 值,是否应该能够跳到玩家上方的某个层级?

内容讨论了关于当前游戏系统中跳跃到上层的问题以及相关的碰撞检测现状,具体如下:

  • 提问中涉及一个特定的值(例如空间体积的 0.9 值),询问是否已经可以实现玩家跳跃到更高的层级。
  • 该值的设置并不起决定性作用,因为目前系统尚未实现对边界盒(inboxes)的碰撞检测逻辑。
  • 当前阶段仅仅实现了边界盒的添加和绘制功能,因此它们实际上不参与物理交互。
  • 进一步说明,当碰撞检测的完整闭环逻辑被实现后,才会评估是否能够跳跃到上层。如果跳跃无法实现,那将被视为一个错误;如果可以正常跳跃,则系统运行正确。
  • 当前的工作重点在于明天完成碰撞检测的闭环逻辑,之后才能进一步验证相关功能。

总结:由于碰撞检测逻辑尚未实现,目前边界盒仅起到绘制作用,无法参与物理交互,跳跃功能需待完整检测逻辑实现后进行验证和调整。

不在玩家 Z 层级的实体是否总是会保持相同的 alpha 透明度,还是会稍微减少以显示它们处于不同的 Z 层级?

讨论了在游戏中不同Z层级的实体如何呈现及其透明度问题,具体内容如下:

  • 关于是否应该对不在玩家当前Z层级的实体设置统一的透明度,或者通过轻微的可见度变化来表明它们处于不同的Z层,当前尚未明确,需要进一步的设计和实验。
  • 初步猜测是:
    • 当前玩家所在层级的实体和低于玩家层级的实体会保持完全不透明,展现为实心。
    • 高于玩家所在层级的实体将保持不可见。
    • 当玩家开始沿斜坡上行时,相机可能会向上移动,同时上层的透明实体逐渐淡入,完成可视化的过渡。
  • 目前的设计和实现主要是探索性的,没有固定的表现方案,更多是通过实际尝试来决定最终的实现方式。
  • 虽然过往的大部分游戏开发经验集中在3D游戏上,但此类2D设计对于如何处理层级显示及效果实现仍是一个全新的领域,需要反复尝试以找到最适合的方式。
  • 未来可能需要结合实际效果对不同设计方案进行取舍,并根据喜欢与否调整具体细节。

总结:透明度和层级显示的实现仍处于探索阶段,当前倾向于根据玩家所在的Z层级调整实体的可见性,并通过动态过渡实现更流畅的视觉体验,但具体方案需通过实验来验证其效果与可行性。

为什么没有已发布的商业游戏成功经验,大家应该如何相信你在注释游戏?

针对为何可以信任其注释游戏而质疑其没有完整开发商业游戏成功记录的问题,讨论如下:

  • 在编程领域,已经有大量代码被用于多款发布的商业游戏,数量达到数千个,包括特定技术(如Granny和Big)在内的广泛应用。
  • 尽管设计游戏的经验可能较少,但这并非游戏设计课程,而是游戏编程课程,强调的重点是技术实现,而非设计理念。
  • 通过编程技术为多个商业项目提供了支持,这些实际应用证明了技术能力和可靠性,能够胜任注释游戏相关的任务。

总结:尽管设计游戏的经验有限,但凭借在商业游戏开发中广泛应用的编程技术,足以证明在技术支持和注释游戏实现方面的能力。

如果你是软件程序员,你在相同的时间里能够开发多少个应用?

如果把同样的时间投入到开发应用程序中,考虑到不同的应用质量水平,可能的情况如下:

  • 如果只是快速制作一些简单的应用程序,比如展示 Twitter 动态的应用,使用预制库代码来搭建,时间上可以完成很多这种应用,因为它们的功能简单、效率不高、可能存在性能问题。
  • 但是,如果要开发一个高质量的应用程序,比如一个有趣的绘图工具,那可能就无法在短时间内做得太远。高质量的应用开发需要更多的时间来确保功能完善和用户体验。

因此,完成的应用程序数量取决于应用的复杂度和质量要求。

游戏中会有水吗?它会如何影响运动?

关于是否添加水以及水如何影响角色的移动,有些不确定。原本并没有考虑水的存在,考虑的更多是不可穿越的水域,类似于墙壁,只是看起来更美观。不过,经过更仔细的思考,随着设计上涉及进出框体的机制,确实可以考虑将某些框体定义为水域,在这些区域中,角色可能会下沉,或者可以游泳。水的处理方式仍不确定,因此这个问题还在考虑中。

提醒: 水体是否可以游泳,可能还会有水流?

决定将"水域"加入待办事项中,因为之前没有考虑到这一点。现在考虑到可能会在游戏中加入可以游泳的水域,甚至可能包括水流,水流可能会将角色拉动。这种设计可能会很有趣,因此决定将其加入待办事项,进一步探索这一元素。

这个方案中,房间几何体需要重叠才能在房间间移动,还是它们只需要相邻即可?

关于房间几何是否需要重叠才能在房间之间移动,理论上它们应该可以直接接触,不会有问题。然而,具体实现取决于墙壁交叉代码的编写方式。为了让数学处理更简便,可以在代码中做些松散的处理,可能会选择让房间略微重叠,以简化问题。因此,目前还不确定是否需要重叠,最终要看实现情况。

你能说明现代引擎如何进行关卡编辑器/世界布局吗?

在现代引擎中,关卡编辑器的世界布局方式通常有很大差异。例如,最新的引擎如 Frostbite 和 Snowdrop 并没有直接经验,所以不清楚它们的具体实现方式。而像 Unreal 和 Unity 这些老引擎,虽然比较陈旧,但它们仍然是很多游戏开发的主流。

在《The Witness》中的做法是,通过几何实例化的方式构建世界,开发者会在 Maya 或其他 3D 软件中制作网格,然后使用世界编辑工具将这些网格导入并放置在合适位置。这里没有"实心空间"或"构建滑块"的概念,只有简单的多边形网格拼接在一起。然后,通过标记为"可走"的网格来决定玩家可以移动的区域。这种方式非常直接,依赖于网格和标记,而不是复杂的空间定义。

对于一些更现代的引擎,具体做法并不清楚,因为没有直接使用过。

你会使用文件存储关卡吗?如果会,是自定义格式吗?

关于关卡存储,计划使用自定义格式来存储关卡数据。考虑到游戏存档和关卡保存的需求,选择自定义格式而不是标准库格式(如 XML),因为自定义格式可以提供更高的速度。

2D 游戏中的战斗算法是否与 3D 游戏不同?

关于战斗算法,在2D游戏和3D游戏中的实现可能会有所不同,具体取决于战斗算法的定义和具体实现内容。一些部分可能是相似的,而另一些部分则可能完全不同,这取决于具体使用的算法和战斗的设计。

如何与其他程序员合作,当我们的编码风格不合时?

当编码风格冲突时,如果指的是代码格式(如行宽限制)或者其他细节,通常可以通过相互妥协解决,例如尽量容忍其他人的风格差异,尤其是当这些差异不影响代码功能时。如果冲突较为严重,例如每个人的代码要求完全不同,可能需要划分代码区域,让每个人负责自己部分的代码,不干扰对方。关键在于确定冲突的程度,合理安排任务和沟通。

现在楼梯口是否需要围墙,还是我们仍然使用之前的碰撞规则?

对于楼梯是否需要围墙的问题,楼梯本身不会额外添加围墙,而是依然使用原来的碰撞规则。楼梯可能会被放置在某些区域的盒子内,并且在碰撞检测上进行改进,以更好地处理坡道区域的碰撞。

你打算生成程序化关卡,还是使用预定义关卡?

游戏的大部分内容将采用程序生成的方式,包括关卡的构建,除了艺术部分将是手工绘制的,可能较为随意。

这个直播中会展示光源、光线追踪、表面映射等内容吗?

在未来的开发中,光源一定会涉及到。如果是指实时路径跟踪或实时kd树跟踪,则可能不会实现。如果是指其他原因的光线追踪,则可能会考虑加入,但具体实施情况取决于对这些技术的定义。

我们开始做碰撞检测和处理了吗?如果没有,它将需要多详细?

目前已经开始进行碰撞检测的处理,尤其是在角色与树木发生碰撞的情况。虽然还没有编写最终版的碰撞检测器,但目前已经有一个运行中的碰撞检测系统。

你怎么看将游戏数据存储在代码中?

将游戏数据存储在代码中是可行的,但需要注意一些明显的问题。首先,这种方式不利于高效的分页,因此不能存储太多数据在代码中。另外,当数据存储在代码中时,编辑和修改会变得更加困难。如果需要通过图形界面编辑数据,虽然可以将代码放在单独的C文件中,并通过编辑器重写C文件来实现,但这种做法可能会带来更多麻烦。因此,选择这种方式时需要权衡优缺点,没有特别强烈的偏好,关键是了解相关的利弊再做决定。

相关推荐
dal118网工任子仪12 分钟前
58,【8】BUUCTF [PwnThyBytes 2019]Baby_SQL1
数据库·笔记·sql·学习·mysql
s_little_monster2 小时前
【Linux】打破Linux神秘的面纱
linux·运维·经验分享·笔记·学习·学习方法
无所谓จุ๊บ2 小时前
VTK知识学习(36)-图像平滑
学习·vtk
stormjun3 小时前
2025 年 Java 最新学习资料与学习路线——从零基础到高手的成长之路
java·开发语言·学习·java学习路线·java 学习教程·2025java 学习路线
【上下求索】3 小时前
学习笔记081——如何备份服务器中MySQL数据库数据?
数据库·笔记·学习
dal118网工任子仪3 小时前
55.【5】BUUCTF WEB NCTF2019 sqli
数据库·笔记·sql·学习·mysql·安全
隼玉4 小时前
【STM32-学习笔记-10-】BKP备份寄存器+时间戳
c语言·笔记·stm32·学习
yzx9910134 小时前
OpenCV入门学习
学习
黑不拉几的小白兔4 小时前
Python爬虫学习前传 —— Python从安装到学会一站式服务
爬虫·python·学习