游戏引擎学习第188天

回顾并计划今天的内容

原本这周的目标是进行可视化操作的尝试,但每一天都被一些棘手的bug和问题所阻碍,导致我们一直没能实现这个目标。直到今天,星期四,我们终于解决了这些问题,所有功能都能正常运行了,所以今天终于有机会进行这个可视化操作了。对于这个任务,我一直期待很久,终于可以开始着手做这件事了。

接下来,我们打开之前的调试工具,回顾一下目前为止的进展。通过这些调试输出,我们可以看到一些细节问题,接下来会重点关注这些内容。

游戏运行缓慢,因为每一帧都在收集过去64帧的所有调试事件

有一件事是显而易见的,就是随着游戏的进行,性能变得越来越慢。这是有原因的,因为我们将事件不断地积累到一个缓冲区,直到收集到64帧的调试事件。思考一下这意味着什么,可以看出,这表明我们不应该将所有事件都一起处理。我们可能应该在每次遇到帧边界时,就将该帧的调试信息存储起来,并以已处理的形式存储。这样我们就可以避免当前的麻烦。

因此,我觉得在这里我们需要进行一些组织工作,来优化处理方式。

将我们处理的调试帧数量从64减少到8

为了优化调试,我决定将调试帧数设置为较低的数字,这样我们可以先进行可视化的工作,因为我一直想做这个,但因为有一些bug被耽搁了。我要先处理可视化问题,然后再回过头来优化性能,避免占用太多时间。为了测试效果,我将最大事件数组的大小从34减少到8,这样处理的帧数就大大减少了。

测试结果表明,帧率大幅提高,性能显著改善。这样处理的效果很好,基本上能够确认这是一个合适的方案,之后如果我们将处理的帧数减少到1,性能会进一步提升为现在的1/8时间。

接下来,我想先花些时间把系统改造成一个对我们可视化有用的工具。目前我们能看到的一些信息还很粗糙,比如我们可以看到线程执行的渲染任务以及它们所消耗的时间,可以看到调试信息的处理情况以及等待帧的时间等,尽管这些信息已经能提供一定的帮助,但目前的可视化效果还不够清晰,界面看起来很杂乱,且信息展示不够直观。

之前的一个Bug

我们想从调试显示中提取更多信息

当前的可视化界面存在一些问题,我们虽然已经收集了大量的调试信息,但无法有效地查看这些数据。具体来说,当鼠标悬停在某个条形图上时,无法知道该条形图对应的实际数据,而且也无法放大或查看某个特定条形图的详细信息,比如显示该条形图内部包含的子进程或子函数,以及它们消耗了多少时间。这些信息虽然已经记录下来了,但我们没有办法与之交互,导致目前的调试界面看起来非常不直观,无法有效提取有用的数据。

为了解决这个问题,首先需要建立一个基本的用户界面,使得我们可以与这些调试信息进行交互。具体来说,可以通过点击某个条形图来查看该条形图的详细内容,逐步打开和查看数据。我想从实现一个最简单的功能开始,比如让用户能够点击条形图并查看相关的信息。

目前,我们已经实现了鼠标的位置获取功能,可以获取鼠标的 X 和 Y 坐标以及鼠标按钮的状态。这些功能已经能够免费使用,并且可以帮助我们实现交互功能。所以接下来我计划实现一些简单的用户界面功能,使得我们可以浏览和操作这些调试信息。

我们希望当鼠标悬停在任何条形图上时,调试显示能展示与之相关的信息

为了实现这个功能,最简单的实现方式就是通过鼠标悬停在某个条形图上,能够显示该条形图对应的函数名称。具体操作是,当鼠标悬停在某个条形图时,系统会打印出当前悬停的条形图对应的函数名称。这个功能是实现调试信息交互的第一步,能够让我们简单地查看某个函数的基本信息,作为后续更复杂交互的基础。

将游戏输入传递给调试系统,以便它能够访问鼠标位置

为了实现这个功能,首先需要将鼠标信息传递给调试系统,因为目前系统并没有直接的方式来传递这些信息。调试系统目前没有接收到游戏输入数据,而游戏输入数据在游戏更新和渲染过程中是可用的。我们需要做的就是将游戏输入直接传递到调试系统中,确保调试系统能够访问鼠标的位置信息。

