Jump to content
Search Community

shifting the object origin point in bezier animations

da2020 test
Moderator Tag

Recommended Posts

Hi,

 

I'm using the v12 bezier plugin to animate objects along curved paths using the "through points" option), and am looking for a way to shift the origin (registration) point for the object being tweened so that it can be centered on the path (the path is made visible in this app by drawing it via the flash drawing api method described in the bezier plug-in api documentation, which does match exactly with the actual tween path).

 

The challenge here is that this is being done in an "add-on" app of sorts to a commercial flash-based elearning authoring tool.. In this environment, I am not able to use what seem to be the standard tricks for moving origin points (ie, the object being animated is created by the authoring app, and therefore I cannot re-parent it to carry out the shell container shift trick (the app won't allow that type of change to the top level display list), and because of the complex child hierarcy of these objects I cannot use the transform matrix approach on the object's contents either). The good news is that, within the add-on app I'm developing, I can tween the object nicely using the gs v12 bezier plugin (need the through points curved paths this provides), but the object is tweened at its default "top=left" origin point, which is not acceptable in this use case -- I need to center it, and also need to use auto-orient-along-path option as well (which the bezier plugin also supports nicely).  I thought perhaps the tranformAroundCenter plugin would help, but from what I've read in the forum this plugin only works for basic tween types, and does not work with the bezier plugin.

 

So, one approach I'm considering is to use an enter-frame handler to track the movement of a dummy object being bezier tweened, and assign the dummy object's rotation and offset  x - y values for the actual object there (some trig needed here, I think, to get the right x- y offset values, given that auto-orient rotation is happening). I think this could be made to work, but don't like the overhead implications of frame-by-frame tracking of the tween.

 

The idea I like best is to, once at initialization time, simply decalre the actual tween curve such that it is shifted away from the visible drawn curve, such that the end-result is that the object appears to animate centered on the drawn path.  This is easy if not using auto-orient-along-path, as it's just a matter of shifting the bezier through points (relative to the visible drawn path) by the x and y amounts of 1/2 the width and heigh of the object.. It becomes trickier though, when auto-orient-along-path is enabled, because the rotation that occurs makes the simple x-y offsets for the tween declaration difficult/impossible to know -- so this is where I'm stuck..  IF there were a way to use the bezier plugin along with timelinemax to somehow, as part of "initialization", go to the defined through points one by one, then check the object rotation value at each of those points, and then use that info to calc the x-offsets at those points using trig, then I think the offset tween curve "through" points could be determined and plugged into the bezier tween declaration statement... but I don't see support for "going to" the bezier through points to do such a thing.... So, the question is, can this be done somehow, or are there ideas on an alternate approach that would be better, given the constraints of the hosting authoring tool mentioned above?

 

Thanks for any insights/suggestions,

 

Doug

Link to comment
Share on other sites

Hm, I think I see exactly what you're saying. Too bad you can't use the wrapper Sprite concept. 

 

I'd probably just use an onUpdate and figure out the offset x/y based on the rotation. For example, let's say we've got a MovieClip named "mc" and its registration point is in its upper left corner, but we actually want it to position itself on the Bezier path as if its CENTER is on the path, we could do this:

var xOffset:Number = -mc.width / 2;
var yOffset:Number = -mc.height / 2;
TweenMax.to(mc, 5, {bezier:{values:[{x:dot1.x, y:dot1.y}, {x:dot2.x, y:dot2.y}, {x:dot3.x, y:dot3.y}], autoRotate:true}, onUpdate:applyOffset});

function applyOffset():void {
	var angle:Number = mc.rotation * Math.PI / 180;
	var cos:Number = Math.cos(angle);
	var sin:Number = Math.sin(angle);
	mc.x += cos * xOffset - sin * yOffset;
	mc.y += cos * yOffset + sin * xOffset;
}

Does that help?

  • Like 1
Link to comment
Share on other sites

Jack,

 

Thanks for the suggestion and code snippet.. I incorporated your approach and the equations but it did not have any net effect as far as centering the object.. I traced the expressions for mc.x and mc.y and they actually each net out to zero at every point, so there is no offset applied for either x or y, as written.

 

When I was working on my own trig-based solution earlier, I got close by just using cos for the x calc and sin for the y calc... but could never achieve consistent centering over the entire path -- I think part of the problem is that the object being animated has changing width/height values over time -- I think this may be due to how the bounding box widens and narrows as rotation occurs.

 

Anyway, since my post above, I was able to work out what appears to be a reliable non-trig solution by  using a variation on the popular container-with-shifted-child approach for centering.  As mentioned in my earlier post, I can't simply re-parent the target to be inside a container  due to constraints in the hosting app. As a workaround, I created a proxy child object inside a container as if it were the target, offset  the child based on 1/2 the dimensions of the target object, and then in the enter frame handler I simply assigned the x and y coordinates of target to equal the global space x and y values of the shifted child (where the container (parent) object was the one actually being tweened), and also set the rotation of the target to match the rotation of the container..  Since the global (stage) space coordinates were needed, the child x and y coordinates could not just be read directly, because that just results in getting fixed numbers that relate to the child's coordinate space within the container parent --- so, needed to use the localToGlobal method to get a point that was in terms of the global coordinate space.   Got good centering results with this approach across the full bezier paths, and it's fairly intuitive and easy to tweak.

 

 

- Doug

Link to comment
Share on other sites

Glad to hear you found a solution, Doug. I'd be curious to see how you were applying my original code snippet, as I tested it on my end and it worked beautifully. The registration point was in mc's top left corner, but it animated on the path as if its center was locked to the path. Buttery smooth too. I'm not sure why you saw a net zero effect. I wonder if your xOffset and yOffset were zero? 

 

Anyway, not critically important at all if you've already got a solution. Thanks for letting us know. 

Link to comment
Share on other sites

Jack,

 

Good to know.. In just looking, I think I may have dropped the assignment statements for the 2 offset values in a spot that executes prior to the code that initializes the existing variables I was using... ie, you may be right that they were both zero inadvertently..  I'll try this out later and let you know.

The only other difference is my tween declaration, but I don't think this would present a problem:

TweenMax.to(tweenObject, 5, {bezier:{curviness:1, timeResolution:9, autoRotate:["x","y","rotation", 90,false], values:[{x:tweenPoint2X, y:tweenPoint2Y}, {x:tweenPoint3X, y:tweenPoint3Y}]}, ease:Linear.easeNone});

 

Note I had the the auto-rotate set at 90 to shift the facing forward point of the object to be the "top" of it -- but wouldn't think this should matter.    The curve is roughly a parabola shape. The timeResolution value has been set high as an experimental setting to force a faitly constant speed regardless of point spacing...

 

 I haven't quite yet got my mind around using both the cos and sin calcs in that manner in each of the offset calculations... been away from the trig side of things too long.. is there a reference you could point me too that addresses this particular technique? In prior attempts, I had just been using cos for x and sin for y offset calcs. 

 

By the way, I'm using the approach laid out in the Bezier plug-in API doc to use the flash curve drawing API to draw a visible path that matches the tween path..  It's an exact match when tween "curviness" is set to 1, but I'm wondering if there's a way to plot the curve to match other curviness values?

 

Thanks,

 

Doug

Link to comment
Share on other sites

Hi Jack,

 

Update -- I did in fact have an error in where/when I initiatilized the offsets, and this resulted in the 0 value calc results... After correcting that, I'm seeing your trig code work perfectly -- now I have two viable solutions it seems! 
The only app-specific issue I have now is that some of the objects being animated in the hosting app have children with display elements that add width to the overall visual entity, such as stroke elements that can have varying widths extending beyond the parent's width (these aren't reflected in the width property of the top level object, so the centering is off a bit when these are present) ... so, I'm hoping I can find a generic way to get true "total width" that includes the effects of child elements (without having to dig throught the dimensions of all the actual children, which vary a lot depending on the type of object construction)...  

 

