Frage

I know it's simple to animate the amount of any given filter, but lets say you have a filter on a specific region(Rectangle) of the stage. How would you animate(tween) the position of this filtered area so that the effect moves on the stage?

War es hilfreich?

Lösung

One way to achieve the effect that comes to mind is to draw the contents of the stage to a BitmapData and then use BitmapData.applyFilter(). applyFilter() lets you specify a sourceRect and a destPoint. So in your case you can animate the properties of sourceRect. destPoint's x and y should be the same as sourceRect's x and y in this case.

Here's a working example:

package {
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    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 {
            removeEventListener(Event.ADDED_TO_STAGE, init);

            var bitmapData : BitmapData = new BitmapData(this.stage.stageWidth, this.stage.stageHeight);
            var sourceRectVelocity : Point = new Point(3, 2);
            var sourceRect : Rectangle = new Rectangle(50, 100, 200, 150);
            var bitmap : Bitmap = new Bitmap(bitmapData);

            // draw some random circles on the stage
            for (var i:int = 0; i < 100; i++) {
                this.graphics.beginFill((Math.floor(Math.random()*255) << 16) + (Math.floor(Math.random()*255) << 8) + Math.floor(Math.random()*255), 1);
                this.graphics.drawCircle(Math.random()*this.stage.stageWidth, Math.random()*this.stage.stageHeight, 50 + Math.random()*50);
            }

            this.addChild(bitmap);

            this.addEventListener(Event.ENTER_FRAME, function(event : Event):void {
                sourceRect.x = Math.min(Math.max(sourceRect.x + sourceRectVelocity.x, 0), bitmapData.width - sourceRect.width);
                sourceRect.y = Math.min(Math.max(sourceRect.y + sourceRectVelocity.y, 0), bitmapData.height - sourceRect.height);

                if (sourceRect.right >= bitmapData.width) {
                    sourceRectVelocity.x = -Math.abs(sourceRectVelocity.x);
                } else if (sourceRect.left <= 0) {
                    sourceRectVelocity.x = Math.abs(sourceRectVelocity.x);
                }

                if (sourceRect.bottom >= bitmapData.height) {
                    sourceRectVelocity.y = -Math.abs(sourceRectVelocity.y);
                } else if (sourceRect.top <= 0) {
                    sourceRectVelocity.y = Math.abs(sourceRectVelocity.y);
                }

                // clear the bitmap with white (not needed if the stage doesn't have any transparency)
                bitmapData.fillRect(bitmapData.rect, 0xffffff);

                // draw the stage to the bitmapData, but make sure the Bitmap display object showing the BitmapData isn't visible
                bitmap.visible = false;
                bitmapData.draw(stage);
                bitmap.visible = true;

                // apply greyscale filter
                bitmapData.applyFilter(bitmapData, sourceRect, new Point(sourceRect.x, sourceRect.y), new ColorMatrixFilter([0.3, 0.59, 0.11, 0, 0,0.3, 0.59, 0.11, 0, 0,0.3, 0.59, 0.11, 0, 0,0, 0, 0, 1, 0]));
            });
        }
    }
}

This example draws the whole stage to a BitmapData but then only apply the filter to a region. A more optimized approach (especially if the region never/rarely change size) is to only draw the region you want to filter to a BitmapData with the size of the region and then apply the filter to the whole BitmapData.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top