【问题标题】:AS3 Constrain Object while Zooming/Panning with GestureEvent / MouseEvent使用 GestureEvent / MouseEvent 缩放/平移时 AS3 约束对象
【发布时间】:2015-05-13 17:32:18
【问题描述】:

我想要做的是让我的 MovieClip(比视口大)的边框不可见。就像许多应用程序一样,例如部落冲突。

这样,如果您放大、缩小或平移,您将永远看不到它下面的舞台。

如果我只是平移而不是缩放,那会很容易,因为我只需要计算我的 MC 矩形是否在我的舞台内,如果是,我会:

mc.x = 0 + mc.width / 2;
//or
mc.x = stage.StageWidth - (mc.width/2);
//or .... The same for y

现在最大的问题是当我也缩放时!每次我想出一些代码时,它都不能很好地工作。网上有很多通过GestureEvent 进行缩放的示例,但没有一个可以限制 MC,因此您看不到它下面的舞台。

谁能给我一个例子。假设舞台是 480x720,mc 是 1080x720!

你必须在始终覆盖舞台的同时进行平移和缩放,并且mc的比例将保持在1-1.5之间。


这是我当前的代码:

Multitouch.inputMode = MultitouchInputMode.GESTURE;
stage.addEventListener(TransformGestureEvent.GESTURE_PAN, onPan);
stage.addEventListener(MouseEvent.CLICK, gotoBox);

var isInBox: Boolean = false;
table.x = 203.1;
table.y = 360;
table.scaleX = 1;
table.scaleY = 1;

var mouseTimer: Timer;

function onPan(event: TransformGestureEvent): void
{
    if (!isInBox)
    {
        if (event.phase == GesturePhase.BEGIN)
        {
        stage.removeEventListener(MouseEvent.CLICK, gotoBox);
        trace("noClick");
        }

        table.x += event.offsetX;
        table.y += event.offsetY;
        if (table.x > (table.width / 2))
        {
        table.x = table.width / 2;
        }
        if (table.x < stage.stageWidth - (table.width / 2))
        {
            table.x = stage.stageWidth - (table.width / 2)
        }
        if (table.y > (table.height / 2))
        {
            table.y = table.height / 2;
        }
        if (table.y < stage.stageHeight - (table.height / 2))
        {
            table.y = stage.stageHeight - (table.height / 2)
        }

        if (event.phase == GesturePhase.END)
        {
            if (mouseTimer !== null)
            {
                if (mouseTimer.running)
                {
                    mouseTimer.stop();
                    mouseTimer.removeEventListener(TimerEvent.TIMER, enableClick);
                }
            }
            mouseTimer = new Timer(250);
            mouseTimer.addEventListener(TimerEvent.TIMER, enableClick);
            mouseTimer.start();
            trace("start");
        }
    }
}
function enableClick(e: TimerEvent)
{
    mouseTimer.stop();
    trace("stop");
    mouseTimer.removeEventListener(TimerEvent.TIMER, enableClick);
    stage.addEventListener(MouseEvent.CLICK, gotoBox);
    trace("nowClick");
}
function gotoBox(e: MouseEvent)
{
// here it goes to another frame
}

我无法添加缩放功能,因为它完全是一场灾难;我在这个链接 FlashAndMath 中使用了类似于函数onZoom 的东西

因为我需要放大和缩小一个点,这是主要问题,因为我必须移动我的 mc 以使该点位于中心,而我必须移动它来制作我的整个 MC在一定的范围内覆盖舞台!这些运动也相互对抗。如果最后一部分不清楚,请让我解释更多:)

在得到 LDMS 的正确答案后,我更新了这个问题以避免聊天讨论:)

