Interactive Spin Actionscript Tutorial
I have been thinking of different interactions that are possible with objects. If you’ve read this blog at all you’ll know that I’ve played with physics and gravity and throwing balls and bouncing balls and all sorts. But I hadn’t wrapped my head around an interactive spinner. I know it’d be easy to make a slider or something that would apply a spin to an object, but this just isn’t interactive enough for me.
Circle with slider to rotate and button for random spin:
This attempt at spinning is ok. I mean, it spins the object and it even glides to a stop if you press the button for a random spin… But it’s just not intuitive and not fun. But if you want this, here’s how I did it.
Actionscript:
- drag = .96;
- speed = 0;
- slider.handle.onPress = function() {
- spinning = false;
- //drag along the line
- this.startDrag(true, slider.line._x-slider.handle._width/2, slider.line._y-slider.handle._height/2, slider.line._width-slider.handle._width/2, slider.line._y-slider.handle._height/2);
- }
- slider.handle.onRelease = slider.handle.onReleaseOutside = function() {
- this.stopDrag();
- }
- _root.onEnterFrame = function() {
- if (spinning) {
- //apply the speed to the rotation
- knob._rotation += speed;
- //recalculate speed
- speed = speed*drag;
- //if speed gets unnoticeably tiny just set it to 0
- if (Math.pow(speed, 2) < .0001) {
- speed = 0;
- }
- }
- else {
- //set the rotation from the slider position
- knob._rotation = slider.line._x + slider.handle._x + slider.handle._width/2;
- }
- //spit out feedback continuously
- feedbackr.text = knob._rotation;
- feedbackaccr.text = speed;
- }
- spinner.onRelease = function() {
- //find a random speed
- speed = (Math.random()* 50) - 25;
- spinning = true;
- }
I want to grab it and spin it though. I want to apply the same principles from physics, like acceleration and friction as forces to the object, so I can grab to spin and release to watch it glide gracefully to a stop. I’ve been thinking about this and how I’d have to use trigonometry and stuff to do it. One day I finally had the time and tried it out. It took me a minute but I figured out that what I needed was arctangent. So (with pointers from jbum, thanks Jim!) I came up with this:
Interactive grab-able circle to spin and twirl:
This one is much more interactive and intuitive. I really think this is because there are no sliders or buttons, no controls, just an object to interact with. It’s much more like real life!
Steps:
In order to make a grab and spin object
1. You have to know where you grab. The user clicks on the shape (knob) and you must figure out what degree or rotation point they have started at. (atan2)
2. As the knob is clicked and the mouse moves (dragging), calculate new rotation by mouse position
3. When mouse is released figure out the current speed of rotation and apply it to the knob with friction, so it can be thrown and spun in that way. (Of course this is optional, if you just want to spin it when the mouse is down you’re done at step 2)
Actionscript:
- damp = .96; //friction
- r = 0; //rotation
- accr = 0; //speed of rotation
- knob.onPress = function() {
- dragging = true;
- //find mouse y coordinate in relation to knob origin
- a = _root._ymouse - knob._y;
- //find mouse x coordinate in relation to knob origin
- b = _root._xmouse - knob._x;
- //using arctangent find the spot of rotation (in degrees)
- oldr = Math.atan2(a,b)*180/Math.PI;
- }
- knob.onRelease = knob.onReleaseOutside = function() {
- dragging = false;
- }
- knob.onEnterFrame = function() {
- if (dragging) {
- //find mouse y coordinate in relation to knob origin
- a = _root._ymouse-knob._y;
- //find mouse x coordinate in relation to knob origin
- b = _root._xmouse-knob._x;
- //using arctangent find the spot of rotation (in degrees)
- r = Math.atan2(a,b)*180/Math.PI;
- //use current rotation and previous rotation
- //to find acceleration
- //averages the acceleration with the
- //previous acceleration for smoother spins
- accr = ((r - oldr) + accr)/2;
- //apply the acceleration to the rotation
- knob._rotation += accr;
- //remember current rotation as old rotation
- oldr = r;
- feedbacka.text = a;
- feedbackb.text = b;
- }
- else {
- knob._rotation += accr;
- //apply friction to acceleration force
- //and if acceleration gets tiny, just set it to zero
- if (Math.pow(accr, 2) > .0001 ) {
- accr *= damp;
- }
- else{
- accr = 0;
- }
- }
- //spit out feedback continuosly
- feedbackr.text = knob._rotation;
- feedbackaccr.text = accr;
- }
I commented the code to explain what is happening, if you need more just post a comment. Let me know if you find this useful and what you end up making with it.





























Hi Evan
Grab the knob and rotate it all the way around for one revolution without letting go.
There is a rather violent movement when the user rotates the knob all the way through x < 0 and when y passes through 0 (positive to negative or negative to positive). It jumps to the other side (180 deg away) and then rapidly comes back again.
I would suggest not using atan2 and using only sine to determine your rotation.
Thanks for catching that Zac, I hadn’t noticed that hiccup in there…
It seems to be when it is calculating the acceleration as you drag through the negative x-axis (from the origin of the knob). It’s because I’m using the difference between old rotation and current rotation to find the acceleration (line 32), and when oldr is -179 and new is 180 that makes for quite a bit of acceleration… accr = ((r - oldr) + accr)/2; … it helps I guess that it’s averaged with the old accr, but it doesn’t correct it by any means.
When I have some time I’ll have to get in and map the accr calculation correctly to see the values as circular, … 178, 179, 180, -179, -178 …
Here’s a fix, albeit not perfect, to the above mentioned problem. Within the onEnterFrame actions, find the line that says:
accr = ((r-oldr)+accr)/2;
and change it to this….
if (r-oldr > 160 || r-oldr < -160){
accr = ((0)+accr);
}else{
accr = ((r-oldr)+accr)/2;
}
I’m in the process of implementing this code into a project. When it’s ready I’ll try to remember to link it.
thanks you guys both. This is perfect for what i am doing. (making tutorials for a gas-fitting school), i am going to try apply this rotation to one of the gas taps. Just have to figure out how to make a ‘maximum’ amount of turns.
Great tutorial. One question, how would I make the knob only spin a certain degree? Say if I wanted this to be a volume knob and would want it to only spin a certain degree as if turning the knob on a speaker amplifier. Thanks!