Actionscript 3 将MovieClip拖动约束为圆形

Actionscript 3 将MovieClip拖动约束为圆形,actionscript-3,trigonometry,Actionscript 3,Trigonometry,…好吧,一个不完整的圆圈 我有一个可拖动的滑块,如下所示: 蓝色条有实例名轨迹,粉红色点有实例名冰球 我需要冰球在任何时候都被限制在蓝色区域内,这就是我数学失败的原因!到目前为止,我只让冰球沿着x轴这样移动: private function init():void { zeroPoint = track.x + (track.width/2); puck.x = zeroPoint-(puck.width/2); puck.buttonMode = true;

…好吧,一个不完整的圆圈

我有一个可拖动的滑块,如下所示:

蓝色条有实例名
轨迹
,粉红色点有实例名
冰球

我需要冰球在任何时候都被限制在蓝色区域内,这就是我数学失败的原因!到目前为止,我只让冰球沿着x轴这样移动:

private function init():void
{
    zeroPoint = track.x + (track.width/2);
    puck.x = zeroPoint-(puck.width/2);
    puck.buttonMode = true;
    puck.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown);
}

private function onMouseDown(evt:MouseEvent):void
{
    this.stage.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
    this.stage.addEventListener(MouseEvent.MOUSE_UP,onMouseUp);
}

private function onMouseUp(evt:MouseEvent):void
{
    this.stage.removeEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
}

private function onMouseMove(evt:MouseEvent):void
{
    puck.x = mouseX-(puck.width/2);
    //need to plot puck.y using trig magic...
}
我目前的想法是,我可以使用不完整圆(50)的半径和相对于圆弧顶部的鼠标来计算三角形,从那里我可以计算出所需的y位置。问题是,我正在阅读各种各样的三角学网站,但仍然不知道从哪里开始。有人能解释一下我需要做什么,就像对一个孩子说话一样吗

编辑:圆圈被打破的事实不应该是个问题,我可以很容易地将每个方向的移动限制到一定数量的角度,它首先得到的是我无法理解的角度

Edit2:我试图按照Bosworth99的答案,这是我提出的计算弧度的函数,将弧度放入他的函数中:

private function getRadian():Number
{
    var a:Number = mouseX - zeroPoint;
    var b:Number = 50;
    var c:Number = Math.sqrt((a^2)+(b^2));
    return c;
}

在我看来,你要解决的问题是找到圆上最近的点。谷歌在这个问题上有很多建议

您可以通过首先检测鼠标位置和圆心之间的角度来优化它。使用Math.atan2()实现此目的。如果角度在间隙范围内,只需选择最近的端点:左或右

EDIT1以下是此策略的完整示例

希望有帮助

import flash.geom.Point;
import flash.events.Event;
import flash.display.Sprite;

var center:Point = new Point(200, 200);
var radius:uint = 100;

var degreesToRad:Number = Math.PI/180;

// gap angles. degrees are used here just for the sake of simplicity.
// what we use here are stage angles, not the trigonometric ones.
var gapFrom:Number = 45; // degrees
var gapTo:Number = 135; // degrees

// calculate endpoints only once

var endPointFrom:Point = new Point();
endPointFrom.x = center.x+Math.cos(gapFrom*degreesToRad)*radius;
endPointFrom.y = center.y+Math.sin(gapFrom*degreesToRad)*radius;

var endPointTo:Point = new Point();
endPointTo.x = center.x+Math.cos(gapTo*degreesToRad)*radius;
endPointTo.y = center.y+Math.sin(gapTo*degreesToRad)*radius;

// just some drawing
graphics.beginFill(0);
graphics.drawCircle(center.x, center.y, radius);
graphics.moveTo(center.x, center.y);
graphics.lineTo(endPointFrom.x, endPointFrom.y);
graphics.lineTo(endPointTo.x, endPointTo.y);
graphics.lineTo(center.x, center.y);
graphics.endFill();

// something to mark the closest point
var marker:Sprite = new Sprite();
marker.graphics.lineStyle(20, 0xFF0000);
marker.graphics.lineTo(0, 1);
addChild(marker);