在具体实现中,首先会通过修改主程序,将游戏输入传递给调试系统。在调试系统中,就可以直接读取鼠标的 x 和 y 坐标,从而获取鼠标的位置信息。这个过程相对简单,未来可能需要根据游戏输入缓冲区的处理进一步改进,但目前的实现应该足够用于调试目的。

检查鼠标位置是否落在给定的矩形内

现在的目标是根据鼠标的位置来判断它是否悬停在某个矩形区域内,并显示该区域的相关调试信息。每个矩形代表一个具体的调试区域,矩形坐标已经在渲染过程中确定。通过对比鼠标位置和矩形的位置,判断鼠标是否位于矩形内。这个操作非常简单,可以通过一个基本的比较来实现。

在实现过程中,首先会检查鼠标是否在某个矩形区域内。通过判断鼠标的 x 和 y 坐标是否落在矩形的范围内,若条件满足,就输出一行调试文本,显示该矩形对应的调试信息。这些信息包括了该区域的一些具体数据,例如周期计数、点击计数等。

为了从调试区域中提取这些信息,必须先确认如何获取每个区域对应的调试记录。在调试数据结构中,有存储调试记录的信息,包含了区域的基本信息及与该区域相关的事件。每个区域都有其对应的调试记录,记录了诸如文件名、行号等信息,正是这些数据将被输出以帮助调试。因此,重要的是确保能够正确地关联调试区域和相关的记录信息,方便后续的调试工作。

具体来说,可以通过在调试区域中查找关联的调试记录来获取相应的数据,这样就能够为每个区域显示详细的调试信息。

要显示的信息将来自于与debug_frame_region关联的debug_record

接下来,目标是将每个调试区域与其相应的调试记录关联起来,以便在鼠标悬停在某个区域时,能够获取到该区域的详细信息。具体来说,想要在每个调试区域中存储一个调试记录,通过这个记录可以访问该区域的相关信息。

在鼠标悬停时,可以通过该调试记录获取到该区域的块名、文件名和行号等信息。为了提供更有用的调试信息,可以将调试信息格式化为块名、文件名和行号等,这样开发者就可以直接看到这些信息,知道该区域的具体位置和它所对应的源代码。

此外,还需要获取与该区域相关的计时信息,特别是周期计数(cycle count)。虽然对于某些区域来说,点击计数等其他信息可能不那么重要,但周期计数对于分析性能非常关键。通过记录和显示周期计数,可以帮助分析特定区域的执行时间。

总的来说,目标是通过获取每个调试区域的相关信息(例如块名、文件名、行号和周期计数)来提升调试信息的可视化,使得开发者在查看调试信息时,能够更方便地定位问题并进行优化。

在debug_frame_region中添加一个调试记录和周期计数

接下来,需要对调试信息的存储结构进行升级,以便能够包含更多的信息,具体来说,就是需要添加调试记录和周期计数。

在每次记录调试帧和区域时,都要确保每个区域都包含这些新信息。对于周期计数,这个信息相对简单,因为它可以通过已知的事件开始和结束时间来计算得到,因此不需要太多复杂的处理。

同时,调试记录也需要被正确地关联到每个区域。调试记录的源信息(如文件、行号等)已经在系统中存在,因而可以直接提取并使用。这样每个区域就能存储周期计数和调试记录的详细信息。

一旦完成了这些改动,就能确保每个区域的调试信息包含完整的上下文,使得开发者可以更方便地查看和分析这些数据。

总的来说,整个过程是对现有存储结构的扩展,目的是为了提供更加详细和有用的调试信息,尤其是在鼠标悬停时能够获取到区域的完整信息。

构建一个矩形来测试鼠标指针是否在其中

为了优化矩形的处理和鼠标交互,首先回顾了已经存在的矩形功能。接着决定利用现有的矩形功能进行扩展,创建一个矩形对象,并通过给定的最小值和最大值来定义矩形的范围。这些值可以直接用于计算矩形的边界,进而在游戏或调试中应用。

具体来说,创建矩形时,主要关注了最小值和最大值之间的范围,尤其是矩形的宽度和起始点(x坐标)。矩形的定义考虑了如何传递矩形的最小值、最大值以及其他相关参数,确保矩形能够在后续的代码中正常使用。

此外,还提到了一些改进计划,比如使得矩形可以方便地传递给其他模块,进一步优化代码的可读性和可操作性。在这部分代码中,矩形不仅仅是一个简单的数据结构,还需要与其他组件(如鼠标输入)交互。因此,矩形的边界、位置以及其他相关信息会随着鼠标的移动而动态变化。

