NumericUpDown in Windows Forms and a small acceleration hack...

Since I've been chatting about acceleration, I figured I'd point out how and where these types of methods could be used to make your life simpler and how sometimes a basic hack will do. The first exercise is going to be taking a NumericUpDown and setting the maximum value to somewhere around 1 million. Next, run the app, press and hold the up button. What you'll notice is that the longer you hold it the faster the increment gets. The problem you'll quickly find is that reaching 1 million is going to be hard. You could mess with the interval, but then users won't be able to set values in between the interval without editing the text of the control directly.

How does the NumericUpDown achieve acceleraton? First, they use a timer while the user holds the mouse button down. The timer is set to 500 milliseconds initially and is then modified by 0.7 and truncated (well, they appear to multiply by 7 then divide by 10). As you can see the timer messages will get more and more frequent. Each time a message is processed the control is incremented or decremented by the current interval. This is pretty much just an acceleration hack. In fact, the fastest the control can move is the speed of a propagating timer event, which is something like once every 50ms and it will always move at some constant velocity once it achieves the maximum speed of a timer.

Could we make the control a bit more robust? Sure, we could fix the timer at something like a quarater of a second, and then run the physics to figure out how many spaces have been sped past. Our initial velocity is 1, since we'll update the control by at least once each time. Our acceleration might be 4items/s^2. The Windows Forms control gets up to speed pretty fast. In fact, it hits the 20 increment (1000 / 50) point around 1 and a half seconds. Our new acceleration function would hit 20 items per second after 5 seconds... That makes it a bit slower to start, but much faster later. The designer for the control would allow you to set the actual physics though and you could modify exactly how fast the control would go. For instance, the acceleration itself might be a function. You could even have the acceleration ramps geared towards how the user operates with the control. Given enough user input on the spinner and seeing how often the user has to correct or how long they have to depress a button to get a desired result you can try to optimize the entire process.

I also want to talk about another popular style of control that you often see on TV, but rarely get a chance to experience on the computer. The counting label is constantly used to graphically animate some score or value into existence. Before the control starts all the fields are 0'ed out of course. Then the control operates for some fixed period of time, or sometimes not, and eventually settles into a final result. There are plenty of hacky ways to do this:

  • Rotate all spinners simultaneously, stop each digit place on the appropriate digit. This is a reel approach and isn't a counter.
  • Add a fixed amount at each time step. This is the most popular and produces those 10-15 second waits when you get a bitchin score.
  • Scale the fixed amount to to the operation time. Another popular approach resulting in a fixed time to score.

If you really want to be cool, you have to use acceleration and deceleration. You want to haul butt to some point in the count-down and then you want to ease off and decelerate the final digits into place. You might set the acceleration period to something like 4 seconds, and the deceleration period to 2 seconds. The total 6 second animation would be very pleasing overall.

using System;

public class AccelerationModeler {
    private static void Main(string[] args) {
        int previous = 0;
        for(int i = 0; i < 25; i++) {
            int currentScore = GetScore(1000000, 4f, 2f, 0.25f * i);
            Console.WriteLine("Current: {0}, Delta: {1}", currentScore, currentScore - previous);
            previous = currentScore;
        }
    }
   
    private static int GetScore(int totalScore, float tAccel, float tDecel, float tCurrent) {
        // We want the acceleration period to cover a distance proportional to it's time.
        float accelDistance = totalScore * (tAccel / (tAccel + tDecel));
        float acceleration = (2*accelDistance)/(tAccel*tAccel);
        float finalVelocity = acceleration * tAccel;
       
        // Now, we need to slow down system
        float decelDistance = totalScore - accelDistance;
        float deceleration = -(finalVelocity / tDecel);
       
        if ( tCurrent > (tAccel + tDecel) ) {
            return totalScore;
        } else if ( tCurrent < tAccel ) {
            return (int) (0.5*acceleration*(tCurrent*tCurrent));
        } else {
            return (int) (accelDistance + (finalVelocity * (tCurrent - tAccel) + (0.5*deceleration*((tCurrent - tAccel)*(tCurrent - tAccel)))));
        }
    }
}

Published Thursday, September 02, 2004 6:55 PM by Justin Rogers

Comments

Friday, September 03, 2004 1:47 PM by Paul

# re: NumericUpDown in Windows Forms and a small acceleration hack...

I had a quick question on why the number calculated uses return (int) (0.5*acceleration*(tCurrent*tCurrent)); instead of just calculating the returned number as a velocity and using acceleration * tCurrent?

Thanks
Friday, September 03, 2004 4:51 PM by Justin Rogers

# re: NumericUpDown in Windows Forms and a small acceleration hack...

Ah a great question.

Acceleration is how fast the velocity is changing. If you run the sample program, acceleration is responsible for the delta betweens scores being different.

Velocity is how fast the score is changing at some point in time. The score always changes for the positive, but at some point we want it to start changing more slowly again. This terms holds our current speed, while acceleration holds how we change that speed.

Distance is how much of the score we've traversed. The area under the curve. If you wanted a similar function that came up with the same results in terms of score values, at each time point, you'd have to do a different type of work.
----

As an example, take a football player at the 0 yard line. Now, you tell him to run for the 100 yard line. As he first starts out he is building speed. The rate at which he builds speed is his acceleration, while his speed at any point in time is velocity. As he gets to the 30 or 40 yard line he is probably at maximum velocity, but for sake of our argument, let's say he continues to accelerate to the 66 yard line (2/3rds).

He starts to get tired at the 66 yard line and begins to slow down. His positive acceleration, turns negative and he carries his velocity forward (let' say it reached 8y/s), but now his velocity starts to decrease as well. He ran a bit too fast and he is spent. He begins decelerating at nearly twice the rate he accelerated. He finally hits the 100 yard line and collapses in a pile of pads. What values are usable?

a0 = 2y/s^2, v0 = 0y/s, d0 = 0
a1 = -4y/s^2, v1 = 8y/s, d1 = 66y
a2 = 0y/s^2, v2 = 0y/s, d2 = 100y

Both acceleration and velocity are too important in controlling how the yardage changes with respect to time. Only distance (sometimes referred to as displacement) can effectively measure the actual yardage covered during the event.

Leave a Comment

(required) 
(required) 
(optional)
(required)