Still wondering a couple of things:

 

- do you have a reference that explains the nature of the trig calcs that use both x and y sin/cos elements in EACH offset calc, as you did (I suppose this is just "common sense" for animation gurus, but I'm a bit rusty in the applied trig area)

 

- what would you suggest for being able to display a plot that matches the bezier tween curves? Right now I'm using the flash curveTo quadratic method suggested in the API doc for the bezier plug-in, but that only matches if the tween "curviness" is set to 1 (normal). Hoping to be able to get a matching plot that works with any curviness setting... I suppose I could draw the path via the actual animated object's path by running the tween once just to create the path, but that could be a little clunky... My intended use case is providing a friendly UI so that a non-flash author can set/drag anchor points, and change curviness values, etc, and instantly see the plotted animation path that results.. 

 

Thanks,

 

Doug

Link to comment
Share on other sites

To answer your questions....

  1. The math isn't exactly "obvious", no - it's something I got from a book. I could walk through the trigonometry in a longer fashion but that particular formula is more optimized and short. Just trust me - it works :)
  2. You can use the BezierPlugin.bezierThrough() method to feed it your points and have it spit back to you either cubic Bezier data or quadratic Bezier data for the path(s) that go through those points. Then, you can take that and feed it to Flash's drawing methods to actually draw the Bezier to the screen. Like sprite.graphics.curveTo(). For the BezierPlugin.bezierThrough() method's docs, see http://api.greensock.com/as/com/greensock/plugins/BezierPlugin.html#bezierThrough()

Is that what you were looking for?

Link to comment
Share on other sites

Thanks Jack.

 

Regarding item 2, I was doing as you suggest, BUT, somehow I completely missed the fact that BezierThrough ALSO has a curviness parameter which I just noticed in checking the documentation again... so, with that it seems I can get the plot to match the tween path exactly for all curviness settings.... very cool.

 

Thanks again,

 

Doug
 

  • Like 2
Link to comment
Share on other sites

  • 2 years later...

Hm, I think I see exactly what you're saying. Too bad you can't use the wrapper Sprite concept. 

 

I'd probably just use an onUpdate and figure out the offset x/y based on the rotation. For example, let's say we've got a MovieClip named "mc" and its registration point is in its upper left corner, but we actually want it to position itself on the Bezier path as if its CENTER is on the path, we could do this:

var xOffset:Number = -mc.width / 2;
var yOffset:Number = -mc.height / 2;
TweenMax.to(mc, 5, {bezier:{values:[{x:dot1.x, y:dot1.y}, {x:dot2.x, y:dot2.y}, {x:dot3.x, y:dot3.y}], autoRotate:true}, onUpdate:applyOffset});

function applyOffset():void {
	var angle:Number = mc.rotation * Math.PI / 180;
	var cos:Number = Math.cos(angle);
	var sin:Number = Math.sin(angle);
	mc.x += cos * xOffset - sin * yOffset;
	mc.y += cos * yOffset + sin * xOffset;
}

Does that help?

so i have few number of tweens so when i use this function the last one which is accessing the function is getting tweened , for example i have 3 mc's and each mc will do this as i am using timeline max all the tweens will be done at the same point of time so the last tween which access this will change , the other two wont change , any suggestions?

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
  • Recently Browsing   0 members

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