Flash AS3 - 如何在缩放后围绕点居中对象

时间:2011-10-27 07:46:48

标签: flash actionscript-3 scale

我创建了一个mc,它可以作为我的地图和控件使用,可以移动地图并将关键点导航到并以不同的缩放级别放大。

我正在使用scaleX和scaleY缩放地图mc以及x和y位置列表,以便为每个关键点正确定位地图。

当我想去某个区域时,我执行此计算(offsetX和offsetY是屏幕的中心):

newX = posX * scale + offsetX;
newY = posY * scale + offsetY;

然后我补间地图的位置和比例以平滑地缩放并将地图移动到正确的位置:

var tween = new TweenLite(_background, EASING_SPEED, {x:newX, y:newY,scaleX:scale.getScale(),scaleY:scale,ease:EASING_TYPE,onComplete:moveToComplete,onCompleteParams:[room]});

我现在需要实现放大/缩小功能,这正是我所挣扎的。缩放应该使用屏幕的中心作为比例的注册点,所以我一直在尝试沿着以下的方向进行正确的定位:

var newX = offsetX - (offsetX - _background.x) * scale;
var newY = offsetY - (offsetY - _background.y) * scale;

所以在我的脑海中,这将获得距离地图当前位置相对于屏幕中心点(offsetX,offsetY)的距离,然后按照新比例缩放该距离。

然而,这显然是错误的,因为它不起作用并且地图的定位是错误的。

我也尝试使用变换矩阵来获得正确的值,但我对它们的了解甚至更少,而且得不到正确的结果。

function scale(target:MovieClip, center:Point, scale:Number):Point {
    var m:Matrix = new Matrix();
    m.translate(-center.x, -center.y);//move the center into (0,0)
    m.scale(scale, scale);//scale relatively to (0,0) (which is where our center is now)
    m.translate(center.x, center.y);//move the center back to its original position
    return m.transformPoint(new Point());//transform (0,0) using the whole transformation matrix to calculate the destination of the upper left corner
}

如果有人可以了解我出错的地方,我会非常感激!

4 个答案:

答案 0 :(得分:4)

function scaleAroundPoint (object:DisplayObject, offsetX:Number, offsetY:Number, absScaleX:Number, absScaleY:Number ):void {
    var relScaleX:Number = absScaleX / object.scaleX;
    var relScaleY:Number = absScaleY / object.scaleY;
    var AC:Point = new Point( offsetX, offsetY );
    AC = object.localToGlobal( AC );
    AC = object.parent.globalToLocal( AC );
    var AB:Point = new Point( object.x, object.y );
    var CB:Point = AB.subtract( AC );
    CB.x *= relScaleX;
    CB.y *= relScaleY;
    AB = AC.add( CB );
    object.scaleX *= relScaleX;
    object.scaleY *= relScaleY;
    object.x = AB.x;
    object.y = AB.y;
}

来自http://timwhitlock.info/blog/2008/04/13/scale-rotate-around-an-arbitrary-centre/

上述功能的用法示例:

var currentScale:Number = 1;
mc.addEventListener(MouseEvent.CLICK, onClick);

function onClick (e:MouseEvent):void {
    var point:Point = new Point(e.localX, e.localY);
    currentScale += .1;
    scaleAroundPoint(mc, point.x, point.y, currentScale, currentScale);
}

答案 1 :(得分:2)

我遇到了类似的问题,当我改变图像旋转时,我希望图像在图像中心旋转,而图像会围绕0点旋转。

在这两种情况下(你的和我的)有两种解决方法。
第一种方法是在缩放变化时用数学设置它。

var newX = stage.width/2 - _background.width/2
var newY = stage.height/2- _background.height/2

一旦加载的另一种方式将不需要额外的代码 在该动画片段中的_background中添加另一个movieClip图像将会去。 该图像的中心点位于0,0点,而不是图像的位置为0,0。 所以基本上

image.x = -(image.width/2)
image.y = -(image.height/2)

这将适用于以图像中心为中心的图像缩放和旋转。

[编辑]
好的,你需要做的就是开始一个新项目并创建类似这个图的东西 enter image description here

将图像放入容器动画片中 图像和容器将具有相同的高度和宽度
移动图像使其中心位于MovieClip的0,0点 把容器放在舞台上。 点击事件上的2个按钮添加.1另一个将.1减去容器上的刻度。
现在运行测试
如您所见,缩放以图像为中心 现在进行测试2打开容器并向左拖动图像 再次运行测试。
您会看到图像现在正在向中和向右缩放(与您拖动的位置相对)。

总而言之,偏移量是从图像中心开始的反向运动。(如果您理解那个,则为+ 2点)

image.x = -(image.width/2) - offsetX
image.y = -(image.height/2) - offsetY


注意:缩放将应用于容器而不是图像直接,因为图像移动仍将是image.x和image.y

答案 2 :(得分:1)

缩放对象时,焦点应保持相同的坐标。由于您正在缩放对象,因此您应该使用此点的坐标作为相对于地图大小的坐标。

由于该点保持在同一阶段位置,因此应该可以计算相对于该固定值的地图坐标。

//Pseudo Code
   // the point you want to zoom in
   // Record Mouse Click Coordinates , store in variable
   var origin:Point = new Point ( mouseX , mouseY );

   //calculate these coordinates as percentage of 
   //the map's width & height
    //store in variable 
    var percent:Object = { x% , y%}

   //during scaling, calculate the point's 
    //position using the "percent" values and
   //tween back to original ( var origin ) position 
好吧,我没有尝试,但这将是我的第一个方法:)

希望它有所帮助!

假设您的地图以1:1的比例为800x400。然后中心将在(400,200)。 如果你缩放地图,比方说1600x800,中心点将移动到(800,400)。然后,您需要补间地图以使该点回到(400,200),这将有效地给人以中心点保持原位的印象。

我给你的例子是基于这样的想法,例如,只要鼠标点击,“放大”点就会变化。如果不是,那么您只需将注册点移动到中心:)

答案 3 :(得分:0)

人们,我认为这只是一个数学问题。您可以在动画中同时进行缩放时更改x,y位置:

public function FadeInWithGrowth(_obj:*, _timeSec:Number=DEFAULT_TIMESEC_FADE_IN, _ease:Ease=null):void{
        var _endAlpha:int = _obj.alpha;
        var _startScaleX:int = _obj.scaleX/2;
        var _startScaleY:int = _obj.scaleY/2;
        var _endScaleX:int = _obj.scaleX;
        var _endScaleY:int = _obj.scaleY;
        var _startX:int = _obj.width/2 -(_startScaleX*_obj.width/2);
        var _startY:int = _obj.height/2 -(_startScaleY*_obj.height/2);
        var _endX:int = _obj.x;
        var _endY:int = _obj.y;
        _ease = _ease ? _ease : Back.easeOut;
        //Para que o scale ocorra centralizado e não a partir do topo
        TweenMax.fromTo(_obj, DEFAULT_TIMESEC_FADE_IN,
            {alpha:0, scaleX:_startScaleX, scaleY:_startScaleY, x:_startX, y:_startY},
            {alpha:_endAlpha, scaleX:_endScaleX, scaleY:_endScaleY, x:_endX, y:_endY, ease:_ease}
        );
    }