Retro / NES tarzı fiziği kasıtlı olarak kesin olmayan bir şekilde yeniden yaratmak


16

Arka fon:

Retro bir platformcu yeniden yapım projem için atlama eğrisini düzeltmekte sorun yaşıyorum. Orijinal oyun NES içindir ve oyuncunun hızı iki ayrı parçada saklanır: bir tam sayı için bir bayt ve bir de kesirli kısım için.

Yerçekimi, oyuncunun Y hızına 0.25 / kare hızında eklenir.

Oyuncu zıpladığında, Y hızı -4.64453125 olarak ayarlanır. Atlama eğrisinin geri kalanı yer çekimine bırakılmıştır.

Oyuncu yükseldikçe dikey hızı 0,25 / kare hızında 0'a yaklaşır. Ancak oyuncunun hızı sıfırdan küçük bir değere ulaştığında, hız farklı bir paternin ardından değişir. Her kareyi sürekli olarak 0,25 oranında azaltmak yerine, bu kalıbı izler:

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

Tamsayı taşmasıyla bir ilgisi var gibi görünüyor.

Veri:

İşte orijinalden bir veri dökümü. Bu bir hız tablosu.

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

Sorun:

Oyunumda bu etkiyi başaramadım. Hız sıfırdan düşük olduğunda, yukarıda açıklanan model yerine düzenli olarak 0,25 azalmaya devam eder. Bütün ve kesirli parçaları ayrı ayrı saklamak yerine, onları tek bir şamandıra içinde saklıyorum.

Bu etki nasıl elde edilebilir?


1
Dürüst olmak gerekirse, maksimum atlama yüksekliğini / uzunluğunu piksel cinsinden hesaplamak için ekran görüntüleri alırdım ve mevcut işlevinizi olabildiğince görünmesi için ayarladım. Kesinliğin kasıtlı olduğunu söylüyorsunuz, bu bir soruna neden olmamalı mı?
Jonathan Connell

Hızı değiştirdiğiniz kısmı yayınlamanız ve kodu ve ihtiyacınızı tam olarak açıklamanız gerektiğini düşünüyorum.
Ali1S232

2
@Gajet ne? Sorunu tam olarak tarif etti.
Maik Semder

@maikSemder: Koduna göre çözüm vermek için fizik motorunu nasıl uyguladığını merak ediyorum.
Ali1S232

Daha fazla ayrıntıya ihtiyacınız varsa bana bildirin, korkacağım için devasa bir yazı yazmak istemedim, yanıtları alacağım.
Zack The Human

Yanıtlar:


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

Temel olarak low0.25'i çıkarmak için sadece 64'ü çıkarmanız gerekir , çünkü 8 bitlik bir değer 256 değere sahip olabilir, bu yüzden 256 * 0.25 = 64 low1'den çıkarmada bir alt akış olduğunda high.

Feragatname: Negatif sayılar söz konusu olduğunda bu kod kasıtlı olarak yanlıştır, soruda açıklanan sayısal anomalileri modellemesi gerekir. Karşılaştırma nedenlerinden ötürü, sabit nokta sınıfını işleyen uygun bir negatif sayının uygulanması bu cevabın alt kısmında bulunabilir.

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

EDIT : Ben de float ve float ve çıktı dönüşüm ekledi

Oluşturulan çıktı tablonuzla aynıdır:

 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

Bunun aksine, bu sabit nokta sınıfı negatif sayıları düzgün şekilde işler:

#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 evet emin, benim pozisyon yapısı bakın, ben tam olarak bunu float işlevine bir dönüşüm ekledi.
Maik Semder

1
@Zack ayrıca bir fromFloat dönüşümü ekledi
Maik Semder

1
@Maik Siz bayım, bir centilmensiniz. Yardım için teşekkürler. Bu beni tekrar yoluna sokacak.
Zack The Human

1
@Zack çok hoş geldiniz, özellikle böyle güzel bir soru için yardımcı olmaktan mutluluk duyuyorum :)
Maik Semder

1
@ İlgilendiğiniz takdirde, negatif sayıları karşılaştırma için düzgün bir şekilde işleyen bir sabit nokta sınıfı ekledim
Maik Semder
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.