Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

Background:

I'm having a problem getting the jump curve correct for a retro platformer remake project of mine. The original game is for the NES, and the player's velocity is stored in two separate parts: one byte for the whole number and another for the fractional part.

Gravity is added to the player's Y speed at a rate of 0.25/frame.

When the player jumps, his Y speed is set to -4.64453125. The rest of the jump curve is left to gravity.

As the player ascends his vertical velocity converges to 0 at a rate of 0.25/frame. When the player's velocity reaches a value less than zero, however, the velocity changes following a different pattern. Instead of decreasing steadily by 0.25 every frame, it follows this pattern:

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

It appears to have something to do with integer overflow.

Data:

Here is a dump of the data from the original. It's a table of the velocity.

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

Problem:

In my game I haven't been able to achieve this effect. When the velocity is less than zero it continues to decrease regularly by 0.25 rather than the pattern described above. Rather than storing the whole and fractional parts separately, I am storing them together in a single float.

How can this effect be achieved?

share|improve this question
1  
To be honest I'd just take screenshots to work out his max jump height / length in pixels and just tweak your current function to look as like it as possible. You say the imprecision is intentional, so this shouldn't cause a problem? –  Jonathan Connell Jun 11 '11 at 21:36
    
I think you need to post the part you are changing the velocity and exactly describe the problem and your need on the code. –  Ali.S Jun 11 '11 at 22:01
2  
@Gajet what? He did describe the problem exactly. –  Maik Semder Jun 11 '11 at 22:09
    
@maikSemder: i'm just curious about how he implemented physics engine to give solution based on his code. –  Ali.S Jun 11 '11 at 22:12
    
Let me know if you need more details, I didn't want to write a gigantic post for fear I'll get tl;dr responses. –  Zack The Human Jun 11 '11 at 22:14
show 4 more comments

1 Answer 1

up vote 16 down vote accepted
one byte for the whole number and another for the fractional part

Basically you just have to subtract 64 from low in order to subtract 0.25, because an 8 bit value can have 256 values, so 256 * 0.25 = 64 When there is an underflow in low also subtract 1 from high.

Disclaimer: This code is intentionally wrong when it comes to negative numbers, it is supposed to model the numerical anomalies described in the question. For comparison reasons the implementation of a proper negative numbers handling fixed point class can be found at the bottom of this answer.

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: I also added the conversion to float and from float and the output

The generated output is the same as in your table:

 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

In contrast this fixed point class handles the negative numbers properly:

#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;
    }
};
share|improve this answer
1  
@Zack yes sure, see my position structure, I added a conversion to float function which does exactly that. –  Maik Semder Jun 11 '11 at 22:35
1  
@Zack also added a fromFloat conversion –  Maik Semder Jun 11 '11 at 22:40
1  
@Maik You sir, are a gentleman. Thanks for the help. This will get me back on track. –  Zack The Human Jun 11 '11 at 23:38
1  
@Zack you're very welcome, glad to help, especially for such a nice question :) –  Maik Semder Jun 11 '11 at 23:40
1  
@Zack in case you are interested, I added a fixed point class that handles the negative numbers properly for comparison –  Maik Semder Jun 12 '11 at 8:49
show 3 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.