实现这一目标的方法是通过鼠标的坐标(鼠标位置)与矩形的位置进行比较。具体做法是,判断鼠标当前的位置是否位于矩形范围内,这样可以通过矩形的最小值和最大值来确认鼠标是否在矩形区域内。如果鼠标在矩形内,那么就可以通过调试信息输出相关数据,如矩形的属性、鼠标的位置等。

总结来说,目标是将矩形的定义与鼠标位置的交互结合,使得能够方便地通过鼠标事件来访问和操作矩形区域。这一过程涉及到对矩形位置、鼠标位置的实时判断,并且能够在调试过程中输出相应的数据。

实现一个接受矩形作为参数的PushRect版本

首先,讨论了如何在渲染过程中推送矩形,这次是使用与之前不同的方法。新的方法涉及传递一个带有Z坐标的矩形,这意味着矩形不仅包含常规的最小值和最大值,还增加了一个新的维度(Z坐标)。目标是使得矩形的推送方式变得更加灵活,能够处理更复杂的空间结构。

为了解决这个问题,提出了一种新的推送矩形的方法。首先创建一个新的矩形对象,并将其与Z坐标结合起来。这是通过对原始的矩形推送方式进行改进来实现的。新的方法允许矩形在渲染过程中根据需要进行更精确的定位,尤其是在三维空间中。

接下来,考虑到优化的问题,决定使用现有的工具来简化实现。例如,调用"get center"方法来获取矩形的中心位置,确保矩形的中心点和Z坐标都能正确地在渲染中体现。矩形的维度(宽度和高度)也通过已有的结构来获取,并将其作为渲染参数传递。最后,将颜色信息直接传递给渲染函数,确保矩形的视觉效果与期望一致。

总结来说,这段工作主要集中在通过增加Z坐标来改进矩形的渲染方式,并使用现有的工具和方法来简化这一过程。最终的目标是确保矩形在渲染时能够正确地显示,且具备更多的灵活性和扩展性。

测试。运行正常,但悬停效果还没有工作

现在的任务是确保鼠标悬停在矩形上时,能够正确地显示出相应的信息。虽然已经成功实现了绘制矩形的功能,但鼠标悬停的效果还未实现。当鼠标移动时,当前并没有看到任何反馈,这意味着还需要进一步的调整。

首先,需要解决为什么当前鼠标悬停没有效果的问题。这是因为在现有的代码中,鼠标悬停的处理逻辑尚未完全实现,因此无法正确捕捉鼠标在矩形区域内的状态。为了让鼠标悬停功能生效,需要继续完善代码。

下一步的工作将是完成鼠标悬停的处理,确保当鼠标经过矩形时,能够正确响应并显示相应的调试信息。虽然已经完成了矩形的绘制,但还需要做更多的工作来确保鼠标悬停能够触发正确的视觉反馈。

鼠标位置是相对于窗口的坐标系,而不是我们的渲染空间

目前面临的主要问题是,鼠标坐标(mouse x, mouse y)和渲染空间的坐标并不一致。鼠标坐标是由操作系统(如Windows)提供的,而渲染系统使用的是不同的坐标空间。具体来说,操作系统的坐标系统与渲染系统使用的正交投影坐标系并不匹配。

在调试过程中,当前的渲染使用了正交投影,将渲染空间的坐标范围设置为从负宽度的一半到正宽度的一半、从负高度的一半到正高度的一半,而这些坐标与Windows提供的鼠标坐标系不一致。因此,鼠标坐标需要进行转换才能正确地映射到渲染坐标空间中。

解决方案是先在当前系统中直接实现这一转换功能,使得鼠标坐标可以与渲染空间的坐标对接。之后,再根据需求考虑是否将这个坐标转换的责任推给平台层。这样做的好处是,无论不同平台如何处理鼠标坐标,平台层都可以统一将其转换为渲染系统需要的坐标格式,保证跨平台的一致性。

将鼠标坐标转换为游戏空间坐标

我们需要做的事情是,首先需要理解Windows中鼠标坐标的范围通常是从0到窗口的宽度。因此,鼠标的X坐标是从0到窗口的宽度,而渲染系统的坐标系可能与此不同。为了将Windows的鼠标坐标映射到渲染坐标系,我们需要做一些转换操作。具体来说,我们要做的是:将鼠标X坐标减去窗口宽度的一半,这样就能将鼠标坐标从Windows的坐标系转换到渲染坐标系中。