【问题讨论】:

  • 如果您显示当前的缩放/平移代码,我将根据这些代码给您一个示例。这是很常见的情况。
  • 我会把它放在这里,但在我只想说之前我在手机上问这个问题之前已经犯了一些错误,比如我没有写的“约束”这个词它必须是一个单词建议,也是以小写开头的“StageWidth”:)
  • 当你说更新我不明白你的意思时,我可以编辑、发送评论并回答我的 Q,所以我做了第三个。对不起。并感谢您多次帮助我;)
  • #LDMS 它的鼠标点击
  • 好的,您可能会做的是在捕获阶段收听并停止在您的子鼠标点击中传播事件。我不确定这会如何影响客人(我几乎从未使用过客人,而且我不确定取消鼠标按下事件是否会阻止客人发送。我明天会玩弄它以找出答案.

标签: actionscript-3 flash zooming gesture pan


【解决方案1】:

您只需在移动或缩放对象时检查以确保它没有超出范围。

因此,如果您创建了一个名为 forceBounds 的函数,只需在缩放或更改 x/y 时调用它:

        function forceBounds():void {
            //figure out the bounds to constrain to
            //the x, should be the farthest left it can go without the edge being seen on the right. To get this value just subtract the smaller width (stage) from the larger width (mc) - this should be a negative number
            var bounds:Rectangle = (stage.stageWidth - mc.width, stage.stageHeight - mc.height, mc.width - stage.stageWidth, mc.height - stage.stageHeight);

            if (mc.x > bounds.x + bounds.width) {
                mc.x = bounds.x + bounds.width;
            }
            else if (mc.x < bounds.x) {
                mc.x= bounds.x;
            }

            if (mc.y > bounds.y + bounds.height) {
                mc.y = bounds.y + bounds.height;
            }
            else if (mc.y < bounds.y) {
                mc.y = bounds.y;
            }
        }

这是我在 FlashPro 中制作的完整示例:(舞台上有一个对象,其实例名称为 mc,大于舞台边界。

缩放代码取自FlashAndMath.com

import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
import flash.events.TransformGestureEvent;
import fl.motion.MatrixTransformer;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.events.GesturePhase;

Multitouch.inputMode = MultitouchInputMode.GESTURE;
stage.addEventListener(TransformGestureEvent.GESTURE_PAN, onPan);
stage.addEventListener(TransformGestureEvent.GESTURE_ZOOM, onZoom);

forceBounds();

function onPan(e:TransformGestureEvent):void {
    trace("PAN");
    if(e.phase == GesturePhase.BEGIN){
        stage.removeEventListener(TransformGestureEvent.GESTURE_ZOOM, onZoom);
    }

    //localToGlobal is a helper method that converts a point to global coordinates
    var p:Point = DisplayObject(e.target).localToGlobal(new Point(e.offsetX, e.offsetY));
    //conversely, global to local does the opposite
    p = mc.globalToLocal(p);

    mc.x = p.x;
    mc.y = p.y;

    forceBounds();

    if(e.phase == GesturePhase.END){
        stage.addEventListener(TransformGestureEvent.GESTURE_ZOOM, onZoom);
    }
}

function onZoom(event:TransformGestureEvent):void {
    trace("ZOOM");
    var container:MovieClip = mc;
    var locX:Number=event.localX;
    var locY:Number=event.localY;
    var stX:Number=event.stageX;
    var stY:Number=event.stageY;
    var prevScale:Number=container.scaleX;
    var mat:Matrix;
    var externalPoint=new Point(stX,stY);
    var internalPoint=new Point(locX,locY);

    container.scaleX *= (event.scaleX + event.scaleY) * .5;

    if(event.scaleX > 1 && container.scaleX > 6){
        container.scaleX=prevScale;
    }
    if(event.scaleY > 1 && container.scaleY > 6){
        container.scaleX=prevScale;
    }
    if(event.scaleX < 1 && container.scaleX < 0.8){
        container.scaleX=prevScale;
    }
    if(event.scaleY < 1 && container.scaleY < 0.8){
        container.scaleX=prevScale;
    }

    if(container.scaleX < 1) container.scaleX = 1;
    if(container.scaleX > 1.5) container.scaleX = 1.5;
    container.scaleY = container.scaleX;

    mat=container.transform.matrix.clone();
    MatrixTransformer.matchInternalPointWithExternal(mat,internalPoint,externalPoint);
    container.transform.matrix=mat;

    forceBounds();
}

function forceBounds():void {
    //figure out the bounds to constrain to
    //the x, should be the farthest left it can go without the edge being seen on the right. To get this value just subtract the smaller width (stage) from the larger width (mc) - this should be a negative number
    var bounds:Rectangle = new Rectangle(stage.stageWidth - mc.width, stage.stageHeight - mc.height, mc.width - stage.stageWidth, mc.height - stage.stageHeight);

    if (mc.x > bounds.x + bounds.width) {
        mc.x = bounds.x + bounds.width;
    }
    else if (mc.x < bounds.x) {
        mc.x= bounds.x;
    }

    if (mc.y > bounds.y + bounds.height) {
        mc.y = bounds.y + bounds.height;
    }
    else if (mc.y < bounds.y) {
        mc.y = bounds.y;
    }
}

【讨论】:

  • 谢谢,这个代码对我有用,因为我的 mc 的方向点在中心。但现在我面临另一个问题,因为我在我们正在使用的主 mc 中有其他电影剪辑,当我放大这些电影剪辑时,结果很奇怪,我认为它来自: var locX:Number=event.localX; var locY:Number=event.localY;如果您认为我是对的,请告诉我如何从我的主 mc 而不是其中的那些值获取这些值。
  • 我才意识到这种奇怪的事情不仅发生在我手指下还有一个 mc 的时候,而且当我的两根手指之间有一个甚至没有被触摸时也会发生!
  • 您可能应该使用mc.mouseChildren = false,如果您需要子级来调度鼠标事件,那么您需要将event.scaleXevent.offsetX/Y 转换为相对于父级(@987654329 @) 而不是调度事件的孩子。
  • 我在 onPan 和 onZoom 的第一行添加了 mc.mouseChildren = false ,但除非这些函数至少被调用一次,否则它不会有帮助。因为第一次改变 onPan 和 onZoom 被称为我的 mc.children 仍然受到鼠标的影响,所以它已经晚了。我平移或缩放您的想法的第二次以上效果很好。
  • 因为我需要再次重新启用这些 mouseChildren(即使通过 TimerEvent 延迟),所以总是会在这些 mouseChildren 设置为 true 的情况下第一次运行 onZoom 和 onPan!
猜你喜欢
  • 2019-04-02
  • 1970-01-01
  • 2018-01-04
  • 1970-01-01
  • 2019-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-15
相关资源
最近更新 更多