I have this movieclip loaded on runtime called cHolder. I apply a tint at first, and when it is mouseOver there will be no tint. How do i apply a tween to make the change in tint appear more gradually? THanks!
var imageLoader = new Loader();
imageLoader.load(new URLRequest(projectDP));
var origColor: Color = new Color();
origColor.setTint( 0x000000, 0.8 );
cv.cHolder.transform.colorTransform = origColor;
cv.cHolder.addChild(imageLoader);
this.addChild(cv);
cv.cHolder.addEventListener(MouseEvent.MOUSE_OVER, onRoll);
cv.cHolder.addEventListener(MouseEvent.MOUSE_OUT, onOut);
function onRoll(e:Event):void
{
origColor.setTint( 0, 0 );
e.currentTarget.transform.colorTransform = origColor;
}
function onOut(e:Event):void
{
origColor.setTint( 0x000000, 0.8 );
e.currentTarget.transform.colorTransform = origColor;
}
I recommend using a tween engine. You can use flash Tween, but I prefer to work with any of the many available engines out there, such as TweenMax.
to tween a tint you would do something like this:
import com.greensock.*;
import com.greensock.plugins.*;
TweenPlugin.activate([TintPlugin]);
var color:uint = 0x0;
var imageLoader = new Loader();
imageLoader.load(new URLRequest(projectDP));
var origColor: Color = new Color();
origColor.setTint( 0x000000, 0.8 );
cv.cHolder.transform.colorTransform = origColor;
cv.cHolder.addChild(imageLoader);
this.addChild(cv);
cv.cHolder.addEventListener(MouseEvent.MOUSE_OVER, onRoll);
cv.cHolder.addEventListener(MouseEvent.MOUSE_OUT, onOut);
function onRoll(e:Event):void
{
//origColor.setTint( 0, 0 );
//e.currentTarget.transform.colorTransform = origColor;
TweenLite.to(e.currentTarget, 1, {tint:null});
}
function onOut(e:Event):void
{
//origColor.setTint( 0x000000, 0.8 );
//e.currentTarget.transform.colorTransform = origColor;
TweenLite.to(e.currentTarget, 1, {tint:0x000000});
}
Related
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?
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.
So I have a Tile class, with a sprite variable that holds the graphic for the tile. On mouse over, I ColorTransform the graphic. Seems to work fine. On mouse out, I try to change it back. Nada. And in fact, rolling over the same tile twice will increase the alpha until eventually it fades totally. Not sure how to fix it. Here's my code.
In the Tile class:
this.addEventListener(MouseEvent.MOUSE_OVER, thisMouseOver);
this.addEventListener(MouseEvent.MOUSE_OUT, thisMouseOut );
public function thisMouseOver( e:Event ):void {
tileGraphic.bitmapData = setAlpha(tileGraphic.bitmapData);
}
public function thisMouseOut( e:Event ):void {
tileGraphic.bitmapData = resetAlpha(tileGraphic.bitmapData);
}
private function setAlpha( bmd:BitmapData ):BitmapData {
var rec:Rectangle = new Rectangle( 0, 0, bmd.width, bmd.height );
var ct:ColorTransform = new ColorTransform();
ct.alphaMultiplier = .65;
bmd.colorTransform( rec, ct );
return bmd;
} //end function setAlpha
private function resetAlpha( bmd:BitmapData ):BitmapData {
var rec:Rectangle = new Rectangle( 0, 0, bmd.width, bmd.height );
var ct:ColorTransform = new ColorTransform();
ct.alphaMultiplier = 1;
bmd.colorTransform( rec, ct );
return bmd;
} //end function resetAlpha
Can anyone point me in the right direction? Thanks!
Replace the resetAlpha with
private function resetAlpha( bmd:BitmapData ):BitmapData {
var rec:Rectangle = new Rectangle( 0, 0, bmd.width, bmd.height );
var ct:ColorTransform = new ColorTransform();
ct.alphaOffset = 255
bmd.colorTransform( rec, ct );
return bmd;
} //end function resetAlpha
You should better change alpha of the container instead of playing with the BitmapData pixels. For example, in your case if your tile bitmap will initially have transparent pixels (fill it with 0x00ff0000 prior to drawing a thing and check if so), they will become opaque with codingbuddha's answer. So, change the listeners to the following:
public function thisMouseOver( e:Event ):void {
tileGraphic.alpha=0.65;
}
public function thisMouseOut( e:Event ):void {
tileGraphic.alpha=1;
}
I have MC with external loaded image (jpg).
Next layer is masked Sprite where I am drawing lines in different colors, opacity ,etc with graphics.lineStyle . Everything works fine, so I can see image and drawings over. Now I want eraser to make, and trying to make some kind of (transparent) line which will "erase" exising line.
If I for example draw (with mouse) red line, and then switch color to yellow and intersect on some point with previous line, it is ok, I see yellow color. Now I don't have idea how to make "transparent" color? So when mouse move over existing drawing, just see again part of background image. If I set one color background everything is OK, but I have image, end eraser leaves some color, and I need to be transparent. Tried blend modes, cached as bmp, everything I found but still no solution.
Seemingly you use Graphics objects that overlay the image. In order to erase something, you should give your sprite a topmost shape that will have BlendMode.ERASE as blend mode, and draw on it with alpha component of color being 0xFF. The sprite should have its blendMode to be BlendMode.LAYER. Here's a test to play with:
public class TestErase extends Sprite
{
public function TestErase() {
var b:Sprite = new Sprite();
var c:Shape = new Shape();
b.blendMode = BlendMode.LAYER;
c.blendMode = flash.display.BlendMode.ERASE;
c.graphics.beginFill(0, 1);
c.graphics.drawRect(50, 50, 50, 50);
c.graphics.endFill();
b.graphics.beginFill(0xff0000, 1);
b.graphics.drawRect(0, 0, 150, 150);
b.graphics.endFill();
b.addChild(c);
addChild(b);
this.graphics.beginFill(0x00c000, 1);
graphics.drawRect(75, 75, 100, 100);
graphics.endFill();
}
}
This makes a 50x50 hole, defined by "c" sprite in "b" sprite, that does not affect "this" sprite.
Okay you asked for an example. Here.
public class Main extends Sprite
{
public var sh:Shape;
public var drawing:Boolean;
public var sp:Sprite;
public var bd:BitmapData;
public var erasing:Boolean;
[Embed(source = '../lib/093.jpg')]
public static const Background:Class;
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);
// entry point
var ba:Bitmap = new Background();
ba.scaleX = 0.5;
ba.scaleY = 0.5;
addChild(ba);
bd = new BitmapData(640, 400, true, 0);
var bm:Bitmap = new Bitmap(bd);
sp = new Sprite();
sp.addChild(bm);
sp.blendMode = BlendMode.LAYER;
var tf:TextField = new TextField();
tf.y = 401;
tf.background = true;
tf.backgroundColor = 0x0;
tf.defaultTextFormat = new TextFormat('Arial', 12, 0xe00000, true, false, false);
tf.selectable = false;
tf.text = 'Erase';
addChild(tf);
addChild(sp);
tf.addEventListener(MouseEvent.CLICK, toggleErasing);
sp.addEventListener(MouseEvent.MOUSE_DOWN, startDrawing);
sp.addEventListener(MouseEvent.ROLL_OUT, endDrawing);
sp.addEventListener(MouseEvent.MOUSE_UP, endDrawing);
}
private function toggleErasing(e:MouseEvent):void {
erasing = !erasing;
if (erasing) (e.currentTarget as TextField).text = 'Erasing...'; else (e.currentTarget as TextField).text = 'Erase';
e.stopPropagation();
}
private function startDrawing(e:MouseEvent):void {
if (drawing) return;
sh = new Shape();
sh.graphics.lineStyle(3, Math.floor(Math.random() * 0x100000), 1,true);
if (erasing) sh.blendMode = BlendMode.ERASE;
sh.graphics.moveTo(e.localX, e.localY);
addEventListener(MouseEvent.MOUSE_MOVE, trackMouse);
sp.addChild(sh);
drawing = true;
}
private function endDrawing(e:MouseEvent):void {
if (!drawing) return;
removeEventListener(MouseEvent.MOUSE_MOVE, trackMouse);
if (erasing) bd.draw(sh, null, null, BlendMode.ERASE);
else bd.draw(sh);
sp.removeChild(sh);
sh = null;
drawing = false;
}
private function trackMouse(e:MouseEvent):void {
sh.graphics.lineTo(e.localX, e.localY);
}
}
Tested by me, and should work as is, just change the background :)
my code:
myCircle = new Shape();
function doStuffWithBitmapData(bmd:BitmapData):void
{
myCircle = new Shape();
var matrix:Matrix = new Matrix();
matrix.translate(0, 0);
myCircle.graphics.beginBitmapFill(bmd, matrix, false);
myCircle.graphics.drawCircle(0, 0, 17);
myCircle.graphics.endFill();
myCircle.x = 40;
myCircle.y = 63;
addChild(myCircle);
// your code
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event)
{
myCircle.rotation += 3;
}
I need to fill the circle with image , but the image is repeating many times, but if I set the repeat to false, the picture will be bigger, can I make no repeat and at the same time don't change the sizes of the filled image?
i'm not too sure of the the bitmapfill method, but creating your own bitmap and bitmapData, and then using your image's bitmapdata, you can manipulate the image pixel/data anyway you like.
-Using the setPixel/setPixel32 method of the bitmapData class will be helpful in your task (google is your friend)
Adobe's help: http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/BitmapData.html
Please look closely at the draw() method of BitmapData Class Documents. It is very important.
and refer a following code.
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Bitmap;
var myCircle:Shape;
var bmd:BitmapData = new BitmapData(600,400,false,0xffffff);
var bmp:Bitmap = new Bitmap(bmd);
this.addChild(bmp);
var circleBitmapData:BitmapData = new BitmapData(20,20,false,0xffffff * Math.random());
myCircle = new Shape();
var matrix:Matrix = new Matrix();
myCircle.graphics.beginBitmapFill(circleBitmapData);
myCircle.graphics.drawCircle(0, 0, 20);
myCircle.graphics.endFill();
myCircle.x = 40;
myCircle.y = 63;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(e:Event)
{
bmd.draw(myCircle, myCircle.transform.matrix, myCircle.transform.colorTransform);
myCircle.x = Math.random() * stage.width;
myCircle.y = Math.random() * stage.height;
}
long story short, I made image for it.
I am beginner in actionscripting, found out that only animating is not enough.
What I try to accomplish:
You can use a simple mask to achieve this. Here's a working example (using LEFT mouse button, though. I don't think RIGHT one would be suitable for this):
package examples
{
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.MouseEvent;
import flash.ui.Mouse;
public class MaskTest extends Example
{
private var _toBeErased:Sprite;
private var _discoverable:Sprite;
private var _holesContainer:Sprite;
private var _mouseIsPressed:Boolean = false;
public function MaskTest()
{
}
// Call this method once this Class instance has been added to stage
public function init():void
{
// Create sprites
_toBeErased = new Sprite();
addChild( _toBeErased );
_discoverable = new Sprite();
addChild( _discoverable );
_holesContainer = new Sprite();
addChild( _holesContainer );
// Draw sprites
_toBeErased.graphics.beginFill( 0xFFFF00 );
_toBeErased.graphics.drawRect( 0, 0, 900, 600 );
_toBeErased.graphics.endFill();
_discoverable.graphics.beginFill( 0xFFAAAA );
_discoverable.graphics.drawRect( 0, 0, 900, 600 );
_discoverable.graphics.endFill();
// Set mask
_discoverable.mask = _holesContainer;
// Add mouse listeners
stage.addEventListener( MouseEvent.MOUSE_MOVE, onMouseMove );
stage.addEventListener( MouseEvent.MOUSE_DOWN, onMouseDown );
stage.addEventListener( MouseEvent.MOUSE_UP, onMouseUp );
}
// Mouse listeners callbacks...
private function onMouseDown( e:MouseEvent ):void{
_mouseIsPressed = true;
}
private function onMouseUp( e:MouseEvent ):void{
_mouseIsPressed = false;
}
private function onMouseMove( e:MouseEvent ):void
{
if( !_mouseIsPressed )
return;
// Get a random size for circle
var radius:Number = 5 + (Math.random()*10-5);
// Create new circle and paint it
var circle:Sprite = new Sprite();
circle.graphics.beginFill( 0x000000 );
circle.graphics.drawCircle( 0, 0, radius );
circle.graphics.endFill();
// Move it randomly, just a bit
circle.x = _holesContainer.mouseX + (Math.random()*20-10);
circle.y = _holesContainer.mouseY + (Math.random()*20-10);
_holesContainer.addChild( circle );
}
}
}
Check out http://f6design.com/journal/2009/05/24/erase-an-image-using-your-mouse-in-as3/
Basically, you have to make use of the erase Blend Mode: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BlendMode.html