1

I'm trying to find a good way to use TweenMax and flash's drawing class together, but it always bogs down and crashes the flash player, and I can't really figure out what's going wrong. Really all I want to do is make sure that when two (or more) circles, connected by a line, move, that the line between them follows. This is my code:

import com.greensock.TweenMax;

var sw = stage.stageWidth;
var sh = stage.stageHeight;
var cr = 3; //circle radius
var moveRange = 20;
var circleColor = 0xcccccc;
var numCircles = 2;
var circleArray = [];
var lineCanvas:Sprite = new Sprite();
addChild(lineCanvas);
var lineColor = 0xe9e9e9;
var lineWeight = 1;

function init(){
    drawCircle();
}

function drawCircle(){
    for (var i = 0; i<numCircles; i++){
        var xPos = randomRange(cr, sw-cr);
        var yPos = randomRange(cr, sh-cr);
        var newCircle:Shape = new Shape();
        newCircle.graphics.beginFill(circleColor);
        newCircle.graphics.drawCircle(0,0,cr);
        newCircle.x = xPos;
        newCircle.y = yPos;
        newCircle.graphics.endFill();
        circleArray.push(newCircle);
        addChild(newCircle);
    }
    drawLine();
}

function drawLine(){
    for (var i = 0; i<numCircles-1; i++){
        lineCanvas.graphics.clear();
        lineCanvas.graphics.lineStyle(lineWeight,lineColor);
        lineCanvas.graphics.moveTo(circleArray[i].x,circleArray[i].y);
        lineCanvas.graphics.lineTo(circleArray[i+1].x,circleArray[i+1].y);
    }
    moveCircle();
}

function moveCircle(){
    for (var i = 0; i<numCircles; i++){
        var curX = circleArray[i].x;
        var curY = circleArray[i].y;
        var moveX = randomRange(curX-moveRange,curX+moveRange);
        var moveY = randomRange(curY-moveRange,curY+moveRange);
        //TweenMax.to(circleArray[i],.5, { x: moveX, y: moveY, onUpdate:drawLine });
    }
}

function randomRange(minNum:Number, maxNum:Number):Number {  
    return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);  
}

init();

Is there a better way to do this? Should I not be using a tweening library?

mheavers
  • 29,530
  • 58
  • 194
  • 315

2 Answers2

3

Assuming you uncomment that TweenMax line, the function drawLine() calls moveCircle()... which is adding a tween for each circle, that will call drawLine() again - and everything repeats. I guess it's adding tons* of listeners and tweens, resulting in a crash. You should add a check, that prevents the other tweens from being added, while there is a tween still running for that circle.

Also, lineCanvas.graphics.clear(); should be moved before the loop, otherwise it would clear lines drawn for the other circles, if there are any.

Tweening libraries are good, you should use one if you can. They help very much even with simple tweening task.


Edit:
* I like numbers. Assuming a frame rate of 24 frames per second, you really get quite a lot tweens there. Growing exponential. 1 tween when initializing, 2 tweens in the first frame, 4 in the second, and so on. When the first tween finishes (if it were doing so before the crash) you'd have a nice number of 2^24-1 tweens running. 16777215 tweens. For each circle.

But seriously now, to fix this, you could use TweenMax.isTweening(circleArray[i]) to check if there is already a tween running. I think drawLine shouldn't call moveCircle. The function moveCircle should now only be called once, to start the tween - or if you want it to loop, every time a tween is complete (onComplete).

kapex
  • 28,903
  • 6
  • 107
  • 121
  • Thanks for pointing out the issue with drawLine calling moveCircle - I didn't realize the loop that was creating.. – mheavers Nov 27 '11 at 15:16
1

because mheavers asked me, i put together a little example using an ENTER_FRAME listener to animate the circles manually.

i got two classes:

