Previous Page
Next Page

Recipe 11.5. Springs

Problem

You want an object to jump to and settle at a specific point, as if it were attached by a spring or rubber band.

Solution

Use Hooke's Law, the formula for a spring.

Discussion

Hooke's Law describes the forces at work in a spring. In simple terms, it says that the force applied by the spring (acceleration) is proportional to how far it is stretched. This makes total sense. For example, if you barely pull on a rubber band, it snaps back lightly. But if you pull it back as far as you can, it snaps back with enough force to be painful.

Obviously, springs have different amounts of "springiness" or tension. Some are easy to stretch and won't snap back too strongly. Others require a lot more force to pull, and will spring back with an equally strong force. A number can be used to represent each spring's strength. The variable _k represents this constant, and it is generally a small fraction of 1. A value such as 0.1 or 0.2 works well.

When a spring is modeled with ActionScript, you also need to specify a target point that the spring will pull the object to. Finally, you need to apply some damping or friction. In the real world, as an object springs back and forth, it loses a bit of energy and eventually comes to rest somewhere. If you don't add dampening to your code, the object just springs back and forth forever. To apply damping, multiply the velocity values by a fraction, such as 0.95. This removes 5 percent of its speed on each frame, eventually slowing it down to a stop. Here is an example, with all these principles in place:

package {
    import flash.display.Sprite;
    import flash.events.Event;
    
    public class Spring extends Sprite {
        private var _sprite:Sprite;
        private var _vx:Number = 20;
        private var _vy:Number = 0;
        private var _k:Number = .1;
        private var _damp:Number = .94;
        private var _targetX:Number = 200;
        private var _targetY:Number = 200;
        
        public function Spring(  ) {
            _sprite = new Sprite(  );
            _sprite.graphics.beginFill(0x0000ff, 100);
            _sprite.graphics.drawCircle(0, 0, 25);
            _sprite.graphics.endFill(  );
            _sprite.x = 0;
            _sprite.y = 0;
            addChild(_sprite);
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
        }
        
        public function onEnterFrame(event:Event):void {
            var ax:Number = (_targetX - _sprite.x) * _k;
            var ay:Number = (_targetY - _sprite.y) * _k;
            _vx += ax;
            _vy += ay;
            _sprite.x += _vx;
            _sprite.y += _vy;
            _vx *= _damp;
            _vy *= _damp;
        }
    }    
}

In this example, the spring's force, represented by the variable _k, is set to 0.1. The variable _damp is set to 0.94; this variable controls the damping or friction. The target point 200, 200 is stored in the variables _targetX and _targetY.

In the onEnterFrame method, get the distance from the target to the object's current position. This tells you how far the spring is stretched. Multiply this by _k, the spring's strength. This gives you the force (or acceleration) to apply. Add this to the velocity and add the velocity to the position.

Finally, apply the damping by multiplying the velocity by the damp variable.

When you test this, you should see the sprite spring quickly to the target point, go past it, and spring back. Eventually it settles down and comes to rest.

The target point does not have to be stationary. You can easily alter the previous example to use the mouse coordinates as a target by changing the two lines that determine the acceleration:

var ax:Number = (mouseX - _sprite.x) * _k;
var ay:Number = (mouseY - _sprite.y) * _k;

This gives you a very smooth, interactive spring.

Try using different values for _k and _damp to see how you can alter the spring's properties.

See Also

Recipes 11.1, 11.2, and 11.4 for information velocity and acceleration.


Previous Page
Next Page
Converted from CHM to HTML with chm2web Pro 2.85 (unicode)