Jump to content
Search Community

ThrowProps Rotation - min and max Values

Terry test
Moderator Tag

Recommended Posts

I'm using the throwProps_rotation_demo.fla file to experiement with setting the min and max values with the ThrowPropsPlugin, and I'm not able to get the min and max values to work.

 

In the demo, the initial rotation value of the dial is zero. I've set min and max values in the ThrowPropsPlugin call to non-negative numbers:

ThrowPropsPlugin.to(dial, {throwProps:{rotation:rVelocity, resistance:250, min:0, max:145}, ease:Strong.easeOut}, 10, 0.25, 2);

When I test the file by flicking the dial, the dial will rotate beyond the min or max value and continue to rotate instead of reversing back to the min or max value.

 

I haven't been able to detect a pattern. The problem happens when the dial's rotation value is within the min and max values and the ThrowPropsPlugin call is made.

 

Any idea why this would happen?

Link to comment
Share on other sites

You just nested the values incorrectly:

 

BAD: ThrowPropsPlugin.to(dial, {throwProps:{rotation:rVelocity, resistance:250, min:0, max:145}, ease:Strong.easeOut}, 10, 0.25, 2);

GOOD: ThrowPropsPlugin.to(dial, {throwProps:{rotation:{velocity:rVelocity, min:0, max:145}, resistance:250}, ease:Strong.easeOut}, 10, 0.25, 2);

 

That'll cap the values for you, but the tricky thing about rotation values is that they're non-linear. Like 359 is only 1 degree away from 0. And -270 is the same as 90, etc. So if you want to allow the dial to be spun multiple times around (based on the velocity of the user's mouse when they release it) and always land within your max/min values, there's some extra work that needs to be done. I've attached an FLA that demonstrates it using your values of min:0 and max:145. Here's the raw code too:

 

import com.greensock.*;
import com.greensock.plugins.*;
import com.greensock.easing.*;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.utils.getTimer;
import flash.display.*;

TweenPlugin.activate([ThrowPropsPlugin]);

var RAD2DEG:Number = 180 / Math.PI;
var t1:uint, t2:uint, r1:Number, r2:Number, offset:Number;

dial.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);

function mouseDownHandler(event:MouseEvent):void {
TweenLite.killTweensOf(dial);
offset = Math.atan2(dial.y - this.mouseY, this.mouseX - dial.x);
r1 = r2 = dial.rotation;
t1 = t2 = getTimer();
dial.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
dial.stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}

function enterFrameHandler(event:Event):void {
r2 = r1;
t2 = t1;
var newOffset:Number = Math.atan2(dial.y - this.mouseY, this.mouseX - dial.x);
dial.rotation += (offset - newOffset) * RAD2DEG;
offset = newOffset;
r1 = dial.rotation;
t1 = getTimer();
}

function mouseUpHandler(event:MouseEvent):void {
dial.stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
dial.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
var time:Number = (getTimer() - t2) / 1000;
var rVelocity:Number = getShortAngle(dial.rotation, r2, false) / time;

var max:Number = 145;
var min:Number = 0;
var resistance:Number = 250;
//calculate the duration so that we can plug it into the calculateChange() method to find out where exactly the rotation will end up if we don't apply any limits (max/min)
var duration:Number = ThrowPropsPlugin.calculateTweenDuration(dial, {throwProps:{rotation:rVelocity, resistance:resistance}, ease:Strong.easeOut}, 10, 0.25, 2);
//figure out where it'll land normally
var landingValue:Number = dial.rotation + ThrowPropsPlugin.calculateChange(rVelocity, Strong.easeOut, duration);
//translate the end rotation into a value between 0 and 360
var normalized:Number = landingValue % 360;
if (normalized 		normalized += 360;
}
if (normalized  max) {
	//figure out the angle to the min and the max and then whichever one is less (shorter distance), we'll snap the end value to that one.
	var angleToMin:Number = getShortAngle(normalized, min, false);
	var angleToMax:Number = getShortAngle(normalized, max, false);
	if (Math.abs(angleToMin) 			landingValue -= angleToMin;
	} else {
		landingValue -= angleToMax;
	}
} 
ThrowPropsPlugin.to(dial, {throwProps:{rotation:{velocity:rVelocity, min:landingValue, max:landingValue}, resistance:resistance}, ease:Strong.easeOut}, 10, 0.25, 2);

//This was the normal tween with no min/max
//ThrowPropsPlugin.to(dial, {throwProps:{rotation:{velocity:rVelocity}, resistance:250}, ease:Strong.easeOut}, 10, 0.25, 2);
}