package
{
    import flash.filters.BlurFilter;
    import flash.events.Event;
    import flash.display.Sprite;

    [SWF(backgroundColor="#000000", frameRate="60", width="960", height="600")]
    public class Main extends Sprite
    {
        private var numCircles:int = 2;
        private var circles:Vector.<Circle>;
        private var lineCanvas:Sprite;
        private var lineColor:uint = 0xe9e9e9;
        private var lineWeight:int = 1;
        private var blur:BlurFilter;

        public function Main()
        {
            init();
        }

        private function init():void
        {
            circles = new Vector.<Circle>();
            blur = new BlurFilter();

            lineCanvas = new Sprite();
            addChild(lineCanvas);

            drawCircle();

            addEventListener(Event.ENTER_FRAME, onEnterFrame);
        }

        private function drawCircle():void
        {
            for (var i:int = 0; i < numCircles; i++)
            {
                var newCircle:Circle = new Circle();
                circles.push(newCircle);
                addChild(newCircle);
            }
            drawLine();
        }

        private function drawLine():void
        {
            var circle:Circle;
            var nextCircle:Circle;
            for (var i:int = 0; i < circles.length-1; i++)
            {
                circle = circles[i];
                nextCircle = circles[i+1];

                //lineCanvas.graphics.clear();
                lineCanvas.graphics.lineStyle(lineWeight, lineColor);
                lineCanvas.graphics.moveTo(circle.x, circle.y);
                lineCanvas.graphics.lineTo(nextCircle.x, nextCircle.y);
            }
        }

        private function onEnterFrame(event:Event):void
        {
            // update circles
            var circle:Circle;
            for (var i:int = 0, len:int = circles.length; i < len; i++)
            {
                circle = circles[i];
                circle.move();
            }

            drawLine();
        }
    }
}

and another one for the circle:

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

    public class Circle extends Shape
    {
        public var targetx:Number;
        public var targety:Number;

        private var circleColor:uint = 0xcccccc;
        private var cr:int = 3;
        private var moveRange:int = 150;

        public function Circle()
        {
            graphics.beginFill(circleColor);
            graphics.drawCircle(0, 0, cr);
            graphics.endFill();

            addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
        }

        public function move():void
        {
            var absx:Number = Math.abs(targetx-x);
            var absy:Number = Math.abs(targety-y);

            if (absx < 1 && absy < 1)
            {
                targetx = randomRange(x - moveRange, x + moveRange);
                targety = randomRange(y - moveRange, y + moveRange);

                if (targetx >= stage.stageWidth)
                {
                    targetx = stage.stageWidth - moveRange;
                }
                else if (targetx <= 0)
                {
                    targetx = moveRange;
                }

                if (targety >= stage.stageHeight)
                {
                    targety = stage.stageHeight - moveRange;
                }
                else if (targety <= 0)
                {
                    targety = moveRange;
                }
            }
            else
            {
                x += (targetx - x) * 0.125;
                y += (targety - y) * 0.125;
            }
        }


        private function onAddedToStage(event:Event):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);

            // position circle on stage
            x = targetx = randomRange(cr, stage.stageWidth - cr);
            y = targety = randomRange(cr, stage.stageHeight - cr);
        }

        private function randomRange(minNum:Number, maxNum:Number):Number
        {
            return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
        }
    }
}

looks sth like this:

example

Philipp Kyeck
  • 18,402
  • 15
  • 86
  • 123
  • Thanks - this looks awesome - I tried to use your class but I'm getting errors with the lines that reference - I've never seen that sort of notation before. I made sure to add import Circle; but it didn't seem to help. – mheavers Nov 27 '11 at 03:29
  • `Vector.` means a type of Array but it can only contain Circle Objects. so when you retrieve objects from the "array"/vector you can be sure that they are `Circle`s and you don't have to cast them. and it's faster than the usual `Array` it's a flashplayer 10 feature. if you're still using fp9 you can change this to Array. – Philipp Kyeck Nov 27 '11 at 08:37