如何在基于字符的图形系统上保留适当的背景?
How do I retain proper background on a character-based graphics system?
我感觉很复古,因此决定在我的第一台计算机 (Commodore PET 4032) 上编写我最喜欢的 8 位计算机游戏 (Williams' Defender)。所有代码都是用 6502 汇编语言完成的。对于那些不熟悉 PET 的人来说,所有图形都是基于角色的,要构建游戏,您可以在 40 列 x 25 行的屏幕上移动不同的角色。这是非常古老的技术 - 没有精灵,没有图形层,没有我们今天习惯的屏幕级别的 AND 功能等。
我希望游戏同时发射多个 "laser beams",并且这些激光束在穿过屏幕时可能会叠加在一起。现在,当光束沿着屏幕移动时,它们会在内存中存储它们下方的内容,然后在它们移动时替换它们下方的内容以将背景恢复到其原始状态。当第二个激光到达第一个顶部时问题就来了..第一个移动并替换原始背景而不是将第二个激光留在顶部,然后第二个激光移动并留下第一个激光的伪影。
是否有经典的"light"算法或规则集允许多个对象相互移动,从而保留下面的原始正确内容?我尝试了不同的方法(随着事物的移动交换背景等),但似乎没有任何方法能给我想要的正确结果。
让每个 sprite 保留一份它覆盖的任何内容的副本,并让它们按照与您绘制它们的顺序相反的顺序自行擦除是肯定的选择。这不会失败,但它假设您有时间绘制完整的精灵并擦除每一帧。
您还可以使用 'is background' 和 'is sprite' 标志的屏幕大小缓冲区。每次绘制精灵时,将其角色位置标记为 'is sprite'。要擦除所有精灵,请遍历屏幕大小的缓冲区,重新绘制未标记 'is background' 的任何地方的背景。如果迭代整个 2000 个潜在槽的成本太大,您可以保留更新位置的上限和下限。
如果您只有一个视频缓冲区,您还可以比较两个此类缓冲区之间的差异以显着减少闪烁:首先绘制新精灵,无论它们应该去哪里,并在新缓冲区中注意它们。绘制完所有精灵后,在新缓冲区未标记 'is sprite' 但旧缓冲区标记为
的任何地方填充背景。
我建议:
- 维护一个游戏状态模型,让您可以随时重绘整个屏幕。这将包括所有可移动元素的位置和其他状态
- 当您在帧之间更新游戏状态时,累积所有需要重绘的单元格的掩码,因为它们中的某些内容已更改或移动。
- 从上到下按深度顺序遍历游戏元素,重绘每个元素在已更改单元格掩码中的部分
- 从更改的单元格掩码中删除您绘制的任何单元格,这样它就不会被更深的元素重写。
- 背景将放在最后,并将重绘所有剩余的单元格,为您留下一个空蒙版,为下一帧做好准备。
此过程可避免因取消在单帧中绘制的任何内容而导致的任何闪烁。
可以将各种索引结构添加到更改后的单元格掩码中,以避免不必要的绘制工作。什么样的优化在这里是合适的取决于你的游戏。例如,如果背景大部分是静态的,那么在更新期间将每个更改的单元格的坐标添加到列表中,然后在背景重绘期间仅检查这些单元格会很有用。或者您可以根据所有可移动元素的先前位置来执行此操作...向上 2 你。
如果大部分场景在每一帧都发生变化,那么你可以跳过遮罩累积,直接从全屏遮罩开始......虽然我认为 PET 对于此类游戏来说可能不够快。
我从未为 Pet 编程,因此无法就您可以尝试的内容提供任何具体建议,但我可以建议在大约 1k 的 RAM 中保留当前屏幕背景的副本。这样,您可以在删除写入该图块的最后 "sprite" 时使用该数据恢复背景。不幸的是,这还要求您将代码和对象数据的总和保持在 31k 以下,除非您将其编程为盒式磁带。只是一些想法,因为它们是值得的。
我感觉很复古,因此决定在我的第一台计算机 (Commodore PET 4032) 上编写我最喜欢的 8 位计算机游戏 (Williams' Defender)。所有代码都是用 6502 汇编语言完成的。对于那些不熟悉 PET 的人来说,所有图形都是基于角色的,要构建游戏,您可以在 40 列 x 25 行的屏幕上移动不同的角色。这是非常古老的技术 - 没有精灵,没有图形层,没有我们今天习惯的屏幕级别的 AND 功能等。
我希望游戏同时发射多个 "laser beams",并且这些激光束在穿过屏幕时可能会叠加在一起。现在,当光束沿着屏幕移动时,它们会在内存中存储它们下方的内容,然后在它们移动时替换它们下方的内容以将背景恢复到其原始状态。当第二个激光到达第一个顶部时问题就来了..第一个移动并替换原始背景而不是将第二个激光留在顶部,然后第二个激光移动并留下第一个激光的伪影。
是否有经典的"light"算法或规则集允许多个对象相互移动,从而保留下面的原始正确内容?我尝试了不同的方法(随着事物的移动交换背景等),但似乎没有任何方法能给我想要的正确结果。
让每个 sprite 保留一份它覆盖的任何内容的副本,并让它们按照与您绘制它们的顺序相反的顺序自行擦除是肯定的选择。这不会失败,但它假设您有时间绘制完整的精灵并擦除每一帧。
您还可以使用 'is background' 和 'is sprite' 标志的屏幕大小缓冲区。每次绘制精灵时,将其角色位置标记为 'is sprite'。要擦除所有精灵,请遍历屏幕大小的缓冲区,重新绘制未标记 'is background' 的任何地方的背景。如果迭代整个 2000 个潜在槽的成本太大,您可以保留更新位置的上限和下限。
如果您只有一个视频缓冲区,您还可以比较两个此类缓冲区之间的差异以显着减少闪烁:首先绘制新精灵,无论它们应该去哪里,并在新缓冲区中注意它们。绘制完所有精灵后,在新缓冲区未标记 'is sprite' 但旧缓冲区标记为
的任何地方填充背景。我建议:
- 维护一个游戏状态模型,让您可以随时重绘整个屏幕。这将包括所有可移动元素的位置和其他状态
- 当您在帧之间更新游戏状态时,累积所有需要重绘的单元格的掩码,因为它们中的某些内容已更改或移动。
- 从上到下按深度顺序遍历游戏元素,重绘每个元素在已更改单元格掩码中的部分
- 从更改的单元格掩码中删除您绘制的任何单元格,这样它就不会被更深的元素重写。
- 背景将放在最后,并将重绘所有剩余的单元格,为您留下一个空蒙版,为下一帧做好准备。
此过程可避免因取消在单帧中绘制的任何内容而导致的任何闪烁。
可以将各种索引结构添加到更改后的单元格掩码中,以避免不必要的绘制工作。什么样的优化在这里是合适的取决于你的游戏。例如,如果背景大部分是静态的,那么在更新期间将每个更改的单元格的坐标添加到列表中,然后在背景重绘期间仅检查这些单元格会很有用。或者您可以根据所有可移动元素的先前位置来执行此操作...向上 2 你。
如果大部分场景在每一帧都发生变化,那么你可以跳过遮罩累积,直接从全屏遮罩开始......虽然我认为 PET 对于此类游戏来说可能不够快。
我从未为 Pet 编程,因此无法就您可以尝试的内容提供任何具体建议,但我可以建议在大约 1k 的 RAM 中保留当前屏幕背景的副本。这样,您可以在删除写入该图块的最后 "sprite" 时使用该数据恢复背景。不幸的是,这还要求您将代码和对象数据的总和保持在 31k 以下,除非您将其编程为盒式磁带。只是一些想法,因为它们是值得的。