0
\$\begingroup\$

I would like to achieve a smooth movement of a game object up and down. The way I have always seen this done is via a sine wave, and adding the value of y for a specified X to the game objects value of Y.

This method seemed slightly slow so I had the idea of using two parabolas, one of which is negative such as the following two: sample and then one would only use the values above or below zero depending on the parabola. However even this seems like an obtuse and slow method so I was wondering if there was a better way?

\$\endgroup\$
3
  • 2
    \$\begingroup\$ How many objects do you have? I have trouble believing that using a sine wave is “slightly slow”. \$\endgroup\$ Commented Feb 5, 2014 at 7:57
  • \$\begingroup\$ On screen, at most around fifty, it's not a massive performace issue, but I'm finishing up a project and going through everything that seems like it could be rewritten. This was one of those things. \$\endgroup\$ Commented Feb 5, 2014 at 14:35
  • \$\begingroup\$ Well I think your time (and, indirectly, ours) would be best used learning profiling tools and techniques, so that you can pinpoint the parts that are actually slow. \$\endgroup\$ Commented Feb 5, 2014 at 17:24

2 Answers 2

1
\$\begingroup\$

Simple harmonic motion is still easy to achieve with a sine wave and sin is a pretty fast function. However, there are some optimizations you can make since you'll be using it over and over. Since this movement code does not require much accuracy from sin, you can limit the input to sin and store the results. Using something like a hash table or in this example, an array, you can do the following:

float[] sinValues = new float[361];

public void Initialize() {
   for(int i = 0; i <=360; i++) {
       //store the values of sin from 0 to 360
       sinValues[i] = Math.sin(i * (Math.PI / 180f));
   }
}

public float FastSin(float value) {
    //convert the value to value within 360 degrees
    int inputAngle = (int)((value % (2*Math.PI)) * (180/Math.PI));
    return sinValues[inputAngle];
}

Now you can use FastSin to simply retrieve the stored value of sin.


Included below is my misinterpretation of your original question.

If you want to to be faster, increase the frequency. If you want it to move more, increase the amplitude. What does that look like in code? Examples:

//Increase the frequency (faster up and down)
float factor = 3;
Math.sin(deltaTime*factor);

//Decrease the frequency (slower up and down)
float factor = .3f;
Math.sin(deltaTime*factor);

//Increase the amplitude (more distance up and down)
float factor = 3;
Math.sin(deltaTime)*factor;

//Decrease the amplitude (less distance up and down)
float factor = .3f;
Math.sin(deltaTime)*factor;


//All together now, faster up down over a smaller distance
float ampFactor = .4f;
float freqFactor = 4f;
Math.sin(deltaTime*freqFactor)*ampFactor;

Finally, you can make the whole wave above zero by adding one:

(Math.sin(deltaTime*freqFactor) + 1f)*ampFactor; //now go from 0 to 2
((Math.sin(deltaTime*freqFactor) + 1f)/2f)*ampFactor; //now we go from 0 to 1
\$\endgroup\$
3
  • \$\begingroup\$ Oh I just realized you may mean "slow" as in performance. If that's the case, I wouldn't worry too much about that. It's far more likely your performance issues are somewhere other than a call to sin every update. \$\endgroup\$
    – House
    Commented Feb 4, 2014 at 23:42
  • \$\begingroup\$ Yes I am aware as to how to do it with sine waves, and yes it was performance that I was concerned about. Thank you for your help! \$\endgroup\$ Commented Feb 4, 2014 at 23:55
  • \$\begingroup\$ Yep, if you're worried about performance you should profile the code before you do anything else. Sine functions are pretty fast and unlikely to be the source of any performance issues. What made you think sin was slow? \$\endgroup\$
    – House
    Commented Feb 4, 2014 at 23:57
1
\$\begingroup\$

I think the sin function is still slow. You can approximate it with a function like

y = 1 - (x - 1) ^ 2

The code looks like this:

/**
 * @src_x       source x coordination
 * @dst_x       destination x coordination
 * @time_len    length of time
 * @time_cur    current time (from 0 to time_len)
 * @final_x     output result of x coordination
 *
 * math function: y = 1 - (x - 1) ^ 2 { x >= 0 & x <= 1 }
 * (you can use another function like: y = 1 - (x - 1) ^ 3 { x >= 0 & x <= 1 })
 */
void MoveByTime(const float src_x, const float dst_x, const float time_len, const float time_cur, float* final_x)
{
    if (0 >= time_cur)
    {
        *final_x = src_x;
        return;
    }
    if (time_len <= time_cur)
    {
        *final_x = dst_x;
        return;
    }
    float t = time_cur / time_len;
    // math function: y = 1 - (x - 1) ^ 2
    t = 1.0f - (t - 1.0f) * (t - 1.0f);
    *final_x = src_x + (dst_x - src_x) * t;
}

Here's how Wolfram Alpha would plot it:

a plot of the function

The rest of the sine wave can be approximated just by repeating mirror images of that output.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .