Constrain MovieClip drag to circle

... well, to an incomplete circle.

I have a draggable slider that looks like this: Arc slider

The blue bar has an instance name track, and the pink dot has an instance name puck.

I need the puck to be limited in the blue area at all times, and this is where my math failures work against me! So far I have a washer moving along the x axis only like this:

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...
}

My thinking at the moment is that I can use the radius of the incomplete circle (50) and mouseX relative to the vertex of the arc to calculate the triangle, and from there I can calculate the required position y. The problem is that I am reading various trigonometry sites and still do not know where to start. Can someone explain what I need to do if you are talking with a child?

: , , , , !

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;
}
+5
4

, , , - . Google .

, . 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);

EDIT2

, : http://paulbourke.net/geometry/ .

, : http://paulbourke.net/geometry/sphereline/

+6

, , /? , .

:

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;

, , , , , , , .

+1

100% .

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;
    }
}
}
+1

- :

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 
{
    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;
        }

    }

}

, (x), . Thos, , @Nox soution. , ;)

-

0

All Articles