开发者

Best method to scale DropShadows in AS3?

开发者 https://www.devze.com 2022-12-11 02:03 出处:网络
I\'m creating a flash application that makes use 开发者_StackOverflowof both the dropShadow filter and scaling of various sprites.

I'm creating a flash application that makes use 开发者_StackOverflowof both the dropShadow filter and scaling of various sprites.

And therein lies the problem:

This filter supports Stage scaling. However, it does not support general scaling, rotation, and skewing. If the object itself is scaled (if scaleX and scaleY are set to a value other than 1.0), the filter is not scaled.

By happenstance the lack of rotation support is beneficial to me, but I really badly need the scaling to work. What's the best method for doing this?

Can I extend the DropShadow object and "make it" update?

Shall I make my own custom object that just recreates itself with a new .distance value to match the zoom level?

What's the best method to use (with performance in mind)?


With performance in mind, you can make use of a Bitmap and draw the original sized container with its DropShadowFilter onto it. This way, the filter will scale and Flash won't even have to recalculate the rendering of the drop shadow.

Example:

// We need to use this container as the source for the Bitmap.
var sample:Sprite = new Sprite();


// Sample object with DropShadowFilter applied.
var rect:Sprite = new Sprite();
rect.x = rect.y = 10;
rect.graphics.beginFill(0xCC0000);
rect.graphics.drawRect(0, 0, 50, 50);
rect.graphics.endFill();
rect.filters = [new DropShadowFilter()];
sample.addChild(rect);


// Create our Bitmap.
var bitmap:Bitmap = new Bitmap();

bitmap.x = bitmap.y = 100;
bitmap.bitmapData = new BitmapData(sample.width + 20, sample.height + 20, true);
bitmap.bitmapData.draw(sample);
bitmap.scaleX = bitmap.scaleY = 0.5;

addChild(bitmap);


Since a filter doesn't scale, its parameter values must always correspond to pixel units. Therefore, you simply have to scale the filter values the same as the object. To do so, just translate a unit vector (length==1) in the objects's coordinate system to the global coordinate system and the distance will be your global scaling factor for the object's filters.

Every time your object moves or scales, alter any filter values that should scale and reapply the filters. Here is an example document class showing a square with glow and drop shadow filters scaling with it while it's nested in another container that's scaled as well. I also added a stage resize listener to keep the square in the center of the stage.

Paste this into the actions on the main timeline of a new document and run it. Notice that the drop shadow's distance and size scale, and the glow filter's blur scales as well. You could even add the math to account for rotation when you have different x and y blur values.

import flash.display.Sprite;
import flash.filters.GlowFilter;
import flash.events.Event;
import flash.display.StageScaleMode;
import flash.utils.getTimer;
import flash.geom.Point;
import flash.filters.DropShadowFilter;

//Fix the scale of the stage
stage.scaleMode = flash.display.StageScaleMode.NO_SCALE;
stage.frameRate = 60;

//Create a small green square centered at the origin
var r:Sprite = new Sprite();
r.graphics.beginFill( 0x00ff00 );
r.graphics.drawRect( -5, -5, 10, 10 );
r.graphics.endFill();

//Nest it in a container
var container:Sprite = new Sprite();
container.addChild( r )
addChild( container );

//Apply a glow filter
var GLOW_BLUR:Number = 10;
var SHADOW_DIST:Number = 5;
var SHADOW_BLUR:Number = 2;
var dropshadow:DropShadowFilter = new DropShadowFilter( SHADOW_DIST, 45, 0, 1, SHADOW_BLUR, SHADOW_BLUR, 1, 3 ); //new GlowFilter( 0x000000, 0.5, GLOW_BLUR, GLOW_BLUR, 2, 3 );
var glow:GlowFilter = new GlowFilter( 0x0000ff, 1, GLOW_BLUR, GLOW_BLUR, 1, 3 ); //new GlowFilter( 0x000000, 0.5, GLOW_BLUR, GLOW_BLUR, 2, 3 );
r.filters = [glow,dropshadow];

addEventListener( Event.ENTER_FRAME, enterFrame, false, 0, true );
addEventListener( Event.RESIZE, stageResized, false, 0, true );
var t:int = getTimer();
stageResized( null );
function enterFrame( e:Event ):void
{
    var cycle_length:Number = 2000;
    var cycle:Number = (((getTimer() - t) % cycle_length) / cycle_length) * Math.PI * 2.0;
    var scale:Number = 2 + Math.sin( cycle );
    r.scaleX = r.scaleY = scale;
    container.scaleX = container.scaleY = scale * 2;
    container.rotation = cycle / (Math.PI / 180);

    var p0:Point = new Point( 0, 0 );
    var p1:Point = new Point( 1, 0 );
    p0 = r.localToGlobal( p0 );
    p1 = r.localToGlobal( p1 );
    var globalScale:Number = Point.distance( p0, p1 );

    dropshadow.blurX = dropshadow.blurY = SHADOW_BLUR * globalScale;
    dropshadow.distance = SHADOW_DIST * globalScale;
    glow.blurX = glow.blurY = GLOW_BLUR * globalScale;
    r.filters = [glow,dropshadow];
}
function stageResized( e:Event ):void
{
    container.x = (stage.stageWidth / 2);
    container.y = (stage.stageHeight / 2);
}


I am using dropShadow filter like this and scale, rotate, skew works fine:

var localFilters :Array = new Array();
localFilters.push( dropShadowFilter );

component.filters = localFilters;

after that if you do for example :

var m:Matrix = new Matrix();
m.scale( 1.5, 2 );

component.transform.matrix = m;

the dropShadow filter will be scaled.

0

精彩评论

暂无评论...
验证码 换一张
取 消