Recriar física retro / NES com imprecisão intencional


16

Fundo:

Estou tendo um problema para corrigir a curva de salto de um projeto de remake de plataforma retro meu. O jogo original é para o NES, e a velocidade do jogador é armazenada em duas partes separadas: um byte para o número inteiro e outro para a parte fracionária.

A gravidade é adicionada à velocidade Y do jogador a uma taxa de 0,25 / quadro.

Quando o jogador pula, sua velocidade Y é ajustada para -4,64453125. O restante da curva de salto é deixado para a gravidade.

À medida que o jogador sobe, sua velocidade vertical converge para 0 a uma taxa de 0,25 / quadro. Quando a velocidade do jogador atinge um valor menor que zero, no entanto, a velocidade muda seguindo um padrão diferente. Em vez de diminuir constantemente em 0,25 a cada quadro, segue este padrão:

[1.75, -0.25, -0.25, -0.25, 1.75, -0.25, -0.25, -0.25, 1.75, ...]

Parece ter algo a ver com excesso de número inteiro.

Dados:

Aqui está um despejo dos dados do original. É uma tabela da velocidade.

Jump Curve

Y-Hi Y-Lo    Decimal        Change/Frame
4    165     4.64453125     ?
4    101     4.39453125     -0.25
4    37      4.14453125     -0.25
3    229     3.89453125     -0.25
3    165     3.64453125     -0.25
3    101     3.39453125     -0.25
3    37      3.14453125     -0.25
2    229     2.89453125     -0.25
2    165     2.64453125     -0.25
2    101     2.39453125     -0.25
2    37      2.14453125     -0.25
1    229     1.89453125     -0.25
1    165     1.64453125     -0.25
1    101     1.39453125     -0.25
1    37      1.14453125     -0.25
0    229     0.89453125     -0.25
0    165     0.64453125     -0.25
0    101     0.39453125     -0.25
0    37      0.14453125     -0.25
-1   229     -1.89453125    1.75
-1   165     -1.64453125    -0.25
-1   101     -1.39453125    -0.25
-1   37      -1.14453125    -0.25
-2   229     -2.89453125    1.75
-2   165     -2.64453125    -0.25
-2   101     -2.39453125    -0.25
-2   37      -2.14453125    -0.25
-3   229     -3.89453125    1.75
-3   165     -3.64453125    -0.25
-3   101     -3.39453125    -0.25
-3   37      -3.14453125    -0.25
-4   229     -4.89453125    1.75
-4   165     -4.64453125    -0.25
-4   101     -4.39453125    -0.25
-4   37      -4.14453125    -0.25
-5   229     -5.89453125    1.75
-5   165     -5.64453125    -0.25
-5   101     -5.39453125    -0.25
-5   37      -5.14453125    -0.25
-6   229     -6.89453125    1.75

Problema:

No meu jogo, não consegui alcançar esse efeito. Quando a velocidade é menor que zero, ela continua a diminuir regularmente em 0,25, em vez do padrão descrito acima. Em vez de armazenar as partes inteiras e fracionárias separadamente, estou armazenando-as juntas em uma única bóia.

Como esse efeito pode ser alcançado?


1
Para ser sincero, basta tirar capturas de tela para determinar a altura / comprimento máximos do pulo em pixels e ajustar a função atual para parecer o mais parecida possível. Você diz que a imprecisão é intencional, então isso não deve causar problemas?
Jonathan Connell

Eu acho que você precisa postar a parte que está alterando a velocidade e descrever exatamente o problema e sua necessidade no código.
Ali1S232

2
@Gajet what? Ele descreveu o problema exatamente.
Maik Semder

@maikSemder: Estou curioso para saber como ele implementou o mecanismo de física para fornecer uma solução com base em seu código.
Ali1S232

Deixe-me saber se você precisar de mais detalhes, eu não queria escrever um post gigantesco por medo de receber respostas tl; dr.
Zack The Human

Respostas:


16
one byte for the whole number and another for the fractional part

Basicamente, você só precisa subtrair 64 de low para subtrair 0,25, porque um valor de 8 bits pode ter 256 valores, então 256 * 0,25 = 64 Quando houver um subfluxo, lowtambém subtraia 1 de high.

Aviso Legal: Este código está intencionalmente errado quando se trata de números negativos, e deve modelar as anomalias numéricas descritas na pergunta. Por razões de comparação, a implementação de números negativos adequados que manipulam a classe de ponto fixo pode ser encontrada na parte inferior desta resposta.

