夏休みにはじめて触ったActionScript3.0。回転式のつまみを作ってみました。

できあがったものは、どうってことはないです。

フレームアクション

フィルターをActionScriptで掛けるとソースが長くなるので、Flashのワークスペースでフィルターもろもろ全部かけたMovieClipを作ってそれをクラスに割り当てました。

つまみ本体、つまみ内の発光部分、液晶表示部分のMovieClipをそれぞれ作成して、コンストラクタに渡します。

//つまみ本体
var rd = new RotationDial(dial_mc);
//つまみ本体に発光部分を追加
rd.addIndicator(dial_mc.indicator_mc);
//液晶部分
var digit = new Digit(digit_mc);
//液晶部分につまみ本体を追加
digit.addProvider(rd);

RotationDial.as

つまみ本体。

AS3では表示オブジェクトがEventDispatcherクラスを継承しているので、MovieClipクラスを継承させてEventDispatcherを使えるようにします。AS2ではMovieClipのイベントハンドラに無名関数をかましたりしていましたが、AS3ではMovieClipにaddEventListnerできるので1行で済む。これは楽チン。

AS2ではどこからでもStageにアクセスできたが、AS3ではMovieClipやSpriteのstageプロパティにアクセスすることになっている。スコープを逆にさかのぼるみたいでちょっと気持ち悪い。

package
{
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;

    public class RotationDial extends MovieClip
    {
        private var mc:MovieClip;
        private var indicator:Indicator;
        private var angle:Number;
        private var O:Point;
        private var P:Point;

        function RotationDial(_mc:MovieClip)
        {
            mc = _mc;
            mc.addEventListener(MouseEvent.MOUSE_DOWN, onStartDrag);
            mc.stage.addEventListener(MouseEvent.MOUSE_UP, onStopDrag);
            mc.rotation += 90;
            angle = mc.rotation;
            O = new Point(mc.x, mc.y);
        }
        public function addIndicator(_mc):void
        {
            indicator = new Indicator(_mc);
        }
        public function get _rotation():Number
        {
            return angle;
        }
        private function onStartDrag(e:Event):void
        {
            mc.addEventListener(Event.ENTER_FRAME, onDrag);
            dispatchEvent(new Event("onStartDrag"));
            indicator.light();
        }
        private function onStopDrag(e:Event):void
        {
            mc.removeEventListener(Event.ENTER_FRAME, onDrag);
            dispatchEvent(new Event("onStopDrag"));
            indicator.die();
        }
        private function onDrag(e:Event):void
        {
            P = new Point(O.x-this.mouseX, O.y-this.mouseY);
            angle = Math.atan2(P.y, P.x)*180/Math.PI;
            mc.rotation = angle;
            dispatchEvent(new Event("onDrag"));
        }
    }
}

Indicator.as

つまみ内の発光部分。無くてもいいぐらいの感じですが。light関数でフィルターかけて光っている感じを出したり、拡張できるように。

package
{
    import flash.display.MovieClip;
    import flash.geom.ColorTransform;

    public class Indicator
    {
        private var mc:MovieClip;
        private var def_c:uint = 0x333333;
        private var light_c:uint = 0xff0000;

        function Indicator(_mc)
        {
            mc = _mc;
            coloring(def_c);
        }
        public function light():void
        {
            coloring(light_c);
        }
        public function die():void
        {
            coloring(def_c);
        }
        private function coloring(_c):void
        {
            var ct:ColorTransform;
            ct = new ColorTransform();
            ct.color = _c;
            mc.transform.colorTransform = ct;
        }
    }
}

Digit.as

にせ液晶表示部分。カスタムイベントonDragイベントを受け取って角度を表示します。

package
{
    import flash.display.MovieClip;
    import flash.events.Event;

    public class Digit
    {
        private var rd:RotationDial;
        private var mc:MovieClip;
        private var digit:Number;

        function Digit(_mc)
        {
            mc = _mc;
        }
        public function addProvider(_rd:RotationDial)
        {
            rd = _rd;
            rd.addEventListener("onDrag", onChange);
        }
        private function onChange(e:Event):void
        {
            show(e.target._rotation);
        }
        private function show(_angle:Number):void
        {
            if(-180<=_angle&&_angle<90)
            {
                digit = 270+_angle;
            } else {
                digit = _angle-90;
            }
            mc.digit_txt.text = Math.floor(digit);
        }
    }
}