Using text as a mask to add a gradient to the text in AS3 - actionscript-3

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;

Related

AS3: localToGlobal with perspectiveProjection

It seems that if a display object has a perspective projection applied to it, calling localToGlobal gives you the wrong coordinates. In the following code, I draw a rectangle, rotate it slightly about its X axis, then draw an oval inside it using coordinates derived from localToGlobal. It works fine, until I try to apply a perspective projection, then the coordinates are all wrong. Anyone know how to get around this problem?
var w:uint = 300, h:uint = 150;
var s:Sprite = new Sprite();
s.graphics.beginFill(0x000000);
s.graphics.drawRect(-w/2,0,w,h);
s.graphics.endFill();
s.x = 275; s.y = 200; s.z = 600;
s.rotationX = -45;
addChild(s);
var point00:Point = new Point(0,0);
var point0h:Point = new Point(0,h);
var midL:Point = new Point(-w/2,h/2);
var midR:Point = new Point(w/2,h/2);
/*var VP:PerspectiveProjection = new PerspectiveProjection();
VP.fieldOfView = 55;
var p:Point = new Point(275,100);
VP.projectionCenter = p;
s.transform.perspectiveProjection = VP;*/
var o:Shape = new Shape();
o.graphics.beginFill(0x00ff00);
o.graphics.drawEllipse(
s.localToGlobal(midL).x,
s.localToGlobal(point00).y,
s.localToGlobal(midR).x - s.localToGlobal(midL).x,
s.localToGlobal(point0h).y - s.localToGlobal(point00).y
);
addChild(o);
It seems that setting perspectiveProjection does not force the player to redraw the object, and localToGlobal depends on redraw for correct results. You can wait 1 tick like you found (setTimeout for 0ms or enterFrame for 1 frame will do it) or you can force the player to redraw using BitmapData/draw():
// ...
s.transform.perspectiveProjection = VP;
new BitmapData(1, 1).draw(s); // forces player to redraw the sprite
var o:Shape = new Shape();
o.graphics.beginFill(0x00ff00);
o.graphics.drawEllipse(
s.localToGlobal(midL).x,
s.localToGlobal(point00).y,
s.localToGlobal(midR).x - s.localToGlobal(midL).x,
s.localToGlobal(point0h).y - s.localToGlobal(point00).y
);
addChild(o);
I found a workaround that isn't terrible. All you have to do is put a slight delay before the localToGlobal calls and then they will return the right coordinates. That also fixes local3DToGlobal.

How do i dynamically add two shapes with text next to each other using action script 3

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.

Away3d transparent bitmap Sprite3d

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.

Issues with BitmapData of a MovieClip with rotationY applied to it

So I have a simple file right now that eventually will take a movieclip and save it as an image. I am currently rotating the clip's y by 45 to give it kind of a 3D look and adding it back to the stage. I've tried googling and a couple different things, but I can't quite get it to work. The first thing I tried was getting the BitmapData of the movieclip I rotated. That flattened the clip:
test_mc.response_mc.rotationY = 45;
var mc:MovieClip = test_mc.response_mc;
var bmp:BitmapData = new BitmapData(mc.width, mc.height);
bmp.draw(mc);
var output:Bitmap = new Bitmap(bmp);
output.x = 270;
output.y = 191;
addChild(output);
The next thing I tried was getting the parent clip's BD. That gave it an angle... just the wrong one:
(same code as above with this line change)
var mc:MovieClip = test_mc;
Any thoughts here would be nice. I tried doing stuff with matrices, but had no luck. I also have images... just can't post them yet :(
Something else I've tried with no luck:
var target:DisplayObject = test_mc as DisplayObject;
var targetTransform:Matrix = target.transform.concatenatedMatrix;
var targetGlobalBounds:Rectangle = target.getBounds(target.stage);
var targetGlobalPos:Point = target.localToGlobal(new Point());
var targetOriginOffset:Point = new Point(targetGlobalPos.x - targetGlobalBounds.left, targetGlobalPos.y - targetGlobalBounds.top);
targetTransform.tx = targetOriginOffset.x;
targetTransform.ty = targetOriginOffset.y;
var cloneData:BitmapData = new BitmapData(targetGlobalBounds.width, targetGlobalBounds.height, true, 0x00000000);
cloneData.draw(target, targetTransform);
var output:Bitmap = new Bitmap(cloneData);
**Another update**
So hopefully this will help a little. I was able to recreate what I was doing using Matrix3D.
test_mc.response_mc.rotationY = 45;
var matrix:Matrix3D = new Matrix3D();
matrix.prependRotation(45, Vector3D.Y_AXIS);
test2_mc.response_mc.transform.matrix3D = matrix;
test2_mc.response_mc.transform.matrix3D.appendTranslation(0, 0, 0);
And I've come closer to getting the bitmap to look correct (thank to a Mike Chambers blog).
var mcOffset:Matrix3D = test2_mc.response_mc.transform.matrix3D;
var rawMatrixData:Vector.<Number> = mcOffset.rawData;
var globalBounds:Rectangle = test2_mc.response_mc.getBounds(test2_mc);
var matrix:Matrix = new Matrix();
matrix.a = rawMatrixData[0];
matrix.c = rawMatrixData[1];
matrix.tx = test2_mc.response_mc.x - globalBounds.x;
matrix.b = rawMatrixData[4];
matrix.d = rawMatrixData[5];
matrix.ty = test2_mc.response_mc.y - globalBounds.y;
var bmp:BitmapData = new BitmapData(150, test2_mc.height);
test2_mc.response_mc.transform.matrix3D = null;
bmp.draw(test2_mc.response_mc, matrix);
test2_mc.response_mc.transform.matrix3D = mcOffset;
var output:Bitmap = new Bitmap(bmp);
Well I took it a step further back and went to the stage. For whatever reason trying to draw the parent (test_mc) of the rotated movie clip (response_mc) WON'T work, however drawing the stage and setting the bounds to the area of the parent DOES work. Here's my code (which is sadly very simple):
var bmp:BitmapData = new BitmapData(test_mc.width, test_mc.height);
bmp.draw(stage.getChildAt(0), new Matrix(1, 0, 0, 1, -test_mc.x, -test_mc.y));
var output:Bitmap = new Bitmap(bmp);

ColorTransform removes shadow

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;
}