2011-06-28 28 views
5

... tốt, đến một vòng tròn không đầy đủ.Constrain MovieClip kéo đến vòng tròn

Tôi có một thanh trượt kéo trông như thế này: Arc Slider

Thanh màu xanh có tên ví dụ track và dấu chấm màu hồng có tên ví dụ puck.

Tôi cần puck bị ràng buộc trong khu vực màu xanh bất cứ lúc nào, và đây là nơi mà toán học của tôi thất bại làm việc chống lại tôi! Cho đến nay tôi đã puck di chuyển dọc theo trục x chỉ như thế này:

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

suy nghĩ của tôi hiện là tôi có thể sử dụng bán kính của vòng tròn đầy đủ (50) và mouseX so với phía trên cùng của vòng cung để tính toán một tam giác, và từ đó tôi có thể tính toán vị trí y yêu cầu. Vấn đề là, tôi đang đọc các trang lượng lượng giác khác nhau và vẫn không biết bắt đầu từ đâu. Ai đó có thể giải thích những gì tôi cần làm như thể nói chuyện với một đứa trẻ?

Chỉnh sửa: Thực tế là vòng tròn bị hỏng không phải là vấn đề, tôi có thể giới hạn chuyển động đến một số độ nhất định theo từng hướng một cách dễ dàng, nó nhận được độ ở nơi đầu tiên mà tôi có thể ' Tôi quay đầu lại!

Edit2: Tôi đang cố gắng làm theo câu trả lời của Bosworth99, và đây là chức năng tôi đã đi lên với tính một radian để đưa vào chức năng của mình:

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

Tôi chắc rằng ai đó có kiến ​​thức toán học mạnh sẽ cung cấp cho bạn câu trả lời hay. Chỉ muốn chỉ ra rằng trong hầu như tất cả các trường hợp khi tôi cần phải làm việc với một cái gì đó vòng tròn như tôi sử dụng y = sin (x) + cos (x); http://www.ies.co.jp/math/java/trig/graphSinCosX/graphSinCosX.html –

+0

Đó là loại liên kết tôi đã xem. Hình ảnh động vòng tròn khá dường như làm tôi bối rối! – shanethehat

Trả lời

6

Như tôi đã nhìn thấy nó, vấn đề bạn giải quyết là tìm điểm gần nhất trên vòng tròn. Google có rất nhiều đề xuất về chủ đề này.

Bạn có thể tối ưu hóa nó bằng cách đầu tiên phát hiện một góc giữa vị trí chuột và trung tâm vòng tròn. Sử dụng Math.atan2() cho điều đó. Nếu góc nằm trong khoảng cách, chỉ cần chọn điểm cuối gần nhất: trái hoặc phải.

EDIT1 Đây là ví dụ hoàn chỉnh về chiến lược này.

Hy vọng điều đó sẽ hữu ích.

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 Một số liên kết

Dưới đây là một số vấn đề phổ biến giải thích và giải quyết một cách rực rỡ rõ ràng và súc tích: http://paulbourke.net/geometry/ tài nguyên này đã giúp tôi một ngày rất nhiều trước đây.

Intersection của một dòng và một vòng tròn là một chút của một quá mức cần thiết ở đây, nhưng ở đây nó là: http://paulbourke.net/geometry/sphereline/

+0

Xin lỗi, tôi có một bộ não khủng khiếp cho loại toán học này và bạn đã mất tôi. Khi tìm ra góc đầu tiên, tôi có thể sử dụng khoảng cách trục x từ đỉnh của vòng cung đến mouseX và tâm vòng tròn, nhưng điểm thứ ba có phải là đỉnh của cung tròn không? – shanethehat

+0

Ok, tôi đã chỉnh sửa ở trên với một ví dụ hoàn chỉnh. Chỉ cần sao chép và dán nó vào khung trong tài liệu mới của Flash IDE. –

+0

Wow, đó là một câu trả lời rất lớn. Tôi sẽ nghiên cứu điều này; nó chắc chắn dường như làm chính xác những gì tôi cần trong IDE và chuyển nó vào thành phần của tôi nên nằm trong khả năng của tôi. Cảm ơn rất nhiều. – shanethehat

