I don't know if anyone here is old enough to remember ActionScript 2.0 but unfortunately I find myself stuck with it as the game I am writing a mod for (Skyrim) still uses AS2 for UI.
I am using Greensock TweenLite/TimeLineLite for my animations/tweens, but I am having difficulty with what should be some simple co-ordinate calculations.
I am trying to animate icon A from it's starting position, scaling it up and moving in x and y, and finishing in exactly the same position and size as icon B.
Icon A and icon B are within different movieclips two levels up from a common parent clip, so I am trying to use localToGlobal to get stage x/y for each icon, and then moving in x/y by the differences between the two sets of stage co-ordinates.
So for example:
Icon A Global x = 95
Icon B Global x = 150
Difference = 55
Icon A Local x + 55 should put it in the same x position on stage as Icon B right? Well that's nowhere near the result I'm getting on screen, not even close.
To help visualise better this is how the widget looks in game:
And this is how it looks in CS6:
So for example I am attempting to move/scale leftPreselectIcon (Dragonbone War Axe in the example screenshot) into exactly the position of leftIcon (Staff of Firebolts).
Here are the relevant functions:
public function prepareForPreselectAnimation(): Void
{
//This function checks if the preselect icons are to the left or right of their main icon and sets the animate out direction to the opposite side. It also stores current main icon x/y as the target values for the preselect icons to animate to. Finally it gets and stores all necessary current scale and alpha values to ensure everything returns to the exact state it was in prior to starting the animation
var leftIconLTG:Object = {x:(leftIcon._height * 0.5), y:(leftIcon._width * 0.5)};
var leftPreselectIconLTG:Object = {x:(leftPreselectIcon._height * 0.5), y:(leftPreselectIcon._width * 0.5)};
var rightIconLTG:Object = {x:(rightIcon._height * 0.5), y:(rightIcon._width * 0.5)};
var rightPreselectIconLTG:Object = {x:(rightPreselectIcon._height * 0.5), y:(rightPreselectIcon._width * 0.5)};
var shoutIconLTG:Object = {x:(shoutIcon._height * 0.5), y:(shoutIcon._width * 0.5)};
var shoutPreselectIconLTG:Object = {x:(shoutPreselectIcon._height * 0.5), y:(shoutPreselectIcon._width * 0.5)};
leftIcon.localToGlobal(leftIconLTG);
leftPreselectIcon.localToGlobal(leftPreselectIconLTG);
rightIcon.localToGlobal(rightIconLTG);
rightPreselectIcon.localToGlobal(rightPreselectIconLTG);
shoutIcon.localToGlobal(shoutIconLTG);
shoutPreselectIcon.localToGlobal(shoutPreselectIconLTG);
skyui.util.Debug.log("leftIconLTG - x: " + leftIconLTG.x + ", y: " + leftIconLTG.y)
skyui.util.Debug.log("leftPreselectIconLTG - x: " + leftPreselectIconLTG.x + ", y: " + leftPreselectIconLTG.y)
if (leftIconLTG.x > leftPreselectIconLTG.x){
leftTargetX = (leftIcon_mc._width) //If preselect icon is to the left of the main widget animate main widget out to right
//leftPTargetX = (leftIconLTG.x - leftPreselectIconLTG.x) + (leftIcon._width / 2)
} else {
leftTargetX = -(leftIcon_mc._width) //If preselect icon is to the right of the main widget animate main widget out to left
//leftPTargetX = (leftIconLTG.x - leftPreselectIconLTG.x) - (leftIcon._width)
}
leftPTargetX = (leftIconLTG.x - leftPreselectIconLTG.x)
skyui.util.Debug.log("leftTargetX: " + leftTargetX + ", leftPTargetX: " + leftPTargetX)
if (rightIconLTG.x > rightPreselectIconLTG.x){
rightTargetX = (rightIcon_mc._width)
//rightPTargetX = (rightIconLTG.x - rightPreselectIconLTG.x) + (rightIcon._width / 2)
} else {
rightTargetX = -(rightIcon_mc._width)
//rightPTargetX = (rightIconLTG.x - rightPreselectIconLTG.x) - (rightIcon._width)
}
rightPTargetX = (rightIconLTG.x - rightPreselectIconLTG.x)
if (shoutIconLTG.x > shoutPreselectIconLTG.x){
shoutTargetX = (shoutIcon_mc._width)
//shoutPTargetX = (shoutIconLTG.x - shoutPreselectIconLTG.x) + (shoutIcon._width / 2)
} else {
shoutTargetX = -(shoutIcon_mc._width)
//shoutPTargetX = (shoutIconLTG.x - shoutPreselectIconLTG.x) - (shoutIcon._width)
}
shoutPTargetX = (shoutIconLTG.x - shoutPreselectIconLTG.x)
leftPTargetY = leftIconLTG.y - leftPreselectIconLTG.y;
skyui.util.Debug.log("leftPTargetY: " + leftPTargetY)
rightPTargetY = rightIconLTG.y - rightPreselectIconLTG.y;
shoutPTargetY = shoutIconLTG.y - shoutPreselectIconLTG.y;
//Store current alpha and scale values ready to reapply
leftIconAlpha = leftIcon_mc._alpha;
leftTargetScale = ((leftIcon_mc._xscale / leftPreselectIcon_mc._xscale) * 100);
//leftPTargetX = ((leftIconLTG.x - leftPreselectIconLTG.x) * (leftIcon_mc._xscale / leftPreselectIcon_mc._xscale));
leftPIconAlpha = leftPreselectIcon_mc._alpha;
leftPIconScale = leftPreselectIcon._xscale;
rightIconAlpha = rightIcon_mc._alpha;
rightTargetScale = ((rightIcon_mc._xscale / rightPreselectIcon_mc._xscale) * 100);
rightPIconAlpha = rightPreselectIcon_mc._alpha;
rightPIconScale = rightPreselectIcon._xscale;
shoutIconAlpha = shoutIcon_mc._alpha;
shoutTargetScale = ((shoutIcon_mc._xscale / shoutPreselectIcon_mc._xscale) * 100);
shoutPIconAlpha = shoutPreselectIcon_mc._alpha;
shoutPIconScale = shoutPreselectIcon._xscale;
leftNameAlpha = leftName_mc._alpha;
leftPNameAlpha = leftPreselectName_mc._alpha;
rightNameAlpha = rightName_mc._alpha;
rightPNameAlpha = rightPreselectName_mc._alpha;
shoutNameAlpha = shoutName_mc._alpha;
shoutPNameAlpha = shoutPreselectName_mc._alpha;
skse.SendModEvent("iEquip_ReadyForPreselectAnimation", null);
}
public function equipPreselectedItem(iSlot: Number, currIcon: String, newIcon: String, newName: String, currPIcon: String, newPIcon: String, newPName: String): Void
{
var iconClip: MovieClip;
var iconClip_mc: MovieClip;
var currIcon: String;
var pIconClip: MovieClip;
var pIconClip_mc: MovieClip;
var currPIcon: String;
var itemName_mc: MovieClip;
var preselectName_mc: MovieClip;
var targetX: Number;
var pTargetX: Number;
var pTargetY: Number;
var pIconAlpha: Number;
var pIconScale: Number;
var pIconTargetScale: Number
var iconAlpha: Number;
var itemNameAlpha: Number;
var preselectNameAlpha: Number;
switch(iSlot) {
case 0:
iconClip = leftIcon;
iconClip_mc = leftIcon_mc;
pIconClip = leftPreselectIcon;
pIconClip_mc = leftPreselectIcon_mc;
itemName_mc = leftName_mc;
preselectName_mc = leftPreselectName_mc;
targetX = leftTargetX;
pTargetX = leftPTargetX;
pTargetY = leftPTargetY;
pIconAlpha = leftPIconAlpha;
pIconScale = leftPIconScale;
iconAlpha = leftIconAlpha;
pIconTargetScale = leftTargetScale;
itemNameAlpha = leftNameAlpha;
preselectNameAlpha = leftPNameAlpha;
break
case 1:
iconClip = rightIcon;
iconClip_mc = rightIcon_mc;
pIconClip = rightPreselectIcon;
pIconClip_mc = rightPreselectIcon_mc;
itemName_mc = rightName_mc;
preselectName_mc = rightPreselectName_mc;
targetX = rightTargetX;
pTargetX = rightPTargetX;
pTargetY = rightPTargetY;
pIconAlpha = rightPIconAlpha;
pIconScale = rightPIconScale;
iconAlpha = rightIconAlpha;
pIconTargetScale = rightTargetScale;
itemNameAlpha = rightNameAlpha;
preselectNameAlpha = rightPNameAlpha;
break
case 2:
iconClip = shoutIcon;
iconClip_mc = shoutIcon_mc;
pIconClip = shoutPreselectIcon;
pIconClip_mc = shoutPreselectIcon_mc;
itemName_mc = shoutName_mc;
preselectName_mc = shoutPreselectName_mc;
targetX = shoutTargetX;
pTargetX = shoutPTargetX;
pTargetY = shoutPTargetY;
pIconAlpha = shoutPIconAlpha;
pIconScale = shoutPIconScale;
iconAlpha = shoutIconAlpha;
pIconTargetScale = shoutTargetScale;
itemNameAlpha = shoutNameAlpha;
preselectNameAlpha = shoutPNameAlpha;
break
}
var tempIcon: MovieClip = iconClip.duplicateMovieClip("tempIcon", this.getNextHighestDepth());
tempIcon.gotoAndStop(currIcon);
iconClip._alpha = 0;
iconClip.gotoAndStop(newIcon);
var tempPIcon: MovieClip = pIconClip.duplicateMovieClip("tempPIcon", this.getNextHighestDepth());
//var iconLTG: Object = {x:(iconClip._width * 0.5), y:(iconClip._height * 0.5)}
//iconClip.localToGlobal(iconLTG);
//var tempPIconLTG: Object = {x:(tempPIcon._width * 0.5), y:(tempPIcon._height * 0.5)}
//tempPIcon.localToGlobal(tempPIconLTG);
//pTargetX = ((iconLTG.x - tempPIconLTG.x) * (iconClip_mc._xscale / pIconClip_mc._xscale));
//skyui.util.Debug.log("iconLTG.x: " + iconLTG.x + ", iconLTG.y: " + iconLTG.y + "tempPIconLTG.x: " + tempPIconLTG.x + ", tempPIconLTG.y: " + tempPIconLTG.y + ", pTargetX: " + pTargetX)
tempPIcon._xscale = pIconClip_mc._xscale;
tempPIcon._yscale = pIconClip_mc._yscale;
tempPIcon.gotoAndStop(currPIcon);
pIconClip._alpha = 0;
pIconClip._xscale = 25;
pIconClip._yscale = 25;
pIconClip.gotoAndStop(newPIcon);
var tl = new TimelineLite({paused:true, autoRemoveChildren:true, onComplete:equipPreselectedItemComplete});
tl.to(itemName_mc, 0.3, {_alpha:0, ease:Quad.easeOut}, 0)
.to(preselectName_mc, 0.3, {_alpha:0, ease:Quad.easeOut}, 0)
.call(updateNamesForEquipPreselect, [iSlot, newName, newPName, this])
.to(tempIcon, 0.6, {_x:targetX, _y:((tempIcon._height) / 2), _rotation:"+=90", _alpha:0, _xscale:25, _yscale:25, ease:Quad.easeOut}, 0);
.to(tempPIcon, 0.6, {_x:pTargetX, _y:pTargetY, _alpha:iconAlpha, _xscale:pIconTargetScale, _yscale:pIconTargetScale, ease:Quad.easeOut}, 0)
.to(iconClip, 0, {_alpha:iconAlpha, ease:Linear.easeNone})
.to(tempPIcon, 0, {_alpha:0, ease:Linear.easeNone})
.to(pIconClip, 0.4, {_alpha:pIconAlpha, _xscale:pIconScale, _yscale:pIconScale, ease:Elastic.easeOut}, 0.5)
.to(itemName_mc, 0.3, {_alpha:itemNameAlpha, ease:Quad.easeOut}, 0.6)
.to(preselectName_mc, 0.3, {_alpha:preselectNameAlpha, ease:Quad.easeOut}, 0.6)
tl.play();
}
I have also uploaded it to Pastebin HERE
The straightforward Icon A X value + Global X value difference which should work results in this:
And the issue is worse the greater the distance between the two icons is to start with. If I edit the starting position of Icon A to be much further away this is the result:
From those two examples the logged values and calculations are:
[20:12:47.970] leftIconLTG - x: 149.49916992187, y: 581.28598632812
[20:12:47.970] leftPreselectIconLTG - x: 94.587438964844, y: 577.68461914063
[20:12:47.970] leftTargetX: 39.15, leftPTargetX: 54.911730957031
[20:12:47.970] leftPTargetY: 3.6013671874999
[20:13:18.510] leftIconLTG - x: 149.49916992187, y: 581.28598632812
[20:13:18.510] leftPreselectIconLTG - x: 594.56030273438, y: 577.68461914063
[20:13:18.510] leftTargetX: -58.55, leftPTargetX: -445.0611328125
[20:13:18.510] leftPTargetY: 3.6013671874999
So as you can see the target leftIcon global (LTG) x is 149.5, and in the first screenshot the leftPreselectIcon starts at a global x of 94.6. leftPTargetX contains the difference calculated correctly at 54.9. So moving leftPreselectIcon from it's local starting x of 0 to 54.9 should in theory move it into the correct position.
So what am I doing wrong here? As you can see from the commented out code I have made several other attempts including adding half/full icon widths to the calculation, and even testing whether the difference in scale has anything to do with it by multiplying the global x difference value by the scale factor going from icon A scale to icon B scale using the on screen heights for the calculation. But none of them get me close.
Solved
The solution was to create 'store' objects for each set of icons, and then call localToGlobal on the target icon, then globalToLocal on the icon to be moved, both calls on the same object:
var leftPIconTarget:Object = {x:0, y:0};
leftIcon.localToGlobal(leftPIconTarget);
leftPreselectIcon.globalToLocal(leftPIconTarget);
leftPIconTarget now contains the target x and y co-ordinates for the tween on leftPreselectIcon, and continues to work no matter where on the screen I move the starting positions to. The only wierdness is that I have to make the right x negative or it goes in the wrong direction, which makes no sense at all, because if I move the left icon way over to the right so it has to animate right to left I don't have to make it negative. Go figure! Anyway, it works, and that's all I'm bothered about!