если устроит не совсем элипс, а скорее овал из кривых, то с помощью безьевых утилит Дембицкого можно
Код AS3:
package
{
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Bezier;
import flash.geom.Point;
public class Main extends Sprite
{
private var ball:Circle = new Circle(30);
private var segments:Array = [];
private var cX:Number = 300;
private var cY:Number = 300;
private var rX:Number = 200;
private var rY:Number = 100;
private var mX:Number;
private var mY:Number;
public function Main():void
{
ball.x = cX;
ball.y = cY;
addChild(ball);
graphics.lineStyle(2);
// типа 'элипс' из четырех безье
for (var i:int = 0; i < 4; i++)
{
var a:Number = Math.PI * i / 2;
var sP:Point = new Point(cX + Math.cos(a) * rX, cY + Math.sin(a) * rY);
a += 0.5 * Math.PI;
var eP:Point = new Point(cX + Math.cos(a) * rX, cY + Math.sin(a) * rY);
var cP:Point = i % 2 ? new Point(eP.x, sP.y) : new Point(sP.x, eP.y);
var segm:Bezier = new Bezier(sP, cP, eP);
segments.push(segm);
if (!i) graphics.moveTo(sP.x, sP.y);
graphics..curveTo(cP.x, cP.y, eP.x, eP.y);
}
ball.addEventListener(MouseEvent.MOUSE_DOWN, ball_mouseDown);
}
private function ball_mouseDown(e:MouseEvent):void
{
mX = stage.mouseX;
mY = stage.mouseY;
stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMove);
}
private function stage_mouseUp(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, stage_mouseUp);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMove);
}
private function stage_mouseMove(e:MouseEvent):void
{
// двигаем
ball.x += stage.mouseX - mX;
ball.y += stage.mouseY - mY;
mX = stage.mouseX;
mY = stage.mouseY;
// проверка и коррекция
var dir:Number = Math.PI + Math.atan2(cY - ball.y, cX - ball.x);
var segm:Bezier = segments[Math.floor(2 * dir / Math.PI) % 4];
var t:Number = segm.getClosest(new Point(ball.x, ball.y));
var tP:Point = segm.getPoint(t);
if (Point.distance(new Point(ball.x, ball.y), tP) < ball.radius)
{
dir = Math.atan2(tP.y - ball.y, tP.x - ball.x);
ball.x = tP.x - ball.radius * Math.cos(dir);
ball.y = tP.y - ball.radius * Math.sin(dir);
}
}
}
}
import flash.display.Sprite;
class Circle extends Sprite
{
public var radius:Number;
public function Circle(r:Number)
{
super();
radius = r;
graphics.beginFill(0x808080);
graphics.drawCircle(0, 0, r);
}
}
Добавлено через 35 минут
а можно и не связываться с безье, а строить просто отрезками и брать ближайший по наименьшему расстоянию, тогда и эллипс будет как эллипс
Код AS3:
package
{
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Point;
public class Main extends Sprite
{
private var ball:Circle = new Circle(30);
private var segments:Array = [];
private var cX:Number = 300;
private var cY:Number = 300;
private var rX:Number = 200;
private var rY:Number = 100;
private var mX:Number;
private var mY:Number;
public function Main():void
{
ball.x = cX;
ball.y = cY;
addChild(ball);
graphics.lineStyle(2);
// элипс из отрезков
var n:Number = 60;
var dA:Number = 2 * Math.PI / n;
var a:Number = 0;
for (var i:int = 0; i < n; i++)
{
var sP:Point = new Point(cX + Math.cos(a) * rX, cY + Math.sin(a) * rY);
a += dA;
var eP:Point = new Point(cX + Math.cos(a) * rX, cY + Math.sin(a) * rY);
var mid:Point = Point.interpolate(sP, eP, 0.5);
segments.push(mid);
if (!i) graphics.moveTo(sP.x, sP.y);
graphics.lineTo(eP.x, eP.y);
}
ball.addEventListener(MouseEvent.MOUSE_DOWN, ball_mouseDown);
}
private function ball_mouseDown(e:MouseEvent):void
{
mX = stage.mouseX;
mY = stage.mouseY;
stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMove);
}
private function stage_mouseUp(e:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, stage_mouseUp);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMove);
}
private function stage_mouseMove(e:MouseEvent):void
{
// двигаем
ball.x += stage.mouseX - mX;
ball.y += stage.mouseY - mY;
mX = stage.mouseX;
mY = stage.mouseY;
// проверка и коррекция
var tP:Point;
var min:Number = Number.MAX_VALUE;
for (var i:int = 0; i < segments.length; i++)
{
var d:Number = Point.distance(new Point(ball.x, ball.y), segments[i]);
if ( d< min)
{
tP = segments[i];
min = d;
}
}
var dir:Number = Math.PI + Math.atan2(cY - ball.y, cX - ball.x);
if (Point.distance(new Point(ball.x, ball.y), tP) < ball.radius)
{
dir = Math.atan2(tP.y - ball.y, tP.x - ball.x);
ball.x = tP.x - ball.radius * Math.cos(dir);
ball.y = tP.y - ball.radius * Math.sin(dir);
}
}
}
}
import flash.display.Sprite;
class Circle extends Sprite
{
public var radius:Number;
public function Circle(r:Number)
{
super();
radius = r;
graphics.beginFill(0x808080);
graphics.drawCircle(0, 0, r);
}
}
|