0

Something như thế này nên làm việc ra:

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

Rõ ràng, sửa đổi khi cần thiết, nhưng bạn chỉ cần gửi vào một điểm trung tâm, bán kính và sau đó là một radian (bạn có thể có được với angle * (Math.PI/180)). Bạn có thể dễ dàng mã cứng trong hai tham số đầu tiên nếu chúng không thay đổi. Điều gì thay đổi là radian, và đó là những gì bạn sẽ cần phải thay đổi theo thời gian, khi chuột của bạn đang kéo (được xác định bởi khoảng cách mouseX đến điểm trung tâm - dương hoặc âm).

Hy vọng rằng sẽ giúp bạn bắt đầu -

cập nhật

Đây là cách tôi đã làm việc này ra - tho một lỗi chút của nó, trong đó các puck reset về 0 độ khi trình tự khởi động. Điều đó đang được nói, tôi chỉ thấy điều đó - @Nox có quyền này. Tôi sẽ đăng những gì tôi đã đến lúc sử dụng chức năng projectLocation của tôi anyways;)

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

    } 

} 

Sự khác biệt chính là tôi lấy góc qua chuyển động ngang (x) và không kiểm tra góc của con trỏ. Thos, bẫy các giá trị bằng tay cảm thấy kinda hacky so với @Nox rất tốt soution. Sẽ về dọn dẹp tôi đã tiếp tục đi;)

đẹp câu hỏi - Chúc mừng

+0

Điều đó đã giúp ích rất nhiều, trong khi tôi có di chuyển của tôi trong một vòng tròn. Thật không may đó là một vòng tròn lớn hơn nhiều mà tôi muốn, và tôi nghi ngờ đó là để làm với tính toán của tôi cho tài sản radian. Tôi sẽ thêm hàm tôi đã viết cho câu hỏi khi định dạng nhận xét kém. – shanethehat

1

Thay vì cố gắng để di chuyển điểm dọc theo con đường một phần của vòng tròn, tại sao không giả nó và sử dụng một núm/quay số? Làm cho nó trông giống như dấu chấm đang di chuyển dọc theo con đường.

Sau đó, chỉ cần đặt vòng quay của núm:

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; 

Bạn có thể kiểm tra điều này bằng cách ném nó trong một sự kiện enter frame, nhưng rõ ràng bạn sẽ muốn đặt một số logic trong để kiểm soát cách núm bắt đầu di chuyển và khi nào nên dừng lại.

+0

Đây là suy nghĩ đầu tiên của tôi, nhưng đồ họa đã hoàn thành có nhiều bóng và vát trên chúng mà không được xoay nên tôi quyết định cắn viên đạn và dựa vào trí tuệ tập thể của SO! – shanethehat

+0

"Bản nhạc" mà các dấu chấm trượt trên có thể nằm dưới chính núm. Các núm có thể bao gồm không có gì khác hơn là dấu chấm. Nó không nên cản trở thiết kế nào cả. Nếu dấu chấm có các kiểu đặc biệt được áp dụng cho nó mà không được xoay thì bạn phải xoay ngược dấu chấm, làm giảm sự đơn giản của câu trả lời này và mã bạn phải viết. –

+0

Thực ra, đó cũng là suy nghĩ đầu tiên của tôi.Bạn có thể xoay một cái gì đó và có được vị trí của núm trong không gian tọa độ khác với localToGlobal() và globalToLocal(). Hoặc bạn có thể xoay thùng chứa của núm trong khi xoay núm xoay theo hướng ngược lại. Tuy nhiên, toán học được sử dụng để tính toán đúng vị trí không phải là tất cả những gì phức tạp. Và một giải pháp được tách ra từ bất kỳ thủ thuật cụ thể flash là sở thích của tôi, khi nó không làm tổn thương bạn trong bất kỳ cách nào. Nghe có vẻ "tinh khiết" với tôi. :) –

1

100% mã hoạt động.

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