1

I asked a similar question a few hours ago, but I think there was too much information in that question so I deleted that one and made this one more relevant.

I'm trying to move an object with a decreasing acceleration in a specified time but the acceleration reaches 0 before the object reaches the destination.

I calculate acceleration like this:

//Linear acceleration starts at 0 and finishes at 2.
acceleration = this.elapsed / (this.duration / 2.0f);

Acceleration will be a value between 0 and 2 depending on how much time has elapsed. The value will be closer to 2 when elapsed is closer to (total) duration.

So to calculate a deceleration I would do:

 //Linear deceleration starts at 2 and finishes at 0.
 acceleration = 2.0f - this.elapsed / (this.duration / 2.0f);

This appears to work just fine but the decelerating object never reaches the destination, at around 99% of the distance the elapsedTime becomes greater than total duration, causing the acceleration to become negative. In other words, it appears to have decelerated about 1% too fast.

The original acceleration works perfectly, so does the linear velocity. It's just the deceleration that isn't working properly.

Am I doing something wrong?

Thanks

mclark1129
  • 7,532
  • 5
  • 48
  • 84
Orujimaru
  • 835
  • 2
  • 13
  • 18
  • 1
    Please clarify the quanities you're expressing (acceleration, velocity, displacement, time?) and the units of the variables involved. As I read it right now, you're setting acceleration = time/time, which makes no sense. – Dan Bryant Oct 10 '12 at 16:46
  • What datatypes are elapsed and duration? Are they also floats or are they integers? – mclark1129 Oct 10 '12 at 16:50
  • In my code at the moment duration is 2000, this means it will take 2 seconds for the object to reach the destination. elapsed is for how long the object has been moving since it left the initial position. So when it has moved for 1 second, acceleration would be 1.0f. When it has moved for 0.5f second, the acceleration would be 0.5 etc. Then I invert this for the deceleration, so after 0.5 seconds the acceleration would be 1.5f if the object is decelerating. This gives me an average acceleration of 1.0 so it reaches the destination at the same time the object with out acceleration does. – Orujimaru Oct 10 '12 at 16:51
  • @Mike C all values are floats – Orujimaru Oct 10 '12 at 16:51
  • What happens if you switch to `double`s? – markmuetz Oct 10 '12 at 17:09
  • Or switch to `decimal`? Cram in that precision! – Bobson Oct 10 '12 at 17:13
  • Also, the deceleration should be negative. What starting velocity does your decelerating object start with? What velocity will it end with? How far will it travel in total? – markmuetz Oct 10 '12 at 17:34
  • Thanks for all the great comments and answers, I'm going to try all of this tomorrow when I get back to my working station. – Orujimaru Oct 10 '12 at 18:57

2 Answers2

1

You could try to use the C# Clamp function for floats: http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.mathhelper.clamp.aspx

acceleration = MathHelper.Clamp(2.0f - this.elapsed/(this.duration/2.0f), 0.0, 2.0);

It simply sets a min and max value for the first param.

Christopher Bales
  • 1,069
  • 1
  • 13
  • 23
  • Thanks for the suggestion, I didn't know about MathHelper. This makes other parts of my code a lot cleaner. But I'm afraid it didn't solve my issue. The object still doesn't reach the destination. – Orujimaru Oct 10 '12 at 16:58
1

Without seeing your full code, I think the problem is probably due to using a float as an iteration variable in a for loop somewhere.

Using the following program as an example, I am able to replicate that the floating point precision gets kind of screwed up somewhere in the loop when I try to use the float as my iteration variable directly.

float duration = 10f;

for(float elapsed = 0.0f; elapsed <= duration; elapsed = elapsed + 0.1f) {
    Console.WriteLine(2.0f - elapsed / (duration / 2.0f));
}

Console.ReadLine();

The output of this program is:

2
1.98
1.96
1.94
1.92
1.9
1.88
1.86
1.84
1.82
1.8
1.78
1.76
1.74
1.72
1.7
1.68
1.66
1.64
1.62
1.6
1.58
1.56
1.54
1.52
1.5
1.48
1.46
1.44
1.42
1.4
1.38
1.36
1.34
1.32
1.3
1.28
1.26
1.24
1.22
1.2
1.18
1.16
1.14
1.12
1.1
1.08
1.06
1.04
1.02
1
0.9800005
0.9600005
0.9400005
0.9200006
0.9000006
0.8800006
0.8600006
0.8400006
0.8200006
0.8000007
0.7800007
0.7600007
0.7400007
0.7200007
0.7000008
0.6800008
0.6600008
0.6400008
0.6200008
0.6000009
0.5800009
0.5600009
0.5400009
0.5200009
0.500001
0.480001
0.460001
0.440001
0.420001
0.400001
0.3800011
0.360001
0.3400009
0.3200008
0.3000008
0.2800007
0.2600006
0.2400005
0.2200005
0.2000004
0.1800003
0.1600002
0.1400001
0.1200001
0.1
0.07999992
0.05999985
0.03999977
0.01999969

You can see that about halfway through the precision shoots way out, and that is because the precision for the iteration variable itself gets screwed up.

In the second example, I use an integer as the iteration variable instead and I simply scale the integer to my calculation inside of each iteration. This prevents the iteration variable from going all screwy:

float duration = 10f;
float offset_scale = 10.0f;

for (int elapsed = 0; elapsed <= (duration * offset_scale); elapsed++) {
    Console.WriteLine(2.0f - (elapsed / offset_scale) / (duration / 2.0f));
}

Console.ReadLine();

The output for this program is:

2
1.98
1.96
1.94
1.92
1.9
1.88
1.86
1.84
1.82
1.8
1.78
1.76
1.74
1.72
1.7
1.68
1.66
1.64
1.62
1.6
1.58
1.56
1.54
1.52
1.5
1.48
1.46
1.44
1.42
1.4
1.38
1.36
1.34
1.32
1.3
1.28
1.26
1.24
1.22
1.2
1.18
1.16
1.14
1.12
1.1
1.08
1.06
1.04
1.02
1
0.98
0.96
0.94
0.92
0.9
0.88
0.86
0.84
0.82
0.8
0.78
0.76
0.74
0.72
0.7
0.68
0.66
0.64
0.62
0.6
0.58
0.56
0.54
0.52
0.5
0.48
0.46
0.44
0.42
0.4
0.38
0.36
0.34
0.32
0.3
0.28
0.26
0.24
0.22
0.2
0.18
0.16
0.14
0.12
0.1
0.08
0.06
0.04
0.02
0

You can see that the precision never goes crazy, and the result ends up right at 0.

mclark1129
  • 7,532
  • 5
  • 48
  • 84
  • That's a really good call, and I think that might be my problem. But I'm not sure how to fix it since i'm using XNA's game loop. I tried switching out the floats for ints/doubles/decimals with no success. The acceleration/constant always work fine no matter what kind of value I use, but the deceleration never works. However I came up with a workaround, when the elapsed reaches the duration I force the value to the maximum (now the object doesn't get out of sync and the jump in the end isn't visible at all, since it's only >1%). I'm going to pick your answer anyway, I think it can help others. – Orujimaru Oct 11 '12 at 05:47
  • I wanted to add that the same thing probably happens for the acceleration: the acceleration probably exceeds 2.0 by the same amount the deceleration misses 2.0 with. But I wouldn't notice the acceleration exceeding 2.0 since it reaches its target anyway. Is it possible that this has something to do with XNA's GameTime? – Orujimaru Oct 11 '12 at 05:58