蛇线的徒手绘画课

时间:2013-09-13 19:16:45

标签: actionscript-3

我正在寻找建立一个绘图应用程序,并且能够做常规线和虚线,但我想要一条“波浪”线也被称为蛇线。有关如何在AS3中实现此目的的任何想法?

更新:回复的代码确实回答了这个问题,但是希望更加自由的蛇,所以在鼠标移动时它可以画下面的东西(尽管它不需要通过波浪的线)。

enter image description here

1 个答案:

答案 0 :(得分:1)

您可以使用beizer曲线进行操作,但最简单的方法可能是绘制线段。这是一个有效的例子:

package 
{
    import flash.display.*;
    import flash.events.Event;
    import flash.geom.*;

    public class Main extends Sprite {

        public function Main():void {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event = null):void {
            this.graphics.lineStyle(2, 0x0, 0.5);

            // step = 1 creates a high-quality wave
            drawSerpentLine(this.graphics, new Point(50, 50), new Point(150, 250), 4, 20, 1);

            // step = 8 and the wave is not as smooth
            drawSerpentLine(this.graphics, new Point(300, 30), new Point(233, 150), 6, 10, 8);
        }

        // takes a graphics reference, and draws a serpent line between the two
        // specified points using the g's current lineStyle
        // frequency: determines how many waves 
        // amplitude: how "much" wave 
        // step: the quality (lower means smoother lines at the cost of speed)
        private function drawSerpentLine(g : Graphics, from : Point, to : Point, frequency : int = 5, amplitude : int = 20, step : int = 2):void {
            // the angle between the two points
            var ang : Number = Math.atan2(to.y - from.y, to.x - from.x);

            // the distance between the points
            var dis : Number = Point.distance(from, to);

            // a point which we use to store the current position to draw
            var currPoint : Point = new Point(from.x, from.y);

            for (var i:int = 0; i <= dis; i += step) {
                // how far away (perpendicularly) from the straight lines the current points should be
                var waveOffsetLength : Number = Math.sin((i / dis) * Math.PI * frequency) * amplitude;

                // calculate the current point. 
                currPoint.x = from.x + Math.cos(ang) * i + Math.cos(ang - Math.PI/2)*waveOffsetLength;
                currPoint.y = from.y + Math.sin(ang) * i + Math.sin(ang - Math.PI/2)*waveOffsetLength;

                if (i > 0) {
                    this.graphics.lineTo(currPoint.x, currPoint.y);
                } else {
                    this.graphics.moveTo(currPoint.x, currPoint.y);
                }
            }

            // close the last line so we end up at the end point
            this.graphics.lineTo(to.x, to.y);
        }
    }
}

<强>更新

这是一个自由绘制的修改版本。方法类似:每次鼠标移动我们在两点之间画蛇。但是蛇的“阶段”需要存储在一个变量中,以便不同的drawSerpentLine()调用在最后一个调用阶段继续。此外,我们不能只在最后一个鼠标坐标和当前鼠标坐标之间绘制蛇,因为这不会创建平滑的外观。所以我们平均坐标。

package 
{
    import flash.display.*;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.*;

    public class Main extends Sprite {

        private var m_mouseIsDown : Boolean;
        private var m_lastPoint : Point = new Point();
        private var m_currPoint : Point = new Point();
        private var m_phase : Number = 0;

        private var m_firstDrawAfterMouseDown : Boolean;

        public function Main():void {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event = null):void {
            this.graphics.lineStyle(2, 0x0, 0.5);

            this.stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseEvent);
            this.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseEvent);
            this.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseEvent);
        }

        private function drawSerpentLine(g : Graphics, from : Point, to : Point, frequency : Number = 0.15, amplitude : int = 6, step : int = 1):void {
            // the angle between the two points
            var ang : Number = Math.atan2(to.y - from.y, to.x - from.x);

            // the distance between the points
            var dis : Number = Point.distance(from, to);

            for (var i:int = 0; i <= dis; i += step) {
                m_phase += frequency;

                // how far away (perpendicularly) from the straight lines the current points should be
                var waveOffsetLength : Number = Math.sin(m_phase) * amplitude;

                // calculate the current point. 
                var x : Number = from.x + Math.cos(ang) * i + Math.cos(ang - Math.PI/2)*waveOffsetLength;
                var y : Number = from.y + Math.sin(ang) * i + Math.sin(ang - Math.PI/2)*waveOffsetLength;

                if (m_firstDrawAfterMouseDown) {
                    this.graphics.moveTo(x, y);
                    m_firstDrawAfterMouseDown = false;
                } else {
                    this.graphics.lineTo(x, y);
                }
            }
        }

        private function onMouseEvent(event : MouseEvent):void {
            switch(event.type) {
                case MouseEvent.MOUSE_DOWN:
                    m_mouseIsDown = m_firstDrawAfterMouseDown = true;
                    m_currPoint.x = m_lastPoint.x = this.mouseX;
                    m_currPoint.y = m_lastPoint.y = this.mouseY;
                    break;
                case MouseEvent.MOUSE_MOVE:
                    if (m_mouseIsDown) {
                        // to create a smoother look  we average the mouse coords
                        // where only 10% of the new mouse position is used, 90% is the old position
                        // the lower the first percentage the smoother the look, but the more
                        // the serpent will lag behind the actual mouse position (until you release the mouse)
                        m_currPoint.x = this.mouseX * 0.1 + m_lastPoint.x * 0.9;
                        m_currPoint.y = this.mouseY * 0.1 + m_lastPoint.y * 0.9;

                        drawSerpentLine(this.graphics, m_lastPoint, m_currPoint);

                        m_lastPoint.x = m_currPoint.x;
                        m_lastPoint.y = m_currPoint.y;
                    }
                    break;
                case MouseEvent.MOUSE_UP:
                    m_mouseIsDown = false;

                    // when the user releases, we complete the serpent
                    // by drawing the full distance to the current position
                    // (no percentages like in mouse move)
                    m_currPoint.x = this.mouseX;
                    m_currPoint.y = this.mouseY;
                    drawSerpentLine(this.graphics, m_lastPoint, m_currPoint);
                    break;
            }
        }
    }
}