目前,我们还没有直接获取窗口宽度的方式,因此需要在合适的地方存储窗口的宽度信息。为了更好地组织代码,也有必要将一些全局变量移出当前的结构,减少对全局状态的依赖。

此外,对于高度的转换也需要进行类似的处理。在Windows中,鼠标的Y坐标是从顶部开始计数的,而渲染系统中Y坐标是从底部开始计数的。因此,Y坐标需要做相反的转换,通常是将鼠标的Y坐标从半高度开始向下计算,随着鼠标位置的增加,Y坐标也增大。

这种坐标转换目前还不完全正确,但已经接近我们需要的效果。接下来,需要进一步检查并调整这些转换,确保鼠标坐标能准确地映射到渲染系统的坐标系中。

现在悬停功能有效

现在,我们的鼠标悬停功能已经正常工作了。当鼠标悬停在任何一个区域时,能够看到相应的信息。至于为什么信息会出现在下方,我并不完全清楚,但这可能是因为输出的文本会在下一次刷新时显示出来。所以在调试过程中,信息似乎总是显示在下一个位置。

整体来说,悬停功能已经完成,可以正确地显示我们需要的调试信息,只是关于文本显示的位置仍然有一些不明确的地方。

改变调试文本在屏幕上的位置

现在,基本功能已经实现,能够通过鼠标悬停查看调试信息。信息的显示位置和内容已经符合预期。尽管如此,仍然存在一些小问题,特别是在显示调试数据时,比如调试协同条可能非常大,显示的开销也很高,这是需要进一步优化的部分。

此外,还需要做一些调整,尤其是在屏幕的高度计算上,目前的设置是从屏幕底部开始计算,这在某些情况下可能导致显示问题。虽然大致上功能已经实现,可以悬停查看每个区域的详细信息,但还需要进行一些修复和优化,才能确保一切正常工作。

基本来说,虽然当前已经能够看到所需的调试信息,并能够进行一些交互,仍然有细节上的问题需要解决,尤其是在处理调试信息的显示和位置方面。

我们的帧时间显示为0毫秒,因为我们是使用未关闭的帧信息来计算的

目前的问题是最后一帧的时间显示为0.00毫秒,这显得非常奇怪。经过排查,发现这是因为最后一帧还没有完成,所以它的时间被错误地计算为0。实际上,这一帧在调试过程中尚未结束,原因是调试代码协同执行时发生在帧标记完成之前,因此应排除该帧,不应将其计算在内。

为了解决这个问题,需要对帧的计数进行更谨慎的处理。具体来说,应该在确认帧已经完全完成后,才增加帧计数。也就是说,只有当帧真正结束时,才应递增帧数,未完成的帧不应该计入帧统计。

为此,在更新帧计数时,应该增加一个检查,只在帧完成后才递增计数。这样可以防止未完成的帧被误算为有效帧。

经过调整后,悬停功能开始正常工作,用户现在能够正确地查看到悬停的区域和相关的调试信息。这样一来,界面交互得到了更好的改善,功能运行也更加稳定。

我们不希望游戏层依赖于Windows的鼠标位置表示。应该由平台层将其转换为游戏的坐标系统

问题的核心是跨平台的鼠标坐标处理,特别是在不同平台上鼠标坐标的表示方式可能不同。例如,Windows系统的鼠标坐标是基于窗口的原点,而我们的渲染坐标系是以屏幕中心为原点的,因此,直接使用平台传递过来的鼠标坐标可能不适用。

为了避免各个平台层都模仿Windows的坐标处理方式,并且考虑到后续会将这些鼠标坐标转换到自定义的坐标系统中,最合理的做法是将坐标转换的任务交给平台层来完成。这样,平台层负责将鼠标坐标从其本地坐标系转换到我们的标准坐标系,避免了每个平台都去模拟其他平台的坐标处理方式。

因此,决定将这一转换的责任推到平台层中,这样在游戏逻辑层可以直接获取到转换后的鼠标坐标,而不需要在每个地方都进行转换。

具体来说,在游戏代码中,鼠标坐标(mouse xmouse y)应由平台层提供,并且平台层会在这里进行必要的坐标变换。为了避免数据类型的转换问题,平台层会确保传递过来的坐标为合适的格式(如整数而非浮点数)。

这种做法不仅使得代码结构更清晰,还减少了跨平台实现的复杂度,因为每个平台只需要处理它自己的坐标转换,而不需要模拟其他平台的坐标系。