var onEnterFrame:Function = function (event:Event) : void
{
    // circle intersection goes here
    var mx:int = stage.mouseX;
    var my:int = stage.mouseY;

    var angle:Number = Math.atan2(center.y-my, center.x-mx);
    // NOTE: in flash rotation is increasing clockwise, 
    // while in trigonometry angles increase counter clockwise
    // so we handle this difference
    angle += Math.PI;

    // calculate the stage angle in degrees
    var clientAngle:Number = angle/Math.PI*180

    // check if we are in a gap
    if (clientAngle >= gapFrom && clientAngle <= gapTo) {
        // we are in a gap, no sines or cosines needed
        if (clientAngle-gapFrom < (gapTo-gapFrom)/2) {        
            marker.x = endPointFrom.x;
            marker.y = endPointFrom.y;
        } else {
            marker.x = endPointTo.x;
            marker.y = endPointTo.y;
        }
        // we are done here
        return;
    }

    // we are not in a gp, calculate closest position on a circle
    marker.x = center.x + Math.cos(angle)*radius;
    marker.y = center.y + Math.sin(angle)*radius;
}
addEventListener(Event.ENTER_FRAME, onEnterFrame);
导入flash.geom.Point;
导入flash.events.Event;
导入flash.display.Sprite;
变量中心:点=新点(200200);
var半径:uint=100;
变量degreesToRad:Number=Math.PI/180;
//间隙角。这里使用度只是为了简单。
//我们这里用的是阶段角,不是三角角。
变量gapFrom:Number=45;//度
变量gapTo:Number=135;//度
//只计算一次端点
var endPointFrom:Point=新点();
endPointFrom.x=中心.x+数学cos(间隙*度*半径)*半径;
endPointFrom.y=中心.y+数学sin(间隙from*degreesToRad)*半径;
var endPointTo:Point=新点();
endPointTo.x=中心点x+数学坐标(gapTo*degreesToRad)*半径;
endPointTo.y=中心.y+数学sin(gapTo*degreesToRad)*半径;
//只是一些画
图形填充(0);
图形绘制圆(中心x,中心y,半径);
图形移动到(center.x,center.y);
graphics.lineTo(endPointFrom.x,endPointFrom.y);
graphics.lineTo(endPointTo.x,endPointTo.y);
图形.lineTo(center.x,center.y);
graphics.endFill();
//标记最近点的东西
变量标记:Sprite=新Sprite();
marker.graphics.lineStyle(20,0xFF0000);
marker.graphics.lineTo(0,1);
addChild(标记);
var onEnterFrame:Function=Function(事件:事件):void
{
//圆形交叉点在这里
var mx:int=stage.mouseX;
var my:int=stage.mouseY;
变量角度:数字=数学atan2(center.y-my,center.x-mx);
//注:在闪光灯中,旋转是顺时针增加的,
//而在三角中,角度逆时针增加
//所以我们处理这个差异
角度+=Math.PI;
//以度为单位计算工作台角度
var clientring:Number=angle/Math.PI*180
//检查我们是否有差距

如果(clientring>=gapFrom&&clientring这样的事情应该解决:

private function projectLocation(center:point, radius:uint, radian:Number):Point 
    {
        var result:Point = new Point();

        //obtain X
        result.x = center.x + radius * Math.cos(radian));

        //obtain Y
        result.y = center.y + radius * Math.sin(radian));

        return result;
    }
显然,可以根据需要进行修改,但只需输入圆心、半径和弧度(可以通过
angle*(Math.PI/180)
获得)。如果前两个参数不变,则可以轻松地硬编码。改变的是弧度,这是随着时间的推移,鼠标拖动时需要改变的(由鼠标到中心点的距离定义-正或负)

希望这能帮助你开始-

更新

这就是我解决这个问题的方法——虽然有点麻烦,因为当序列开始时,冰球会重置为0度。尽管如此,我只是看到-@Nox做对了。无论如何,我会用我的projectLocation函数发布我得到的结果;)