function getShortAngle(angle1:Number, angle2:Number, useRadians:Boolean=false):Number {
var cap:Number = useRadians ? Math.PI * 2 : 360;
var dif:Number = angle1 - angle2;
if (dif != dif % (cap / 2)) {
	dif += (dif 	}
return dif;
}

 

Hope that helps!

Link to comment
Share on other sites

  • 4 weeks later...

Hi there,

 

Very nice Rotation effect. I am playing around with this example because I'm trying to get the dial to slowly rotate around when the mouse isn't down on the object.

However, I'm getting the following error ArgumentError: Error #1063: Argument count mismatch on starters_App_fla::MainTimeline/startAgain(). Expected 1, got 0.

 

Here's greensock's code with a few additions:

import com.greensock.*;
import com.greensock.plugins.*;
import com.greensock.easing.*;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.utils.getTimer;
import flash.display.*;
import flash.events.Event;

TweenPlugin.activate([ThrowPropsPlugin]);
dial.buttonMode = true;

var RAD2DEG:Number = 180 / Math.PI;
var t1:uint, t2:uint, r1:Number, r2:Number, offset:Number;

dial.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
dial.addEventListener(Event.ENTER_FRAME, noMouseDownHandler);


////to rotate the object when move is up//////
function noMouseDownHandler(event:Event):void {
TweenMax.to(dial, 35, {rotation:"350", timeScale:0.01, useFrames:true, repeat:-1, ease:Linear.easeNone});
}

function mouseDownHandler(event:MouseEvent):void {
dial.removeEventListener(Event.ENTER_FRAME, noMouseDownHandler);
TweenLite.killTweensOf(dial);
offset = Math.atan2(dial.y - this.mouseY, this.mouseX - dial.x);
r1 = r2 = dial.rotation;
t1 = t2 = getTimer();
dial.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
dial.stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}

function enterFrameHandler(event:Event):void {
r2 = r1;
t2 = t1;
var newOffset:Number = Math.atan2(dial.y - this.mouseY, this.mouseX - dial.x);
dial.rotation += (offset - newOffset) * RAD2DEG;
offset = newOffset;
r1 = dial.rotation;
t1 = getTimer();
}

function mouseUpHandler(event:MouseEvent):void {
dial.stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
dial.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
var time:Number = (getTimer() - t2) / 1000;
var rVelocity:Number = getShortAngle(dial.rotation, r2, false) / time;

var max:Number = 145;
var min:Number = 0;
var resistance:Number = 250;
//calculate the duration so that we can plug it into the calculateChange() method to find out where exactly the rotation will end up if we don't apply any limits (max/min)
var duration:Number = ThrowPropsPlugin.calculateTweenDuration(dial, {throwProps:{rotation:rVelocity, resistance:resistance}, ease:Strong.easeOut}, 10, 0.25, 2);
//figure out where it'll land normally
var landingValue:Number = dial.rotation + ThrowPropsPlugin.calculateChange(rVelocity, Strong.easeOut, duration);
//translate the end rotation into a value between 0 and 360
var normalized:Number = landingValue % 360;
if (normalized < 0) {
	normalized += 360;
}
if (normalized < min || normalized > max) {
	//figure out the angle to the min and the max and then whichever one is less (shorter distance), we'll snap the end value to that one.
	var angleToMin:Number = getShortAngle(normalized, min, false);
	var angleToMax:Number = getShortAngle(normalized, max, false);
	if (Math.abs(angleToMin) < Math.abs(angleToMax)) {
		landingValue -= angleToMin;
	} else {
		landingValue -= angleToMax;
	}
} 
ThrowPropsPlugin.to(dial, {throwProps:{rotation:{velocity:rVelocity, min:landingValue, max:landingValue}, resistance:resistance}, ease:Strong.easeOut, onComplete:startAgain}, 10, 0.25, 2);

//This was the normal tween with no min/max
//ThrowPropsPlugin.to(dial, {throwProps:{rotation:{velocity:rVelocity}, resistance:250}, ease:Strong.easeOut}, 10, 0.25, 2);
}
//////to start the slow rotation again after the ThrowProps has finished ///////
function startAgain(event:Event):void
{
dial.addEventListener(Event.ENTER_FRAME, noMouseDownHandler);
}


function getShortAngle(angle1:Number, angle2:Number, useRadians:Boolean=false):Number {
var cap:Number = useRadians ? Math.PI * 2 : 360;
var dif:Number = angle1 - angle2;
if (dif != dif % (cap / 2)) {
	dif += (dif < 0) ? cap : -cap;
}
return dif;
}

Any help much appreciated.

Ben.

Link to comment
Share on other sites

When you use

 

ThrowPropsPlugin.to(dial, {throwProps:{rotation:{velocity:rVelocity, min:landingValue, max:landingValue}, resistance:resistance}, ease:Strong.easeOut, onComplete:startAgain}, 10, 0.25, 2);

 

to trigger the onComplete, an Event object is not passed to the callback function.

 

so change startAgain to:

 

function startAgain():void
{
  dial.addEventListener(Event.ENTER_FRAME, noMouseDownHandler);
}

 

 

now startAgain() is expecting 0 arguments and the error should go away

Link to comment
Share on other sites

  • 2 weeks later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...