在win32_game.cpp中转换鼠标位置

这个过程的核心是将鼠标坐标转换为游戏系统的坐标系。原始鼠标坐标通常是从窗口的左上角开始的,而游戏的坐标系统是基于屏幕中心的。因此,需要对鼠标坐标进行变换,以便它们能正确地映射到游戏的坐标系统中。

步骤如下:

  1. 获取全局缓冲区的宽度和高度 :通过访问全局的 back buffer(即渲染缓冲区),我们可以获取当前屏幕的宽度和高度。

  2. 坐标系统的转换

    • X坐标变换 :首先,我们需要将坐标系的原点设定在屏幕的中心。为了实现这一点,可以将屏幕宽度的一半(width / 2)从鼠标的X坐标中减去。这使得原本从左上角起始的坐标系统,现在从屏幕中心开始计算。

    • Y坐标变换:Y坐标的变换稍有不同,因为窗口坐标系通常是从上到下递增的,而我们的坐标系是从中间向上和向下扩展的。为了使得鼠标坐标和屏幕坐标一致,首先需要设置原点为屏幕的中心(负半屏高度)。然后,随着鼠标向下移动,Y坐标的数值应该减小。

  3. 坐标的应用:完成坐标变换后,将新的坐标应用到游戏渲染系统中,以确保鼠标在游戏中的位置正确显示。

最终,这样的处理方式可以确保鼠标的位置能与游戏的渲染坐标系相匹配,而不是直接使用操作系统提供的坐标,从而解决了跨平台坐标映射的问题。

(黑板) 如果我们希望后备缓存的最左列和最右列具有相同的绝对X坐标,则(0,0)坐标将位于像素边界上

这个问题的核心是坐标系统中的像素中心问题,尤其是当鼠标坐标映射到屏幕坐标时,如何处理像素对齐问题。

首先,要理解的是,坐标系统的中心与像素的精确位置关系。在游戏的坐标系统中,原点被设置在屏幕的中心,而操作系统中的坐标系统通常是以左上角为原点。这就导致了如何定义像素的中心,是否将坐标系统的原点放在像素的中心,或者像素的边缘上,成为了一个难题。

具体问题分析:

  1. 坐标系统的中心

    • 游戏的坐标系统将屏幕的中心视为 (0, 0),而操作系统的坐标系统是从左上角开始的,坐标值为正数的部分是向右和向下的。
    • 在一个1920x1080分辨率的屏幕上,中心应该位于 (960, 540) 这个像素位置。但问题在于,坐标系统是否应该把 (960, 540) 视为一个完整的像素中心,还是将它放在两个像素的边界之间。因为,如果屏幕分辨率是偶数,这个中间点其实是在第959.5像素和第960像素之间,这可能会导致一些不对齐的问题。
  2. 坐标系统对齐问题

    • 如果把 (0, 0) 放在屏幕的中心,那么它不完全位于某个像素的中心,而是两个像素之间。实际上,中心应该位于像素的边界线之间。这意味着当鼠标坐标的值是 0 时,实际对应的应该是屏幕的 -960 位置。类似地,鼠标的最大坐标 1920 应该对应的是屏幕的 960 位置。
    • 如果不进行正确的对齐,鼠标可能会被映射到错误的位置,尤其是当使用调试工具时,这个误差会变得明显。
  3. 是否需要额外的修正

    • 通过调试可以发现,如果坐标系统中的 (0, 0) 放置在精确的像素边界上,鼠标的映射将不会完全对齐到像素中心。一个可能的解决方法是,在坐标转换时进行额外的微调,比如将 -960960 位置微调,使其符合预期的像素边界。
    • 这会影响渲染效果,尤其是在进行高精度的图形渲染时,像素的对齐会直接影响到显示结果的精细度。
  4. 关于像素中心的讨论

    • 这个问题涉及到很多图形编程中的细节,特别是在像素对齐、坐标变换和渲染时的精度处理上。通常来说,图形程序员会对这些细节非常敏感,因为它们会直接影响到图形渲染的精度和质量。
    • 对于普通的调试工作,可能不需要过于严格的像素对齐,但如果要精确地控制渲染输出,尤其是在高分辨率显示器上,像素的准确对齐是非常重要的。
  5. 最终决策

    • 基于上述讨论,决定如何处理这个问题并没有一个简单的答案。可以选择将 0 放在两个像素之间,或者根据具体需求调整坐标的转换方法。理论上,为了保证精度,最好是让 0 处于像素的边界之间,但这也会带来不同的行为。
    • 这个问题通常会在开发过程中通过多次调试、测试和反复调整来找到最合适的解决方案。