package com.b99.testBed.knob
{
导入com.b99.testBed.Main;
导入flash.display.Sprite;
导入flash.events.Event;
导入flash.events.MouseEvent;
导入flash.geom.Point;
/**
* ...
*@author bosworth99
*/
公共类旋钮扩展雪碧
{
私人冰球:雪碧;
私人变轨:雪碧;
私人建筑直径:uint=100;
私人建筑半径:uint=直径/2;
公共功能旋钮()
{
超级();
init();
}
私有函数init():void
{
assembleDisplayObjects();
addEventHandlers();
}
私有函数assembleDisplayObjects():void
{
_轨迹=新精灵();
带(_轨道)
{
图形填充(0xffffff,1);
图形.线型(0x000000);
图形学.抽屉直径(-RADIUS,-RADIUS,DIAMETER,DIAMETER);
graphics.endFill();
}
this.addChild(_track);
_track.x=Main.stage.stageWidth/2;
_track.y=Main.stage.stageHeight/2;
_冰球=新精灵();
有(_puck)
{
graphics.beginll(0x2DFE07,1);
图形学.抽屉(-8,-8,16,16);
graphics.endFill();
x=_track.x;
y=_track.y-_track.width/2;
buttonMode=true;
}
这个.addChild(_puck);
}
私有函数addEventHandlers():void
{
Main.stage.addEventListener(MouseEvent.MOUSE_向下,激活);
主舞台
package com.b99.testBed.knob 
{
    import com.b99.testBed.Main;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;

    /**
     * ...
     * @author bosworth99
     */
    public class Knob extends Sprite
    {

        private var _puck       :Sprite;
        private var _track      :Sprite;
        private const DIAMETER  :uint = 100;
        private const RADIUS    :uint = DIAMETER / 2;

        public function Knob() 
        {
            super();
            init();
        }

        private function init():void
        {
            assembleDisplayObjects();
            addEventHandlers();
        }

        private function assembleDisplayObjects():void
        {
            _track = new Sprite();
            with (_track) 
            {
                graphics.beginFill(0xffffff, 1);
                graphics.lineStyle(1, 0x000000);
                graphics.drawEllipse(-RADIUS, -RADIUS, DIAMETER, DIAMETER);
                graphics.endFill();
            }
            this.addChild(_track);
            _track.x = Main.stage.stageWidth / 2;
            _track.y = Main.stage.stageHeight / 2;

            _puck = new Sprite();
            with (_puck) 
            {
                graphics.beginFill(0x2DFE07, 1);
                graphics.drawEllipse(-8, -8, 16, 16);
                graphics.endFill();
                x   = _track.x;
                y   = _track.y - _track.width / 2;
                buttonMode = true;
            }
            this.addChild(_puck);
        }

        private function addEventHandlers():void
        {
            Main.stage.addEventListener(MouseEvent.MOUSE_DOWN, activate);
            Main.stage.addEventListener(MouseEvent.MOUSE_UP, deactivate);
        }

        private function deactivate(e:MouseEvent):void 
        {
            Main.stage.removeEventListener(MouseEvent.MOUSE_MOVE, update);
        }

        private var _origin:uint;
        private function activate(e:MouseEvent):void 
        {
            Main.stage.addEventListener(MouseEvent.MOUSE_MOVE, update);
            _origin = mouseX;
        }

        private function update(e:MouseEvent):void 
        {
            var distance:Number;
            (mouseX < _origin)? distance = -(_origin - mouseX) : distance = mouseX - _origin;
            if(distance > 40){distance = 40};
            if(distance < -220){distance = -220};

            var angle:Number  = distance;  //modify?
            var radian:Number = angle * (Math.PI / 180);
            var center:Point  = new Point(_track.x, _track.y);
            var loc:Point     = projectLocation(center, RADIUS, radian);

            _puck.x = loc.x;
            _puck.y = loc.y;
        }

        private function projectLocation(center:Point, radius:uint, radian:Number):Point 
        {
            var result:Point = new Point();

            //obtain X
            result.x = center.x + radius * Math.cos(radian);

            //obtain Y
            result.y = center.y + radius * Math.sin(radian);

            return result;
        }

    }

}
var deg:Number = Math.atan2(stage.mouseY - knob.y,stage.mouseX - knob.x) / (Math.PI/180);
// code to put upper/lower bounds on degrees    
knob.rotation = deg;
enter code here

const length:int = 100;

var dragging:Boolean = false;
var tx:int;
var ty:int;



var p1:Sprite = new Sprite();
var p2:Sprite = new Sprite();

p1.graphics.beginFill(0);
p1.graphics.drawCircle(0, 0, 10);
p1.graphics.endFill();

p2.graphics.copyFrom(p1.graphics);

p1.x = stage.stageWidth / 2;
p1.y = stage.stageHeight / 2;

p2.x = p1.x + length;
p2.y = p1.y;

addChild(p1);
addChild(p2);

p2.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);

function mouseDown(event:MouseEvent):void
{
    dragging = true;
}

function mouseUp(event:MouseEvent):void
{
    dragging = false;
}

function mouseMove(event:MouseEvent):void
{
if (dragging)
{
    tx = event.stageX - p1.x;
    ty = event.stageY - p1.y;
    if (tx * tx + ty * ty > length * length)
    {
        p2.x = p1.x + tx / Math.sqrt(tx * tx + ty * ty) * length;
        p2.y = p1.y + ty / Math.sqrt(tx * tx + ty * ty) * length;
    }
    else
    {
        p2.x = event.stageX;
        p2.y = event.stageY;
    }
}
}