3

我正在扫描互联网和旧的 C64 书籍以寻找这个问题,但没有找到答案,所以最后我不得不把它贴在这里。我喜欢 C64 编码的美好时光,虽然我目前没有在这个平台上编写游戏,但我想知道当时是如何克服一些硬件限制的。

在所有现代游戏编程书籍和教程中,找到向玩家发射敌方子弹的正确方向的方法是使用带有浮点数的矢量数学,或多或少类似于以下伪代码:

bullet_velocity = (player.position - bullet.position).normalize();

现在,考虑到 C64 的限制,我在源代码中看到大量使用正弦表来提高速度,也许我分心了,但是在阅读旧的 C64 书籍或 C64 程序员评论的程序时,我从未见过有关向量数学的词,我想知道当时如何获得相同的目标。

请回答,我有上千个这样的疑问,但回答这个问题也许我可以找到自己的答案!:-)

编辑:请注意:子弹针对玩家的 C64 游戏示例是 Silkworm 和 Cyber​​noid。

4

2 回答 2

5

假设您对足够少的输出方向感到满意,那么通过查找表最容易做到这一点。例如,对于 64 个输出方向,抓取(x, y)从源到目标的向量,如果两者都是正数,则将两者都左移直到其中一个填充符号位,然后从每个的前两位形成一个四位表索引并查看输出向量。

假设您的分辨率为 160x200,那么我想您在进入之前需要丢掉一些精度。

适当地镜像以处理其他象限。假设对象位置的固定点为 8.8,子弹速度为 1,那么这是一个 32 字节的查找表。

所以,天真地,像:

xPosYPos:

    ; assuming ($00) has the positive x difference
    ; and ($01) has the positive y difference

    lda $00
    ora $01

shiftLoop:
    asl $00
    asl $01
    asl a
    bpl shiftLoop

    ; load A with table index
    lda #$00
    rol $00
    rol a
    rol $00
    rol a
    rol $01
    rol a
    rol $01
    rol a

    ; look up vector
    tax
    lda xVec, x
    ; ... put somewhere ...
    lda yVec, x
    ; ... put somewhere ...

...使用更智能的解决方案可能涉及更多类似的东西:

    lda $00
    ora $01

    asl a
    bmi shift1
    asl a
    bmi shift2
    ... etc ...

shift1:

... etc, but you can shift directly to form
the table index rather than going to all the work
of shifting the vector then piecing together from
the top bits ...

或者,您可以创建一个 256 字节的查找表来查找基于的例程地址x|y(由于它们都是正数,因此最多始终为 127)并直接跳转到移位而不计算位。


物体位置和固定点的入门:

假设您处于 160x200 模式,那么您可以将对象位置的每个组件存储为单个字节。所以 x 一个字节,y 一个字节。许多游戏所做的是将每个位置存储为两个字节。所以 x 和 y 总共有四个字节。

其中一个字节与单字节格式相同——它是整数位置。另一个是小数部分。因此,如果您有一个位置和一个速度(以及欧拉积分),那么您可以对位置进行 16 位速度加法。然后你只需使用最高字节作为位置。

这通常称为定点算术。与浮点不同,整数中小数点所在的位置是固定的。在此处描述的方案中,它始终是 8 位。

因此,例如添加仅字节数量的偏移量:

clc
lda xPosition
adc xVelocity
sta xPosition

sta SomeHardwareRegisterForSpritePosition

要使用定点方案添加偏移量:

clc

lda xFractionalPosition
adc xFractionalVelocity
sta xFractionalPosition

lda xPosition
adc xVelocity
sta xPosition

sta SomeHardwareRegisterForSpritePosition

优点是您的速度矢量现在可以在任何方向上小至像素的 1/256。因此,例如,您可以存储一个速度,表示您的子弹每一帧都会向左移动一个像素,向下移动 32/256 个像素。以亚像素精度移动子弹的所有成本是每个向量额外的几个字节存储空间和额外的几个 ADC。

使用上述建议,您可以通过从另一个字节中减去一个字节中的一个字节来获得从源到目标的向量。结果将是两个单字节,这两个字节都是输出的小数部分。因此,例如,您可能决定用 (87/256, 239/256) 的矢量(即 20 度角)发射子弹。

于 2015-10-28T01:56:22.847 回答
1

你也可以(ab)使用 Bresenham 的线条绘制算法来瞄准你的子弹,“线”的起始坐标是敌人的坐标,结束坐标是你的船的坐标。您只需在每次迭代的当前位置重新绘制项目符号,而不是向一条线添加像素。

于 2016-01-15T17:10:51.120 回答