总的来说,这个问题涉及到坐标系统的设计和鼠标坐标与屏幕坐标之间的转换,虽然这看似是一个小问题,但它却直接影响到调试和渲染的精确度。因此,需要深入思考并逐步调整,确保在开发过程中能够最大化地避免像素对齐不准确的问题。

修改字体的设置

暂停收集

目标是实现一种机制,可以在调试过程中停止或冻结当前的计算,而不再继续记录任何信息。为了做到这一点,可以通过条件判断来控制是否暂停或冻结调试过程。

具体步骤:

  1. 暂停功能的实现

    • 需要在调试状态下引入一个新的变量,标记是否处于暂停状态。例如,可以使用一个名为 paused 的布尔值来表示调试是否暂停。
    • 在代码中,添加条件语句来判断是否处于暂停状态。只有当 pausedfalse 时,才会继续执行计算或记录操作。
  2. 修改条件判断

    • 在调试代码的部分,可以像这样添加条件语句:

      cpp 复制代码
          // 执行正常的调试操作
      if (!DebugState->Paused) {
      }
    • 这样,只有在调试状态开启并且没有暂停的情况下,才会执行调试逻辑。如果暂停了,则不会执行任何操作。

  3. 实现暂停控制

    • 可以在某个事件(如鼠标点击)触发暂停。例如,当检测到某个鼠标按钮被按下时,可以改变 paused 的状态:

      cpp 复制代码
      if (Input->mouseButton) {
          paused = !paused; // 切换暂停状态
      }
    • 这样就可以通过鼠标的点击来控制调试过程的暂停与继续。

  4. 调试界面的变化

    • 需要在调试覆盖层(debug overlay)中显示当前的状态,比如显示 "Paused" 或者当前的调试信息。如果调试被暂停,可以在界面上显示暂停的标识,告诉用户当前的调试状态。
  5. 设计思考

    • 这种设计的关键在于灵活控制调试过程。通过引入 paused 状态,可以让调试过程在需要的时候停止,不再继续记录和显示信息。这种机制可以帮助开发人员在调试时更精确地控制和查看程序的状态,避免无效或不必要的计算。

总之,核心是通过引入一个 paused 标志,结合鼠标按钮的点击事件,控制是否继续调试过程。通过这种方式,能够有效地暂停和恢复调试,避免在不需要记录的情况下继续运行程序。

定义鼠标按钮的枚举类型

为了实现鼠标按钮控制调试暂停功能,计划在平台层(Platform Layer)中添加一个鼠标按钮枚举类型,并使用这些枚举来检测鼠标按钮的按下事件,进而切换暂停状态。

具体步骤:

  1. 创建鼠标按钮枚举

    • 在平台层中定义鼠标按钮枚举,用来表示不同的鼠标按钮。例如,定义 left, middle, right 三个按钮,便于后续引用和管理鼠标事件:

      cpp 复制代码
      enum platform_mouse_button {
          MOUSE_BUTTON_LEFT,
          MOUSE_BUTTON_MIDDLE,
          MOUSE_BUTTON_RIGHT
      };
    • 这样就有了一个标准化的方式来管理不同的鼠标按钮,避免硬编码和提高代码的可读性。

  2. 使用鼠标按钮枚举

    • 在平台层的相关代码中,使用这些枚举来检测鼠标按钮的状态。例如,检查是否按下了右键(MOUSE_BUTTON_RIGHT),如果按下了右键,就切换暂停状态:

      cpp 复制代码
       if (Input->MouseButtons[PlatformMouseButton_Right].EndedDown) {
             DebugState->Paused = !DebugState->Paused;
         }
    • 通过这种方式,可以实现鼠标右键控制暂停的功能。

  3. 检查鼠标按钮按下状态

    • 需要检查鼠标按钮是否按下的状态。虽然没有直接的 went_down 宏或函数,可以通过检查鼠标按钮的"是否按下"来控制暂停状态的切换。
    • 可能需要检查"过渡计数"(transition counts)来确认鼠标按钮的状态变化。虽然目前代码中似乎没有使用这部分功能,但可以在现有代码结构中增加类似的检查,确保按钮的按下事件被正确检测到。
  4. 调试暂停功能

    • 每当检测到鼠标右键按下时,切换 paused 状态。根据 paused 状态,控制程序是否继续记录调试信息或执行其他操作。
    • 例如,可以在调试状态下加一个检查:
  5. 清理和优化

    • 如果不需要"过渡计数"功能,也可以简单地删除相关代码,保持代码的简洁性。
    • 可以进一步确认是否需要更复杂的鼠标状态变化检测,例如长按、连续点击等,或者是否仅需单次点击事件触发切换。

