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