敌人子弹瞄准 C64 上的玩家

Enemy bullets targeting player on a C64

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

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

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

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

请回答,我有千千万万这样的疑问,但回答这个问题也许我就能找到剩下的答案! :-)

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

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

假设您使用的是 160x200,那么我想您需要在进入之前放弃一些精度。

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

所以,天真地,像这样:

xPosYPos:

    ; assuming ([=10=]) has the positive x difference
    ; and () has the positive y difference

    lda [=10=]
    ora 

shiftLoop:
    asl [=10=]
    asl 
    asl a
    bpl shiftLoop

    ; load A with table index
    lda #[=10=]
    rol [=10=]
    rol a
    rol [=10=]
    rol a
    rol 
    rol a
    rol 
    rol a

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

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

    lda [=11=]
    ora 

    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 字节的查找 table 来查找基于 x|y 的例程地址(它总是最多 127,因为它们都是正数)并直接跳转到不计算位的移位。


物体位置和固定点入门:

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

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

这通常称为定点运算。与浮点数不同,整数中小数点所在的位置是固定的。在这里描述的方案中,它总是八位。

所以,例如添加仅包含字节数量的偏移量:

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/256ths。以亚像素精度移动那颗子弹的所有成本是每个向量额外的几个字节存储和额外的几个 ADC。

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

您也可以(滥用)使用 Bresenham 的画线算法来瞄准您的子弹,"line" 的起始坐标是敌人的坐标,结束坐标是您飞船的坐标。您无需在线条中添加像素,而只需在每次迭代的当前位置重新绘制项目符号。