总结:

通过在平台层定义鼠标按钮枚举,并使用这些枚举来检测鼠标按钮的按下事件,能够更清晰地管理和控制调试暂停的功能。此外,通过检查鼠标按钮的状态变化,控制是否执行调试逻辑,提供了灵活的暂停机制。

实现WasPressed功能,使用记录的HalfTransitionCount

为了实现更清晰的鼠标按钮按下检测和调试暂停控制,计划引入一种新的方法来判断按钮是否被按下,避免仅依赖于鼠标按钮的状态变化。这种方法需要借助"过渡计数"机制来精确控制按钮按下和释放的时间。

主要思路:

  1. 过渡计数(Transition Count)

    • 每个按钮的按下和释放事件都对应一个过渡状态,即按钮从"按下"到"释放"或从"释放"到"按下"的状态切换。
    • 如果按钮的"过渡计数"(transition count)大于0,说明按钮经历了至少一次从"按下"到"释放"或从"释放"到"按下"的状态变化。这样就可以知道按钮的状态发生了变化。
  2. 按钮按下的判断逻辑

    • 通过检查过渡计数,可以判断按钮是否按下。具体的判断方式如下:
      • 如果"过渡计数"大于1,说明按钮经历了多次按下和释放,按下事件肯定发生过。
      • 如果"过渡计数"等于1,并且按钮的状态是"按下"状态(ended down),说明按钮在当前这一轮按下了。
  3. 按下按钮时触发暂停

    • 如果按钮被按下(符合以上的条件),可以通过设置一个标志来暂停调试信息的记录。例如:

      cpp 复制代码
      if (half_transition_count > 1 || (half_transition_count == 1 && ended_down)) {
          paused = true;  // 按钮被按下,暂停调试
      }
    • 这样可以通过检测按钮的按下状态,控制调试是否暂停。

  4. 代码结构

    • 可以将这种按下判断封装成一个函数,使得判断和处理逻辑更加清晰:

      cpp 复制代码
      bool was_pressed(int button) {
          if (button_half_transition_count[button] > 1) {
              return true;  // 按钮肯定被按下
          }
          if (button_half_transition_count[button] == 1 && button_state[button] == BUTTON_STATE_DOWN) {
              return true;  // 按钮在当前周期按下
          }
          return false;  // 按钮没有被按下
      }
  5. 暂停调试的触发

    • 在主循环中,每次检查按钮是否按下,并在按下时暂停调试:

      cpp 复制代码
      if (WasPressed(Input->MouseButtons[PlatformMouseButton_Right])) {
          paused = !paused;  // 切换暂停状态
      }
  6. 提高精度和灵活性

    • 使用这种方法可以精确控制什么时候按钮被按下,同时避免了仅依赖鼠标按钮的状态的简单判断。通过对过渡计数的判断,可以确保每次按下和释放都被准确地检测到。

总结:

通过引入过渡计数和"按钮按下"判断的逻辑,可以更精确地控制鼠标按钮的按下事件,从而在调试过程中实现更加稳定和灵活的暂停功能。这种方法不仅能够判断按钮是否按下,还能够应对多次按下和释放的情况,确保程序在调试时能够可靠地暂停和恢复。

测试。没有效果

在调试过程中,遇到了关于按钮按下状态检测的逻辑问题。主要是通过"半过渡计数"(half transition count)来判断按钮是否按下。判断的条件是:

  1. 半过渡计数大于1:如果半过渡计数大于1,说明按钮经历了至少一次按下和释放的切换,因此可以确定按钮按下过。
  2. 半过渡计数等于1且按钮结束状态为按下:如果半过渡计数等于1,并且按钮状态是"按下"(ended down),也说明按钮在当前周期按下了。

在写这段逻辑时,出现了一个错误。代码中预期"半过渡计数"大于1时按钮被按下,但实际上似乎并没有正确识别这个条件,导致返回的结果不符合预期。通过调试,发现可能是状态没有被正确清除或更新,导致结果不对。

