工作中遇到几个组件开发的功能:1、沿一条纵向的线段拖动,2、沿一条横向的线段拖动,3、沿圆形的轨迹拖动。
想了想,其实可以归为一类问题,分两步实现。
第一步,实现自由拖拽;
第二步,约束到指定的轨迹上。
有点类似于物理引擎里边的约束。
实现起来并不难,先看效果:
代码如下:
package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
public class Main extends MovieClip{
public var mc1: MovieClip;
public var mc2: MovieClip;
public var mc3: MovieClip;
private var constraintV: VerticalLineConstraint = new VerticalLineConstraint(new Point(100, 100), 200);
private var constraintH: HorizontalLineConstraint = new HorizontalLineConstraint(new Point(200, 100), 200);
private var constraintC: CircleConstraint = new CircleConstraint(new Point(300, 250), 100, 0, 360);
public function Main() {
// constructor code
stage?initStage(null):addEventListener(Event.ADDED_TO_STAGE, initStage);
}
private function initStage(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, initStage);
drag(mc1);
drag(mc2);
drag(mc3);
var p1: Point = constraintV.getPercentP(0);
mc1.x = p1.x;
mc1.y = p1.y;
mc1.mouseChildren = false;
var p2: Point = constraintH.getPercentP(0);
mc2.x = p2.x;
mc2.y = p2.y;
mc2.mouseChildren = false;
var p3: Point = constraintC.getPercentP(0);
mc3.x = p3.x;
mc3.y = p3.y;
mc3.mouseChildren = false;
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
private function enterFrameHandler(e:Event):void
{
updateMc(mc1, constraintV);
updateMc(mc2, constraintH);
updateMc(mc3, constraintC);
}
private function updateMc(mc: MovieClip, constraint: IConstraint):void {
var p: Point = constraint.getConstraintP(new Point(mc.x, mc.y));
mc.x = p.x;
mc.y = p.y;
mc.tf.text = Math.floor(constraint.getPercent(p) * 100) + "%";
}
//-----------------------------
private var curSp:Sprite;
private var draged:Boolean = false;
private function drag(sp:Sprite):void
{
sp.buttonMode = true;
sp.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
}
private function mouseDownHandler(e:MouseEvent):void
{
curSp = e.currentTarget as Sprite;
curSp.startDrag();
addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
stage.addEventListener(Event.MOUSE_LEAVE, mouseUpHandler);
}
private function mouseUpHandler(e:MouseEvent):void
{
curSp.stopDrag();
curSp = null;
removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
stage.removeEventListener(Event.MOUSE_LEAVE, mouseUpHandler);
}
private function mouseMoveHandler(e:MouseEvent):void
{
//
draged = true;
}
}
}
import flash.geom.Point;
interface IConstraint{
function getPercentP(per: Number):Point;
function getConstraintP(p: Point):Point;
function getPercent(p: Point):Number;
}
class VerticalLineConstraint implements IConstraint{
public var p0: Point;
public var length: Number;
public function VerticalLineConstraint(p0: Point, length: Number){
this.p0 = p0;
this.length = length;
}
public function getPercentP(per: Number):Point{
return new Point(p0.x, p0.y + length * per);
}
public function getConstraintP(p: Point):Point{
p = p.clone();
p.y = Utils.limitAB(p.y, p0.y, p0.y + length);
p.x = p0.x;
return p;
}
public function getPercent(p: Point):Number{
return (p.y - p0.y) / length;
}
}
class HorizontalLineConstraint implements IConstraint{
public var p0: Point;
public var length: Number;
public function HorizontalLineConstraint(p0: Point, length: Number){
this.p0 = p0;
this.length = length;
}
public function getPercentP(per: Number):Point{
return new Point(p0.x + length * per, p0.y);
}
public function getConstraintP(p: Point):Point{
p = p.clone();
p.x = Utils.limitAB(p.x, p0.x, p0.x + length);
p.y = p0.y;
return p;
}
public function getPercent(p: Point):Number{
return (p.x - p0.x) / length;
}
}
class CircleConstraint implements IConstraint{
public var p0: Point;
public var r: Number;
public var ang0: Number;
public var ang1: Number;
public function CircleConstraint(p0: Point, r: Number, ang0: Number, ang1: Number){
this.p0 = p0;
this.r = r;
this.ang0 = ang0;
this.ang1 = ang1;
}
public function getPercentP(per: Number):Point{
var ang: Number = Utils.ang2rad(per * (ang1 - ang0) + ang0);
return getAngP(ang);
}
public function getConstraintP(p: Point):Point{
var per: Number = getPercent(p);
per = Utils.limitAB(per, 0, 1);
return getPercentP(per);
}
public function getPercent(p: Point):Number{
var ang: Number = Utils.rad2ang(Math.atan2(p.y - p0.y, p.x - p0.x));
if (ang < 0){
ang += 360;
}
return (ang - ang0) / (ang1 - ang0);
}
private function getAngP(ang:Number):Point{
return new Point(p0.x + r * Math.cos(ang), p0.y + r * Math.sin(ang));
}
}
class Utils{
public static function limitAB(x: Number, a:Number, b: Number):Number{
if (a > b){
var t: Number = a;
a = b;
b = t;
}
if (x < a){
return a;
}
if (x > b){
return b;
}
return x;
}
public static function ang2rad(ang: Number): Number{
return ang * Math.PI / 180;
}
public static function rad2ang(rad: Number): Number{
return rad * 180 / Math.PI;
}
}其中getConstraintP方法可以由另外两个方法组合得到。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。