reviewing “apron”概念以更新区域
我们正在进行模拟区域的扩展工作,目标是通过增加一个更大的区域来支持更丰富的互动,尤其是那些可能超出摄像机视野的内容。现有的模拟区域包括摄像机能看到的区域和其周围的环境区域,但为了保证更高效的游戏体验,我们希望能够模拟屏幕外的事件,例如玩家可能会听到或看到一些未出现在屏幕上的动作。
这个扩展区域的目的是确保在玩家不直接看到的情况下,依然能够处理周围环境中的动态事件,如炸弹的爆炸或墙壁的破裂。为了支持这些事件发生,即使它们不在屏幕上,我们还希望能够模拟这些区域中的物体与环境的碰撞。
为此,我们决定在现有模拟区域的基础上,向外扩展一定的范围,具体扩展的距离取决于每个实体的半径和速度。这样,所有可能与玩家发生碰撞的物体将被包括在模拟区域内,确保在发生碰撞时,游戏世界中的物体可以正确互动。
此外,考虑到实体的大小,我们需要确保不仅仅是实体的中心被考虑进来,实体本身的尺寸也会影响它是否被包括在内。如果实体的整体大小超出某个区域,它也应该被包含进去以避免遗漏。
虽然这种扩展增加了一些限制,例如无法将物体移动到模拟区域外部,但这个限制在当前情况下并不构成重大问题。我们还需要确保模拟区域的扩展能够正确处理每个实体的速度和大小,从而更精确地管理和模拟游戏世界中的互动。
最终目标是使得这些扩展区域能够在不引入额外性能问题的情况下支持更复杂的交互,同时在实现这些功能时避免过多的限制,以保持系统的灵活性和扩展性。
向 sim_entity 添加 Updatable 布尔值
我们讨论了关于实体标志的概念,其中实体标志用于储存一些特殊的状态,例如在非空间的碰撞检测中使用。这些标志基本上表示实体是否在同一区域内。实际上,标志的存储并不是持久化的,而仅限于当前区域内有效。这种设计类似于存储索引,但它只在模拟区域内起作用。
我们也考虑了是否应该在实体上标记一些特殊状态,例如“敌人”标记,这可以帮助我们在游戏中识别敌对实体。通过这种方式,可以确保每个实体的特殊状态可以被正确追踪,并在区域内进行相应的处理。
同时,讨论了更新表和存储结构的优化,提到了一种可能的做法,即根据区域分离存储实体类型。这意味着不同类型的实体会根据它们所在的区域进行组织,并通过这种方法更高效地处理实体的更新和状态。
总之,当前的设计目标是使实体标志更加简洁高效,并且确保它们能够在模拟区域内正确管理和更新。
在 AddEntity 中设置 Updatable 布尔值
首先,需要对实体的更新进行标记。当实体进入更新时,需要给其添加一个更新标记。接下来,检查实体是否位于指定的矩形区域内,如果是,就允许它被更新。这些区域会有一个“更新范围”,实体如果位于该范围内,就会被标记为可更新。实体的更新依赖于它是否位于该区域内,否则就不会触发更新。
当实体进入活动集合时,需要进行存储索引的设置。这意味着在设置存储索引时,需要检查实体是否需要更新,并且是否符合更新的条件。如果实体在更新范围内,它就会被允许更新。如果没有位于更新范围内的实体,则不会被更新。
有时候,可能需要更新那些没有明确位置的实体,像合成实体或特殊的实体。这些实体可以被存放在一个池子中,以便快速设置和管理。
最后,虽然不确定是否需要在更新过程中进行一些额外的检查,但是考虑到某些实体可能没有明确的位置,标记它们为可用仍然是有意义的。这使得未来能够快速设置和管理这些实体。
在模拟更新中检查 Updatable 布尔值
在进行模拟步骤时,我们需要检查实体是否应该更新。如果实体不在更新区域内,它将不会被更新。我们会根据实体是否可获取来判断它是否可以被更新。如果实体可以获取,我们将允许它继续更新,并对其进行处理;否则,它将被跳过,不做任何更新或渲染。
当前的处理逻辑是,如果实体处于更新区域之外,它将被跳过,不会参与任何处理或渲染。这是为了避免不必要的计算和渲染,提高效率。我们关注的是如何通过确保实体只在适当的区域进行更新来优化模拟过程。
总体来说,更新的判断依赖于区域的位置和实体的状态,只有当实体位于正确的区域内时,才会继续更新和渲染。
为 sim_region 设置不同的边界(UpdatableBounds 和 Bounds)
我们现在需要计算区域的大小。我们已经知道可用区域的大小,但要扩展其他区域的边界。更新区域已经在使用中,我们要做的是将其扩大一点。这意味着我们需要增加一些额外的尺寸,通常会是一个跟新安全边界,这个值现在是1米,尽管未来可能会有所不同。
为了实现这一点,我们需要将矩形的边界进行扩展,添加跟新边界。扩展的方式是将跟新安全边界加到矩形的每一边。我们会使用当前的矩形边界,并增加额外的尺寸来形成新的边界。
在这个过程中,我们会计算半径和速度,从而确定更新区域的大小。这样我们就能确保在扩展区域时,实体能够安全更新。
我们还可以通过简单的数学操作来扩展矩形。假设我们有两个矩形,它们的尺寸可以通过将宽度和高度相加来得到。扩展操作就是将原始矩形的半径加到每一边,形成一个更大的矩形。
为了实现这一点,我们将添加一个新的矩形调用,这个调用会自动计算新的矩形边界,考虑到增加的半径和跟新安全边界。
我们不再关心原始矩形的中心,而是直接计算新的最小角和最大角,确保新的矩形大小足够扩展更新区域。在最终的矩形中,原始矩形的最小角将减去跟新安全边界,而最大角将加上跟新安全边界,从而形成一个新的、更大的矩形。
这个扩展过程目前还没有很好的方法来进行测试,但这就是我们现在所需的步骤,接下来我们将继续实施这一逻辑。
剑还有效吗? - no
我们需要解决的最后一件事是弄清楚如何处理一些事情,例如“剑”的问题。我们需要决定的是,一旦我们知道了,是否应该让这些物品变得可用,或者它们是否会自动处理这个问题。我们也想确认是否将其移动到适当的区域或文件中。
接下来,如果我们继续进行英雄的更新,并处理空间的相关内容,我们应该将其移动到空间集合中,这样下次它就会被拉入模拟区域并更新。这似乎是应该发生的,但需要确认到底发生了什么。
此外,当前还没有完全确定是否需要将这些内容放入更新步骤中,因为某些物品显然并不需要更新,或者它们不应该被更新。
错误 - 从引用加载实体时位置设置不正确
在处理实体的位置时,我们意识到可能从未正确设置位置,尤其是在加载实体引用时。由于加载参考内容,我们并没有自动设置这些实体的有效位置。通过进一步分析,我们发现这实际上是一个 bug,之前我们并未注意到它,虽然问题一直存在。
我们决定在加载实体引用时,确保设置其位置。这样,即使实体是通过引用加载的,我们也能确保它们具有有效的位置。通过这样做,我们可以确保这些实体被正确定位,并且能够在模拟区域中正确更新。
接下来,我们将继续按这个方法进行操作,确保在加载引用时给实体分配空间,并更新它们的状态。这将确保我们处理所有低密度实体并将其纳入空间集合中,从而在模拟过程中获得正确的更新。
虽然现在有些额外的调用是必要的,但我们认为这是确保实体在游戏状态中正确流动的关键。通过这种方式,我们不仅能确认实体位置的正确性,还能确保它们在需要时被正确处理。
总体来说,我们对当前的进展感到满意,认为一切已经朝着正确的方向发展,尽管这过程中遇到了一些挑战。接下来,我们可能需要回头看看最初促使这些调整的原因,并进一步改进相关机制。
修复 Familiar 的更新
我们目前正在处理的任务包括一些清理工作,比如移植现有的功能并确保一切正常运作。接下来,我们会查看那些怪物的生命值等相关功能,特别是解决区域问题之后。现在是时候整理一下代码,查看是否需要修复或更新一些问题,确保一切都如预期工作。
在这一过程中,我们发现有些熟悉的功能没有按预期正常工作。特别是某个实体没有按照要求正确跟随玩家,虽然之前一切看似正常。这个问题需要进一步调查,找出原因。
我们还检查了更新过程中调用的代码,发现有一些操作没有达到预期效果,可能是因为我们没有正确地处理所有的实体。这个问题可能是由于一个简单的错误,导致部分功能没有被充分测试或实现。
目前,所有的问题都已经明确,并且我们正在着手解决。
移除剑的非空间标志检查
当前讨论的主要内容是关于碰撞检测,特别是剑的碰撞检测。最初,存在一个非空间的标志用于检查某些条件,但在当前的实现中,似乎不再需要这个标志。因为系统已经调整为仅当物体位于更新区域内时,才会调用更新函数,这样就不再需要对非空间的标志进行额外的检查。
通过这种方式,剑如果不在更新区域内,就不会被调用,这使得不再需要维护原本存在的检查标志。这种简化不仅减少了不必要的操作,也使得代码变得更加精简和高效。随着这一变化的发生,原本复杂的逻辑变得不再重要,因为相关的概念已经被移除。
进一步的讨论涉及到如何进一步简化代码和流程,考虑到这些变化的效果是否有助于进一步的优化。最终,尽管有些意外发生,但这种变化似乎带来了正面的效果,尽管它是一个意外的发现,仍然可以接受并继续推进。
如何更新 MoveEntity 以实现更复杂的碰撞效果?
当前讨论的主要内容是如何处理剑的移动和碰撞检测。首先,当剑移动时,系统会调用移动实体函数来处理物体的运动。接着,讨论了如何利用碰撞检测来执行特定操作,比如记录被撞击的对象。考虑到游戏中的不同需求,碰撞响应需要进行更细致的拆分,以便应对不同的情况。
具体来说,碰撞响应应当能够区分两种情况:一种是物体与障碍物(例如墙壁)碰撞时停止移动,另一种是物体穿透障碍物(例如地板)并且继续移动。在后者的情况下,可能希望角色继续移动,但需要对这种行为进行特别处理。为了实现这一点,碰撞检测和响应机制需要被拆分成多个部分,分别处理不同类型的碰撞和不同的反应。
讨论中提到,剑与怪物碰撞时可能不会停止,而是穿透怪物并造成伤害,这需要特别的碰撞处理方式,例如穿刺伤害。因此,需要对碰撞检测进行更多控制,使得能够根据不同情况灵活调整碰撞反应。
在实现这一过程中,考虑到复杂性,决定将碰撞反应的处理分为多个层级,允许更高层的代码来决定如何具体响应这些碰撞。当前并不打算一次性实现所有的处理逻辑,而是会逐步讨论和实现相关功能。
迭代运动的回顾
在当前讨论中,讲述了碰撞检测和处理的一个迭代系统。假设场景中有两堵墙和一个玩家,玩家试图沿着墙壁移动。首先,当玩家与第一堵墙碰撞时,系统会停止玩家的移动。但为了让玩家沿着墙壁继续前进,系统会计算出玩家可以沿墙走多远。
接下来,可能会遇到第二堵墙,在这种情况下,系统需要再进行一次碰撞检测,来确定玩家与第二堵墙的碰撞点。这意味着在一次移动调用中,实际上进行了两次碰撞迭代:第一次处理与第一堵墙的碰撞,第二次处理与第二堵墙的碰撞。
这种迭代方式确保了玩家可以在碰撞时继续沿墙壁滑动,而不会穿越墙壁。
如何在迭代运动中进行碰撞响应?
在当前的讨论中,重点是关于实体碰撞后的响应。当一个实体(例如玩家)与另一个敌人发生碰撞时,系统可能需要对碰撞做出反应。此时,可能希望根据不同情况执行特定操作。
为了实现这一点,当前的任务是设置一个调度机制,在碰撞检测的迭代过程中处理这些响应。这个调度需要在迭代的过程中触发,从而确保每个碰撞后都能及时进行适当的处理。
讨论处理碰撞的回调
当前讨论的主题是回调函数(callback)的使用及其问题。回调通常用于在迭代过程中处理某些任务,例如碰撞处理。在回调机制中,系统会传递一个函数,这个函数在特定条件下被调用,以完成需要的操作。然而,回调机制虽然有用,但也带来了一些复杂性和耦合问题。
回调会将逻辑“打包”到另一个地方,使得代码的流动变得不那么直观。特别是在处理多个迭代时,回调可能会导致程序的控制流不够清晰,且很难直接共享代码中的迭代行为。每当回调引入时,通常会使得控制流变得不如预期,可能导致程序的维护和调试变得更加困难。
而如果可以直接在同一段代码中编写迭代逻辑,就可以避免这种复杂性,使得代码更加清晰、干净和优化,所有的操作都在一个地方完成。
回调的替代方案 #1 - 如何分解 MoveEntity
回调函数(callback)机制在迭代过程中会带来一些复杂性,尤其是在处理诸如碰撞检测等任务时。通常,回调会将逻辑“打包”到另一个地方,这会使得代码的执行流变得不太直观。特别是在多次迭代的情况下,回调可能会导致控制流变得模糊,难以理解和调试,且不易直接共享代码中的迭代行为。
为了避免这种复杂性,推荐直接在代码中编写迭代逻辑,而不是使用回调。这种方法的好处是可以减少不必要的耦合,简化控制流,代码结构也会更加清晰。可以将迭代逻辑分为初始化和步进两个部分,初始化部分负责设定结构和变量,而步进部分则负责进行迭代操作。
通过将迭代逻辑分开,可以提供更多的灵活性,使得代码更易于维护和理解。这样做的另一大优点是,不需要处理回调函数中复杂的传递机制,而可以在外部以最简单的方式进行操作。
在这种设计下,迭代过程可以更加清晰,每次调用时只需要返回命中的实体,调用次数没有限制。完成所有操作后,可以直接结束迭代,并进行后续处理,保持代码的简洁和直观。这种方式相比于回调机制,能显著提高代码的清晰度和可维护性。
回调的替代方案 #2 - 设置加速度并延迟调用 MoveEntity
另一种方法是将所有实体的移动集中处理,而不是使用回调机制。如果实体的移动总是在一个中心化的地方处理,控制就可以更直接地进行。在这种方式下,更新调用时,无法直接移动实体,也不能调用“移动实体”的函数。相反,系统允许设置加速度,一旦设置好,加速度就会自动驱动实体的移动,而无需再通过回调来触发。
这种方法避免了回调带来的复杂性,因为它不依赖于外部传递逻辑,而是通过集中化的更新机制来处理所有移动。这意味着,实体的碰撞和其他操作都会按照相同的逻辑处理,避免了在回调中可能出现的不一致性。
该方式有一个优势,即它为未来的扩展提供了更大的灵活性。比如,如果需要同时解决多个实体的碰撞问题,或者处理多个实体同时移动的情形,这种集中式处理方式会更加方便。通过这种方式,实体的移动和加速度设置都被集成在一个简单的系统中,避免了在外部直接操作的复杂性。
总的来说,这种方法提供了一种更加统一和简洁的处理方式,避免了回调所带来的不必要的复杂性,并且在未来的扩展中可以更加容易地进行调整和优化。如果此方法证明不可行,可以进一步调整和改进。
实现替代方案 #2
现在,我们决定当进行实体更新时,先设置加速度,而不是直接调用实体的移动函数。加速度一旦设置,实体的移动会自动发生,而不需要在外部触发调用。这种方法使得实体的移动逻辑集中管理,从而简化了系统的结构。
我们还考虑了如何处理这些更新调用。通过将所有的更新代码集中在一个文件中,使用一组案例语句来管理不同的实体更新操作,避免了过度分离函数带来的复杂性。更新逻辑不再通过多个函数调用来进行,而是通过一个集中式的过程来处理。
通过这种方式,所有实体的移动和更新逻辑都被简化为设置加速度和更新状态,避免了每次都需要检查和调用不同函数的麻烦。这种集中式的处理方式使得代码更加整洁,也为将来的扩展和优化提供了更大的灵活性。
在实现过程中,部分代码被移除,简化了操作,例如直接设置“移动规范”(move spec)和“国内生产总值”(GDP),避免了不必要的中间步骤。通过这种方法,实体的更新变得更加直接和高效。
最终,目标是通过这种结构,确保所有更新操作都能集中管理,并且便于未来扩展和优化。
错误修复 - 不应为非移动或非空间实体调用 MoveEntity
在更新实体位置的逻辑中,我们需要确保只处理那些真正需要移动的实体。判断一个实体是否应该移动,主要依据其速度或加速度是否存在。如果速度或加速度为零,那么实体就不需要进行移动。这是一个基本的假设,用于简化更新流程。
此外,还需要进一步检查实体是否标记为“非空间的”(non-spatial)。如果一个实体被标记为非空间的,那么它的移动逻辑将被跳过。这种标记可以有效减少不必要的计算,提高性能。
在处理过程中,我们注意到一个潜在问题:一旦实体被标记为非空间的,是否有可能在某些情况下被错误地重新标记为空间的?为了解决这个问题,我们需要对实体的标记状态进行额外的验证,确保逻辑的一致性。也就是说,需要明确标记某些实体为仅限空间的(spatial-only),以避免无意中修改标记状态。
具体来说,我们将逻辑分为以下几个步骤:
-
检查实体是否需要移动
首先,根据实体的速度或加速度判断其是否需要移动。如果两者均为零,则跳过更新。 -
验证实体的标记状态
如果实体被标记为非空间的,则直接跳过移动逻辑,避免进一步的处理。 -
执行移动逻辑
对于需要移动且标记为空间的实体,执行实际的移动操作。 -
确保标记状态的稳定性
确保非空间的实体不会被误标记为空间的,从而保持标记状态的一致性。
通过以上优化步骤,可以减少不必要的计算,同时确保逻辑的正确性。这种方法不仅提高了性能,还使代码更具可维护性和扩展性。
剑不应该永远移动…
在实现实体移动逻辑的过程中,发现了一些问题与潜在优化点。具体可以总结为以下几个方面:
-
移动距离的约束
移动逻辑中缺乏对运动距离的限制机制,可能导致实体在一次移动中超出预期范围。这需要通过在碰撞例程中引入运动距离的限制来解决。具体而言,应该确保每次移动时,不超过定义的最大允许范围。 -
现有问题分析
之前曾出现过一个类似的错误,即在处理移动逻辑时,未能充分考虑到距离限制的作用。这导致了实体在某些情况下可以移动得过远,而不受控制。 -
解决方案设计
计划对碰撞例程进行改进,使其能够理解并应用运动极限的概念。在每次移动时,检测是否超过设定的运动极限,如果超出,则立即停止移动。这将使系统更加稳健,并避免类似错误的再次发生。 -
改进计划
- 碰撞逻辑增强
更新碰撞检测逻辑,使其能够识别并处理运动极限的情况。 - 代码组织优化
将相关逻辑模块化,使特定的例程集中在一个易于发现和理解的地方,方便后续维护。 - 问题排查优先级
确保上述改动成为下一步开发的重点,首先解决运动限制问题,然后继续完善碰撞检测功能。
- 碰撞逻辑增强
如何处理移动背景的碰撞?例如迷宫和移动的瓷砖?或者这不会出现在这款游戏中?
-
当前已支持背景移动的碰撞检测,比如动态背景物体的碰撞(如屋顶瓦片等),但问题在于未对这些碰撞做出响应。例如,当背景物体碰撞到玩家时,碰撞仅停止,但并未将玩家推开,而实际上应该有推动效果。
-
浮点精度问题可能导致实体被卡在其他物体中。例如,当发生碰撞时,没有确保实体被正确地放置在碰撞之外,因此可能会出现卡顿或不自然的碰撞行为。
-
为了解决上述问题,需要修改碰撞处理例程,使其能够处理运动中的背景物体。同时,需要为碰撞建立优先级规则,当两个物体发生碰撞时,指定其中一个具有优先权。例如,当动态背景物体碰撞玩家时,背景物体应优先推动玩家。
-
处理这些问题的过程虽然需要一定的工作量,但不算复杂。一旦建立了优先级和适当的碰撞响应规则,支持动态背景碰撞会变得相对容易。
-
在实现过程中,需要考虑更多基于游戏玩法的设计问题。例如,当推力物体将玩家推到另一个物体上时,应该决定玩家是否会被卡住,还是可以从某个角度移动出去。这些细节需要根据具体的游戏需求进行调整。
-
总体来说,大多数游戏在处理这些问题时效果并不理想,因此,只要制定合理的规则和处理机制,就可以显著提升游戏中的碰撞表现。
为什么不使用 .c 而是 .cpp?
-
当前的代码使用了C++而不是纯C,但尽量避免使用过多的C++特性。这种选择主要基于对语言特性的取舍,以及避免依赖过多复杂特性带来的问题。
-
对于C++中的某些功能,如随机数生成等,并不特别喜欢或常用。这种特性在设计上可能不符合当前的偏好或需求。
-
尽管如此,项目中仍然存在部分C++代码。例如,有些功能或实现方式需要使用C++,这些代码在C语言中是无法直接编译或实现的。
-
整体来看,当前代码基于C++开发,但使用的C++特性相对较少,仅在必要时采用。这种方式在兼顾功能需求的同时,也保持了代码的简洁性和可维护性。
当你开始使用枚举时,为什么从 (1 << 1) 而不是 (1 << 0) 开始?
-
没有任何特殊的理由,实际上可以完全从位移0开始,这与当前的实现并没有本质区别。
-
这种选择可能是因为当时没有专注于这一部分,导致在细节上没有注意到。简单来说,这是一个无关紧要的操作习惯问题。
-
这种情况可以归结为在开发过程中可能有一些无意的选择,并不代表有特定的逻辑依据或目的。
源文件的大小有多大?你感觉文件的大小让你感到不堪重负了吗?
-
关于源文件的大小,当前的代码体量仍然非常小,完全没有被其尺寸压垮的感觉。
-
对于源代码的行数统计,目前并未直接使用统计工具。简单估算了一下,发现源文件中的代码行数仅有 117 行(或 128 行,具体可能取决于计算方式)。目前并未安装用于统计代码行数的工具,但未来可能会安装一个相关工具来获取更精确的数据。
-
通过观察代码的实际体积,仅从文件大小的角度来看,大约是 150KB 的代码量。相较于更复杂的项目,这显然是非常小的。
-
代码体积中的很大一部分实际上并不是逻辑代码,而是随机数字表和与多个平台兼容的支持代码。逻辑代码的部分显然更少。
-
总体来说,这个代码库目前规模很小,且逻辑上并不复杂,并没有因为代码体量而感到负担。相较于其他更大的项目,这可以被描述为“微小的代码库”。
如果你不小心穿墙了会发生什么?游戏会崩溃吗?
-
当角色因某些问题穿过墙壁时的结果:当前情况下,游戏不会因此崩溃,而是角色会被卡在墙壁内部。
-
未来版本的处理方式:在未来的版本中,将采取措施防止角色穿过墙壁的情况发生。这是游戏设计中的一个重要改进目标。
-
现阶段的应对方法:目前如果角色被卡在墙中,可以尝试通过进一步操作从墙中“脱出”,但没有特别明确的处理机制。
-
关于管理问题的讨论:在另一部分讨论中,提到是否需要更多的管理者来协助,确保环境更有序。如果确实需要,可以提出具体的建议,包括补充更多的管理者。
到目前为止你写了多少行代码?
-
代码行数统计的问题:当前还没有明确统计代码总行数的程序。尝试寻找适合的工具,但目前的设备上可能没有这样的统计程序,因此暂时无法获取准确的行数数据。
-
对代码规模的看法:当前的代码量并不大,相对于复杂的项目而言,这些代码在规模上属于非常小的范围。
-
进一步说明:虽然没有具体的统计工具,但整体代码的复杂性和行数相对较低,显然在管理和处理上负担较小。
总结来看,虽然暂时缺少代码行数统计工具,但可以确定的是,目前的代码量较少,规模小,便于维护和扩展。
在什么情况下你会更倾向于使用回调而不是一个巨大的 switch-case 语句?
-
switch语句与回调函数的比较:switch语句通常比回调函数更优越。在几乎所有的情况下,switch语句在代码质量、灵活性、可读性、易用性和压缩性等方面都表现得更好。回调函数相对较少使用,且switch语句在大多数情况中更为适用。
-
回调函数的应用场景:尽管switch语句通常更好,但回调函数在某些特定的场景下仍有其必要性。例如,当需要隔离不同平台的代码时,回调函数可能更合适。此时需要保持平台特定代码的隔离性,而回调函数可以帮助解耦不同平台的代码。
-
switch语句的优势:switch语句在理解和使用上更加直观,且容易进行优化和持久化处理。它比虚拟函数和回调函数更容易管理,且能有效避免虚拟函数表的复杂性和函数指针的冗余。
-
总结:回调函数和虚拟函数虽然在特定情况下有其用途,但在大多数情况下,使用switch语句能带来更简洁、易于维护且更高效的代码结构。
我们是手动加载和绘制所有内容到 DIB 区域,然后将最终图像进行 blit 吗?
我们处理图形绘制的方法是尽量减少不必要的操作。基本上,我们使用的是位缓冲区,而不是通过传统的图像处理方法来绘制。在这一过程中,我们没有使用类似div
部分的结构,而是直接操作位缓冲区,将缓冲区的位数据放到窗口上,从而显示最终的图像。这种方法的目的是为了减少中间的处理步骤,提高效率。
在你提到“一次性做所有碰撞”后,似乎不仅更容易实现,而且也更符合现实世界的情况,比如将所有力相加以得到净方向。为什么还会有人想要为每个对象编写更新函数?
对于是否为每个对象设置一个更新函数的问题,有人认为虽然这种做法易于实现,并且在某些情况下与现实世界的匹配度更高(例如,所有的力量最终得到净方向),但它可能引入一些问题。主要问题是,物体的自定义代码无法控制更新的时机,也无法处理前后状态的比较,从而使得更新变得更加复杂。尽管如此,允许对象控制更新时机能够带来更大的灵活性,在理想情况下,如果能够同时支持这两种方法,将能够更好地管理对象的状态。
这种方法在实际开发中是常见的,并非什么革命性的想法。对于很多引擎的实现来说,这是一个常见且有效的做法。虽然它有可能是正确的选择,但在具体项目中,还需要根据实际需求来决定是否采用这种方法。
除了显然附加上的部分,你会认为 Windows GUI 是一个好的 API 吗?
提到程序设计时,关于Windows API的讨论指出,尽管一些部分看起来直观和干净,实际上很多更新和改进反而带来了问题。Windows API,特别是其复杂的设计和历史积累,已经经历了数十年的开发,并由成百上千的人组成的团队设计。这个庞大的系统难以评判其优劣,许多改进被认为是灾难性的,尤其是如果按今天的方式编程。
讨论中提到了一些API的部分,虽然它们并不完美,但也不至于糟糕。相比之下,现代的更新和改进往往更加混乱。因此,评估API的好坏需要具体分析其各个部分,而不仅仅是依赖于整体框架。
你是如何决定以这种顺序构建引擎的?是直觉还是经验?
讨论中提到的编程方法强调了一种逐步推进、从简单到复杂的方式来构建引擎架构。这种方法的核心思想是通过不断的小步骤来解决问题,而不是一开始就设计复杂的系统。通过从简单的平铺地图开始,逐步解决性能和结构上的问题,最终形成一个可行的系统,而不是尝试一次性解决所有问题。
在这一过程中,首先设定目标并编写最基本的代码,观察哪些部分有效,哪些部分无效,然后通过不断调整和扩展,逐渐完善系统。这样的方法可以避免设计过程中的过度猜测和复杂的规划,而是让架构自然地随着编程和实验的推进而显现出来。这种方式强调了适应变化和灵活性,避免了将系统各个部分孤立开发并强行拼接在一起的风险。
此外,还强调了程序设计中的经验积累,尽管没有长期的游戏编程经验,但通过不断地实践和解决新问题,能够找到更好的解决方案。这种方法也体现了通过实际编程和探索来解决问题的重要性,而不是依赖预设的假设或过早的设计决策。
说到 UML 和图表,你会使用类图进行代码规划吗?
在讨论中提到,图表或UML图形对于代码规划的帮助有限,因为它们很难完整地呈现代码的复杂性。尽管图表可能提供某些直观的概念,但它们往往无法反映代码中的重要细节。因此,建议从编写代码开始,逐渐从中抽象出更高层次的设计,而不是一开始就依赖UML。这种方法能够更好地捕捉到代码的实际复杂性和运行时的行为。
难道你不能在使用 switch 语句时列举出所有可能的情况吗?如果你想要构建一个可以扩展的系统呢?
在讨论使用 switch
语句时,提到如果系统需要扩展(例如动态添加新功能),简单地通过添加更多的 case
并不难。然而,当谈到更复杂的扩展需求时,依赖 switch
语句就变得局限。为了使系统可扩展,尤其是当代码需要在不直接修改的情况下被动态加载时,通常需要脚本语言或类似机制来支持这种灵活性。使用脚本语言可以让系统支持快速的修改,避免直接修改代码本身。对于游戏等需要玩家修改内容的应用,使用 switch
语句可能不够灵活,这时脚本语言提供了更好的解决方案。
如果不依赖于修改代码本身,而是让用户或开发者通过脚本来扩展功能,那么虽然这种方式失去了一些直接性(如 switch
提供的访问方式),但仍能保证系统的扩展性和灵活性。总之,如果系统需要快速修改并易于扩展,采用脚本语言是一种有效的解决方法,而不仅仅依赖 switch
语句来实现所有的扩展。
为什么使用 switch 语句而不是简单的大型 if-else 语句?
在讨论使用 switch
语句与 if-else
语句时,提到如果需要更多的条件判断,if-else
语句也可以很好地使用。然而,选择使用 switch
语句的原因是它打字量更少,能够让代码更加简洁。这是因为 switch
可以集中处理多个条件,而 if-else
语句则可能需要更多的编写代码,尤其是在条件较多时。通过使用 switch
语句,代码更具可读性和维护性。
碰撞的处理方式是否是顺序无关的?
关于碰撞的处理顺序是否独立的问题,暂时没有明确的答案。在目前的游戏设计中,碰撞的顺序可能不是独立的。通常情况下,碰撞处理的顺序对于游戏的行为影响较大,因此不太可能在没有充分理由的情况下引入这种复杂性。除非在游戏开发过程中发现有理由需要确保碰撞的顺序独立,否则不会考虑这一复杂性。
是在编程周期的过程中调试更好,还是在最后调试更好?
在编程过程中,最好是遇到错误时立即进行调试,而不是等到编程周期结束。遇到错误时及时修复可以避免隐藏问题,确保代码在每个阶段都是稳定的。通过这种方式,可以减少其他潜在的错误对当前代码的影响,因为如果错误没有被及时修复,可能会影响后续的代码开发。
此外,及时修复错误还能提高编写代码的效率,因为不必担心已有的错误会在后续开发中产生干扰。修复bug后,代码的其他部分也能更顺利地工作,从而减少在最终阶段出现问题的机会。
总的来说,发现bug时就解决它,这样可以确保代码在任何时刻都处于健康状态,避免积累更多的难以发现的问题。
仓库: https://gitee.com/mrxiao_com/2d_game