最后,问题得到了确认,正确的判断方式应该是根据按钮状态的变化来确认是否按下。而这种按下判断的核心在于"半过渡计数"是否为1,并且按钮状态是否是"按下"。

我们没有清除鼠标状态!

在调试过程中,发现了一个平台层的 bug,问题出在鼠标按钮状态的清除上。具体来说,鼠标按钮状态的值并没有被正确清除。通过检查代码,发现鼠标按钮状态只在某个地方被引用了一次,但之后再也没有被清除或更新。这意味着鼠标按钮的状态不会在每次新的输入周期中重新计算,导致状态错误。

问题的根本在于,代码并没有正确管理鼠标按钮的状态,导致状态信息可能会在不需要的情况下残留,进而影响后续的逻辑判断。这种处理方式不符合好的软件设计原则,因为状态应该在每次输入周期开始时被清理或者更新,否则会导致错误的行为。

因此,这被认为是一个软件设计中的重大问题,需要修复,避免状态信息不正确地延续到后续的逻辑中。这被归为"坏软件"或不符合最佳实践的代码。

在每一帧开始时清除half-transition计数

在调试过程中,发现了一个问题,涉及到半过渡计数器(half transition count)和状态更新的问题。问题出现在每一帧开始时没有清除半过渡计数,因此导致了状态没有正确重置。这会导致按钮触发不准确,可能会出现双重触发的现象。

解决方法是,在每一帧开始时,应该将所有按钮的半过渡计数重置为零。这是为了确保每一帧的按钮状态都是从零开始,避免上一个帧的状态干扰到当前帧。

此外,代码中还发现了一个问题,就是按钮状态的更新方式不正确。在更新按钮状态时,需要将当前帧的状态复制到上一帧的状态,以便正确计算状态变化。由于没有执行这一步,导致了状态的变化没有被正确记录,从而出现了错误的行为。

总的来说,这段代码需要重新组织和修复,确保每一帧的按钮状态是从零开始的,并且在更新时能正确地保存上一个状态。这些问题如果不修复,会导致系统的行为不稳定,影响调试和输入响应的准确性。

看看我们能否写出一些不完全垃圾的东西β

在解决当前的鼠标按钮状态管理问题时,尝试了改进代码的方式。首先,设定了一个鼠标按钮的索引,并尝试从旧的状态中复制这些信息,确保按钮状态的传递是连续的。

接下来,在处理按钮过渡状态时,清除了半过渡计数器,使得每一帧开始时按钮的状态能够正确初始化。通过设置适当的条件来判断按钮是否被按下,并在按下时正确地更新状态。最后,代码使用了简单的索引和标识符来确保按键状态能够被清晰地跟踪。

尽管这个方案有了一些进展,但还远未达到理想的效果。整体代码还有不少可以改进的地方,甚至仍然可以称之为"垃圾代码",但相比之前,它至少做了一些基本的修复,提升了稳定性。

测试。有效

代码现在已经有了明显的进步,解决了暂停和调试输入的问题,并且实现了鼠标悬停时的反馈功能。虽然仍然有一些可以进一步改进的地方,比如增加调试按钮的大小,使得更容易定位和点击,但整体上已经在正确的轨道上。

接下来,应该实现一种方法,允许点击和检查这些调试输入,这应该是一个相对简单的任务。同时,还需要清理一些输出的代码,使得整体代码更加整洁。整个项目目前进展顺利,接下来的工作也有了明确的方向,感觉一切都在朝着正确的方向发展。

相关推荐
枫景Maple4 分钟前
简单了解一下Unity的MaterialPropertyBlock
unity·游戏引擎
-代号95273 小时前
【JavaScript】十二、定时器
开发语言·javascript·ecmascript
nuc-1273 小时前
sqli-labs学习记录8
数据库·学习·sqli-labs
士别三日&&当刮目相看4 小时前
JAVA学习*简单的代理模式
java·学习·代理模式
灵感__idea4 小时前
JavaScript高级程序设计(第5版):扎实的基本功是唯一捷径
前端·javascript·程序员
摇滚侠4 小时前
Vue3 其它API toRow和markRow
前端·javascript
難釋懷4 小时前
JavaScript基础-history 对象
开发语言·前端·javascript
拉不动的猪4 小时前
刷刷题47(react常规面试题2)
前端·javascript·面试
今夜有雨.4 小时前
HTTP---基础知识
服务器·网络·后端·网络协议·学习·tcp/ip·http