I've got movie clip on stage that has shadow filter.
When I apply ColorTransform to that movie clip, the shadow removes.
var ct:ColorTransform = new ColorTransform;
ct.color = 0x99CC00;
lamp.transform.colorTransform = ct;
How to save shadow?
The idea is to
save the filters (shadow) of your clip lamp,
apply the transformation,
put the clip in a master clip and
re-apply the filters to this untransformed parent.
code:
var lampFilters:Array = lamp.filters.slice(); //save filters
lamp.filters = []; //empty filters
var ct:ColorTransform = new ColorTransform();
ct.color = 0x99CC00;
lamp.transform.colorTransform = ct; //apply your transformation
var superLamp:Sprite = new Sprite();
superLamp.addChild(lamp); //nest the clip
addChild(superLamp);
superLamp.filters = lampFilters; //re-apply the filters
ColorTransform will transform the entire MovieClip, unfortunately, the filter is included. I suggest you layer lamp and apply the transform to the top most layer keeping the bottom layer (shadow) untouched.
Test example:
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x00FF00, 1);
ball.graphics.drawCircle(50, 50, 50);
ball.graphics.endFill();
ball.filters = [new DropShadowFilter()]; //default black
ball.addEventListener(MouseEvent.CLICK, changeColor);
addChild(ball);
//...
private function changeColor(evt:MouseEvent):void {
var ball:Sprite = evt.target as Sprite;
var ct:ColorTransform = new ColorTransform();
ct.color = 0x99CC00; // green-ish
ball.transform.colorTransform = ct;
ball.filters = [new DropShadowFilter(4, 45, 0xFFFFFF)]; //now white
}
Even with the shadow filter reapplied you can see it's still going to be green-ish as set by the transform.
You should use nested display objects to achieve this...
for instance you can create a movieclip within another movieclip. apply the colortransform to inner movie clip and apply the shadow to outer movie clip. works like a charm for me :)
Here is an alternate method that does not require a parent object. You basically use an AdjustColor and ColorMatrix to change the color instead of a ColorTransform.
Note:If you are using an IDE other than Flash, like Flex or FlashDevelop, you will need to include flash.swc into your library from 'Common/Configuration/ActionScript 3.0/libs/flash.swc' for the fl.motion.AdjustColor package/class. You can also Google the swc.
var mc:Sprite = new Sprite();
mc.graphics.beginFill(0xFF0000);
mc.graphics.drawCircle(100, 100, 100);
mc.graphics.endFill();
addChild(mc);
// White out the entire shape first
var whiteAC:AdjustColor = new AdjustColor();
whiteAC.brightness = 100;
whiteAC.contrast = 100;
whiteAC.saturation = -100;
whiteAC.hue = 0;
var whiteMatrix:Array = whiteAC.CalculateFinalFlatArray();
var whiteCMF:ColorMatrixFilter = new ColorMatrixFilter(whiteMatrix);
// Now use ColorMatrixFilter to change color
var colorMatrix:Array = hexToMatrix(0x0000FF);
var colorCMF:ColorMatrixFilter = new ColorMatrixFilter(colorMatrix);
// Create Drop Shadow
var myDropShadow:DropShadowFilter = new DropShadow();
mc.filters = [whiteCMF, colorCMF, myDropShadow];
function hexToMatrix ( hex:uint, alpha:Number = 1 )
{
var r:Number = ((hex & 0xFF0000) >> 16);
var g:Number = ((hex & 0x00FF00) >> 8);
var b:Number = ((hex & 0x0000FF));
var matrix:Array = [];
matrix = matrix.concat([r, 0, 0, 0, 0]); // red
matrix = matrix.concat([0, g, 0, 0, 0]); // green
matrix = matrix.concat([0, 0, b, 0, 0]); // blue
matrix = matrix.concat([0, 0, 0, alpha, 0]); // alpha
return matrix;
}
Related
I am trying to add to rectangles to the stage dynamically using action script 3. When I use the code below I only see one shape with text. I'm not sure what I'm doing wrong. Matt
var room:Sprite = new Sprite();
var bgBlue:Shape = new Shape()
bgBlue.graphics.beginFill( 0xCEEDF0);
bgBlue.graphics.drawRect( 0, 0, 200, 30 );
bgBlue.graphics.endFill();
var tf:TextFormat = new TextFormat();
tf.color = 0xFFFFFF;
tf.font = "Verdana";
tf.size = 17;
tf.align = "center";
var hd_col1_txt:TextField = new TextField();
hd_col1_txt.text = "Shape 1";
hd_col1_txt.x = 0;
hd_col1_txt.y = 0;
hd_col1_txt.width = bgBlue.width;
hd_col1_txt.setTextFormat( tf );
var hd_col1_shp:MovieClip = new MovieClip();
hd_col1_shp.addChild( bgBlue );
hd_col1_shp.addChild(hd_col1_txt);
room.addChild(hd_col1_shp);
hd_col1_shp.x = room.width;
hd_col1_shp.y = 0;
var hd_col2_txt:TextField = new TextField();
hd_col2_txt.text = "Shape 2";
hd_col2_txt.x = 0;
hd_col2_txt.y = 0;
hd_col2_txt.width = bgBlue.width;
hd_col2_txt.setTextFormat(tf);
var hd_col2_shp:MovieClip = new MovieClip();
hd_col2_shp.addChild( bgBlue );
hd_col2_shp.addChild(hd_col2_txt);
room.addChild(hd_col2_shp);
hd_col2_shp.x = 220;
hd_col2_shp.y = 0;
stage.addChild(room)
bgBlue is just one instance, everytime you do
.addChild( bgBlue );
You are taking that instance and adding it to another parent display object: moving it from one parent to another.
If you are going to have just two shapes, just duplicate the code of bgBlue:
var bgBlue2:Shape = new Shape()
bgBlue2.graphics.beginFill( 0xCEEDF0);
bgBlue2.graphics.drawRect( 0, 0, 200, 30 );
bgBlue2.graphics.endFill();
And then add the new shape instead of the original bgBlue
hd_col2_shp.addChild( bgBlue2 );
Of course, if you are going to have more shapes added should be better to define a class and make instances of it to add the dynamically.
By the way, in your code you have:
hd_col1_shp.x = room.width;
Be careful, maybe the sprite width is not going to be defined just after adding it to stage
Usually when a task or a block of code is intended to be used many times, it's better to put it in a function to get a simpler and more maintainable code.
For your case, you want to create buttons, menu items or whatever. So you can write a function which will create one item every time according to data or parameters that you will pass to it ( background color, text color, width, height, ... ).
For that you can start by fixing your items parameters like this :
var items:Array = [
{bgcolor: 0xCEEDF0, width: 200, height: 30, x: 0, y: 0, label: 'Shape 1', color: 0x000090},
{bgcolor: 0xff9900, width: 200, height: 30, x: 201, y: 0, label: 'Shape 2', color: 0xffffff}
];
Then you can write the function that will create the item with its background and label and will be executed for all your items :
function create_item_with_label(item_data:Object, items_container:Sprite): void
{
var text_format:TextFormat = new TextFormat();
// set the color of the text
text_format.color = item_data.color;
text_format.font = 'Verdana';
text_format.size = 17;
text_format.align = 'center';
// create the background
var item_bg:Shape = new Shape();
item_bg.graphics.beginFill(item_data.bgcolor);
item_bg.graphics.drawRect(0, 0, item_data.width, item_data.height);
item_bg.graphics.endFill();
// create the label
var item_label:TextField = new TextField();
item_label.text = item_data.label;
item_label.x = item_label.y = 0;
item_label.width = item_bg.width;
item_label.selectable = false;
item_label.setTextFormat(text_format);
var item:Sprite = new Sprite();
item.x = item_data.x;
item.y = item_data.y;
item.addChild(item_bg);
item.addChild(item_label);
items_container.addChild(item);
}
Note here that I didn't use a MovieClip for the item and instead I used a Sprite because simply we don't need timelines, which is the only difference between these objects.
Then you can create the items container ( the room object ) :
var room:Sprite = new Sprite();
addChild(room);
And then, you can create your items to be added to your items container :
for(var i:int = 0; i < items.length; i++){
create_item_with_label(items[i], room);
}
Hope that can help.
I'm adding some circles to away3d as sprite3ds, but for some reason they all have white backgrounds that I can't seem to remove. Anyone know what I'm missing:
var hotspot:Hotspot = e.target as Hotspot;
var spBoard:Sprite = new Sprite();
spBoard.x = circleX;
spBoard.y = circleY;
var shCircle:Shape = new Shape();
shCircle.graphics.lineStyle(2,0x000000);
shCircle.graphics.drawCircle(0,0,circleR);
shCircle.x = 0;
shCircle.y = 0;
var shFill:Shape = new Shape();
shFill.graphics.lineStyle(1,0x000000);
shFill.graphics.moveTo(0,0);
shFill.graphics.lineTo(circleR,0);
shFill.x = 0;
shFill.y = 0;
var shAngle:Shape = new Shape();
var shArrow:Shape = new Shape();
shArrow.graphics.lineStyle();
shArrow.graphics.beginFill(0x000000);
shArrow.graphics.moveTo(angleR,1);
shArrow.graphics.lineTo(angleR-5,8);
shArrow.graphics.lineTo(angleR+5,8);
shArrow.graphics.lineTo(angleR,1);
shArrow.graphics.endFill();
spBoard.addChild(shFill);
spBoard.addChild(shAngle);
spBoard.addChild(shArrow);
spBoard.addChild(shCircle);
var hotspotTimer:MovieClip = new MovieClip();
hotspotTimer.addChild(spBoard);
var bounds:Rectangle = hotspotTimer.getBounds(hotspotTimer);
var bitmapData : BitmapData = new BitmapData(512, 512);
bitmapData.draw(hotspotTimer);
var bitmapPointsTexture:BitmapTexture = new BitmapTexture(bitmapData);
var _pointsMaterial:TextureMaterial = new TextureMaterial(bitmapPointsTexture);
var inworldHotspotTimer:Sprite3D = new Sprite3D(_pointsMaterial,bitmapData.width,bitmapData.height);
inworldHotspotTimer.x = hotspot.x;
inworldHotspotTimer.y = hotspot.y;
inworldHotspotTimer.z = hotspot.z;
scene.addChild(inworldHotspotTimer);
}
I've seen in blog posts such as this
http://www.allforthecode.co.uk/aftc/forum/user/modules/forum/article.php?index=6&subindex=4&aid=315
On how they do it, but they're using an older version with the BitmapMaterial removed.
Change the line that declares the bitmapdata to this:
var bitmapData : BitmapData = new BitmapData(512, 512, true, 0x00808080);
If you don't fill the bitmap with a color that has alpha of 0, you'll get the borders in the texture.
I want to apply a gradient to my text in Flash Develop and read that using a mask is the easiest way. Problem is that I can not get it to work. I tried to create a mask with just the textField and by adding it to a sprite, neither work.
Another strange thing is that the textmask will function as a mask for start title if I reverse them like:
starttitle.mask =textmask
When I try the code below nothing displays.
var format2:TextFormat = new TextFormat();
format2.size = 40;
format2.font = "Times New Roman";
format2.bold = true
starttitle = new TextField;
starttitle.defaultTextFormat = format2;
starttitle.text = "Memory Circles";
starttitle.textColor = 0xFF0000
starttitle.autoSize = "center";
starttitle.background = false;
starttitle.backgroundColor = 0xFF4242;
starttitle.x = (300 - starttitle.width * .5);
starttitle.y = (150 - starttitle.height * .5);
starttitle.mouseEnabled = false;
addChild(starttitle)
var textmask:Shape = new Shape
var fillType:String = GradientType.LINEAR;
var colors:Array = [0xFF0000, 0];
var alphas:Array = [1, 1];
var ratios:Array = [0, 255];
var gradientBoxMatrix:Matrix = new Matrix();
gradientBoxMatrix.createGradientBox(50,100,45,0,0);
var spreadMethod:String = SpreadMethod.REPEAT;
textmask.graphics.beginGradientFill(fillType, colors, alphas, ratios,
gradientBoxMatrix, spreadMethod);
textmask.graphics.drawRect(200,100,300,100)
addChild(textmask)
textmask.mask =starttitle
I read something about the font needing to be embedded but I'm using Times New Roman and thought this would be embedded. Also other fonts don't work.
Try to use bitmap caching on starttitle and textmask:
starttitle.cacheAsBitmap=true;
textmask.cacheAsBitmap=true;
I have this code for a message to appear on stage when player finishes drag and drop. I would like this sprite to be removed when a button is clicked for the next frame. Can someone help me with the code?
stage.addEventListener(Event.ENTER_FRAME, EntFrame);
function EntFrame (e:Event):void
{
if (CntP1+CntP2+CntP3+CntP4+CntP5+CntP6+CntP7+CntP8 == 40)
{
var w:int = 400, h:int = 200;
var win:Sprite = new Sprite();
win.name = "Mywin";
addChild(win);
// draw rounded rect with subtle vertical linear gradient fill and blue stroke
win.graphics.lineStyle(4,0x0077ff);
var mat:Matrix = new Matrix();
mat.createGradientBox(w, h, 90 * (Math.PI / 180));
win.graphics.beginGradientFill(GradientType.LINEAR,[0xffffff,0xeeeeee],[1.00,1.00],[0,255],mat);
win.graphics.drawRoundRect(0,0,w,h,15,15);
// show center "YOU WIN!" text
var tf:TextField = new TextField();
tf.autoSize = TextFieldAutoSize.LEFT;
tf.antiAliasType = AntiAliasType.ADVANCED;
tf.defaultTextFormat = new TextFormat("Arial, Verdana",36,0x454545,true);
tf.text = "Κέρδισες!";
tf.selectable = false;
win.addChild(tf);
tf.x = w/2 - tf.width/2;
tf.y = h/2 - tf.height/2;
// add a drop shadow
var dropShadow:DropShadowFilter = new DropShadowFilter(3,45,0,.35,8,8,1,3);
win.filters = [dropShadow];
// center the graphic
win.x = stage.stageWidth/2 - win.width/2;
win.y = stage.stageHeight/2 - win.height/2;
}
}
Your code isn't written well and needs rewriting to ensure reuse or scalability of your project, but here's a quick way out.
make a holder Sprite, something like
var messageHolder:Sprite = new Sprite();
addChild(messageHolder);
add all the messages to that holder in any fashion you like. When you need to erase the contents of that holder, call following method:
function clearHolderContents(holder:DisplayObjectContainer):void
{
if (holder.numChildren < 1)
return; // no need to continue this method if the target is empty
for (var i:int = holder.numChildren - 1; i >= 0; i--)
removeChild(holder.getChildAt(i));
}
This method can clear contents of any DisplayObjectContainer => use it for your messageHolder:
clearHolderContents(messageHolder);
Hope that helps!
i want to apply a picture which contains transparent areas as a mask to a display object.
the mask only show the area which the mask has color.but in fact,the display object still show the whole area.so i convert bitmap to a vector image,that's solve the problem,but the convert method is horrible.
public static function createVectorImage(bd:BitmapData,colorKey:uint = 0):Shape{
if(bd==null){
return null;
}
var sh:Shape = new Shape();
var g:Graphics = sh.graphics;
g.beginBitmapFill(bd);
var beginPixel:int = -1;
var i:int,il:int,j:int,jl:int;
var value:uint;
for(i = 0,il=bd.height;i<il;i++){
for(j = 0,jl = bd.width;j<jl;j++){
value = bd.getPixel32(j,i);
if(value!=colorKey&&beginPixel==-1){
beginPixel = j;
}else if(value==colorKey&&beginPixel!=-1){
//draw rect
g.drawRect(beginPixel,i,j-beginPixel,1);
beginPixel = -1;
}
}
if(beginPixel!=-1){
g.drawRect(beginPixel,i,j-beginPixel,1);
beginPixel = -1
}
}
g.endFill();
return sh;
}
is there any way better than this?
You can convert your display object to a bitmap then apply a mask on it.
Convert you display object to a bitmap data:
var rect:Rectangle = displayObject.getRect();
var displayBD:BitmapData = new BitmapData(rect.width, rect.height, true, 0);
displayBD.draw(displayObject);
Apply the mask:
private static const ORIG:Point = new Point(0, 0);
private static function createBitmapDataWithMask(
baseBD:BitmapData, maskBD:BitmapData):BitmapData
{
var bitmapData:BitmapData;
bitmapData = new BitmapData(baseBD.width, baseBD.height, true, 0x000000);
bitmapData.copyPixels(baseBD, baseBD.rect, ORIG, maskBD, ORIG, true);
return bitmapData;
}
Display the bitmap data:
var bitmapData:BitmapData = createBitmapDataWithMask(displayBD, maskBD);
var bitmap:Bitmap = new Bitmap(bitmapData, "auto", true);
addChild(bitmap);
If you remove the bitmap from the stage, don't forget the free the bitmap data!
removeChild(bitmap);
bitmap.bitmapData.dispose();
bitmap = null;
Another option would be to use bitmap caching. It needs to be applied to the mask as well as the maskee:
var bd:BitmapData = new BitmapData(200, 200, true, 0x00000000);
bd.fillRect(new Rectangle(0, 0, 40, 40), 0xff000000);
var mask:Bitmap = new Bitmap(bd);
mask.cacheAsBitmap = true;
var maskee:Sprite = new Sprite();
maskee.cacheAsBitmap = true;
maskee.graphics.beginFill(0xff0000, 1);
maskee.graphics.drawRect(0, 0, 200, 200);
maskee.graphics.endFill();
maskee.mask = mask;
addChild(mask);
addChild(maskee);