struct velocity
{
    char high;
    unsigned char low;

    // fall -0.25
    void fall()
    {
        if(low < 64) --high;
        low -= 64;;
    }

    // convert to a float
    float toFloat() const
    {
        float ret = high;
        float frac = (float)low / 256.0f;
        if(high >= 0) ret += frac;
        else ret -= frac;
        return ret;
    }

    // convert from float
    void fromFloat(float f)
    {
        high = (char)f;
        float frac = f - high;
        low = (unsigned char)(frac * 256.0f);
    }
};

velocity v;
v.high = 4;
v.low = 165;    
for(int i = 0; i < 30; ++i)
{
    printf("%2d     %3d   %f\n", v.high, v.low, v.toFloat());
    v.fall();
}

EDITAR : Eu também adicionei a conversão para flutuar e de flutuar e a saída

A saída gerada é a mesma da sua tabela:

 4     165   4.644531
 4     101   4.394531
 4      37   4.144531
 3     229   3.894531
 3     165   3.644531
 3     101   3.394531
 3      37   3.144531
 2     229   2.894531
 2     165   2.644531
 2     101   2.394531
 2      37   2.144531
 1     229   1.894531
 1     165   1.644531
 1     101   1.394531
 1      37   1.144531
 0     229   0.894531
 0     165   0.644531
 0     101   0.394531
 0      37   0.144531
-1     229   -1.894531
-1     165   -1.644531
-1     101   -1.394531
-1      37   -1.144531
-2     229   -2.894531
-2     165   -2.644531
-2     101   -2.394531
-2      37   -2.144531
-3     229   -3.894531
-3     165   -3.644531
-3     101   -3.394531
-3      37   -3.144531
-4     229   -4.894531
-4     165   -4.644531
-4     101   -4.394531
-4      37   -4.144531
-5     229   -5.894531
-5     165   -5.644531
-5     101   -5.394531
-5      37   -5.144531
-6     229   -6.894531

Por outro lado, essa classe de ponto fixo lida com os números negativos corretamente:

#include <iomanip>
#include <iostream>

struct fixed_point
{
    union
    {
        struct
        {
            unsigned char low;
            signed char high;
        };
        short s;
    };

    float toFloat() const
    {
        fixed_point tmp;
        if(high < 0) tmp.s = ~s;
        else tmp.s = s;

        float ret = tmp.high;
        float frac = (float)tmp.low / 256.0f;
        ret += frac;
        if(high < 0) ret = 0 - ret;
        return ret;
    }

    void fromFloat(float f)
    {
        float tmp;
        if(f < 0.0f) tmp = -f;
        else tmp = f;

        high = (char)tmp;
        float frac = tmp - high;
        low = (unsigned char)(frac * 256.0f);

        if(f < 0.0f) s = ~s;
    }

    fixed_point operator+(const fixed_point &fp) const
    {
        fixed_point ret;
        ret.s = s + fp.s;
        return ret;
    }

    fixed_point operator-(const fixed_point &fp) const
    {
        fixed_point ret;
        ret.s = s - fp.s;
        return ret;
    }

    void print(const char *msg) const
    {
        std::cout << msg << ":" << std::endl;
        std::cout << std::hex << std::uppercase;
        // cout'ing the hex value for a char is kind of a pain ..
        unsigned int _high = 0;
        memcpy(&_high, &high, 1);
        std::cout << "  high : 0x" << std::setfill('0') << std::setw(2) << _high << std::endl;
        unsigned int _low = 0;
        memcpy(&_low, &low, 1);
        std::cout << "  low  : 0x" << std::setfill('0') << std::setw(2) << _low << std::endl;
        std::cout << "  all  : 0x" << std::setfill('0') << std::setw(4) << s << std::endl;
        std::cout << "  float: " << toFloat() << std::endl;
        std::cout << std::endl;
    }
};

1
@ Zack sim, claro, veja a minha estrutura de posição, adicionei uma conversão à função float que faz exatamente isso.
Maik Semder

1
@Zack também acrescentou uma conversão fromFloat
Maik Semder

1
@ Maik Você senhor, é um cavalheiro. Obrigado pela ajuda. Isso vai me colocar de volta aos trilhos.
Zack The Human

1
@Zack você está muito bem-vindo, feliz por ajuda, especialmente para tal pergunta nice :)
Maik Semder

1
@Zack no caso de você estiver interessado, eu adicionei uma classe ponto fixo que lida com os números negativos adequadamente para comparação
Maik Semder
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.