의도적으로 부정확 한 레트로 / NES 스타일의 물리 재현


16

배경:

레트로 플랫 포머 리메이크 프로젝트에서 점프 곡선을 올바르게 얻는 데 문제가 있습니다. 원래 게임은 NES를위한 것이며, 플레이어의 속도는 정수의 바이트와 분수의 다른 두 부분으로 저장됩니다.

중력은 플레이어의 Y 속도에 0.25 / 프레임의 속도로 추가됩니다.

플레이어가 점프하면 Y 속도가 -4.64453125로 설정됩니다. 나머지 점프 커브는 중력에 맡겨져 있습니다.

플레이어가 상승함에 따라 그의 수직 속도는 0.25 / 프레임의 속도로 0으로 수렴합니다. 그러나 플레이어의 속도가 0보다 작은 값에 도달하면 속도는 다른 패턴에 따라 변경됩니다. 매 프레임마다 0.25 씩 꾸준히 감소하는 대신이 패턴을 따릅니다.

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

정수 오버플로와 관련이있는 것으로 보입니다.

데이터:

다음은 원본의 데이터 덤프입니다. 속도의 표입니다.

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

문제:

내 게임에서는이 효과를 얻을 수 없었습니다. 속도가 0보다 작 으면 위에서 설명한 패턴이 아닌 정기적으로 0.25 씩 계속 감소합니다. 전체 및 분수 부분을 별도로 저장하는 대신 단일 부동으로 함께 저장합니다.

이 효과를 어떻게 얻을 수 있습니까?


1
솔직히 말해서 스크린 샷을 찍어 최대 점프 높이 / 길이를 픽셀 단위로 해결하고 현재 기능을 가능한 한 조정하기 위해 조정했습니다. 당신은 부정확성이 의도적이라고 말하는데 이것이 문제를 일으키지 않아야합니까?
— Jonathan Connell 2016 년

속도를 변경하는 부분을 게시하고 문제와 요구 사항을 코드에 정확하게 설명해야한다고 생각합니다.
— Ali1S232 2016

2
@Gajet 무엇? 그는 문제를 정확하게 설명했다.
— Maik Semder

@maikSemder : 자신의 코드를 기반으로 솔루션을 제공하기 위해 물리 엔진을 어떻게 구현했는지 궁금합니다.
— Ali1S232

더 자세한 정보가 필요하면 알려주세요. 나는 tl; dr 응답을 얻을 수 있다는 두려움에 대해 거대한 게시물을 작성하고 싶지 않았습니다.
— Zack The Human

답변:


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

low8 비트 값은 256 값을 가질 수 있기 때문에 기본적으로 64에서 빼기 만하면 low됩니다 high.

면책 조항 : 이 코드는 음수에 관해서는 의도적으로 잘못되었습니다. 질문에 설명 된 수치 적 이상을 모델링해야합니다. 비교 이유로 고정 소수점 클래스를 처리하는 적절한 음수 구현은이 답변의 맨 아래에 있습니다.

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();
}

편집 : 또한 플로트 및 플로트 및 출력으로 변환을 추가했습니다.

생성 된 출력은 테이블과 동일합니다.

 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

반대로이 고정 소수점 클래스는 음수를 올바르게 처리합니다.

#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 예, 내 위치 구조를 보았습니다. 정확히 수행하는 부동 함수로 변환을 추가했습니다.
— Maik Semder

1
@Zack은 또한 fromFloat 변환을 추가했습니다
— Maik Semder

1
@Maik 선생님, 신사입니다. 도와 주셔서 감사합니다. 이것은 나를 다시 궤도에 올릴 것이다.
— Zack The Human

1
@Zack 당신은 매우 환영합니다, 특히 좋은 질문에 도움을 드리겠습니다 :)
— Maik Semder

1
@Zack 관심이 있으시다면, 비교를 위해 음수를 올바르게 처리하는 고정 소수점 클래스를 추가했습니다
— Maik Semder
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.