Actionscript 3, flash: Erasing area dynamically? - actionscript-3

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

Related

Shooting a bullet in flash CS6 ActionScript 3.0

I keep getting the following error when I fire a Shot I made in Flash CS6 AS 3.0
1118: Implicit coercion of a value with static type Object to a possibly unrelated type flash.display:DisplayObject.
package
{
import flash.display.MovieClip;
import flash.ui.Mouse;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.ui.Keyboard;
import flash.events.KeyboardEvent;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.media.SoundChannel;
public class AvoiderGame extends MovieClip
{
public var army:Array;
public var reishoot:ReiShoot;
public var enemy:Enemy;
public var avatar:Avatar;
public var gameTimer:Timer;
public var useMouseControl:Boolean;
public var downKey:Boolean;
public var bullets:Array = [];
public var backgroundMusic:BackgroundMusic;
public var enemySound:EnemySound;
public var bgmSoundChannel:SoundChannel;
public var sfxSoundChannel:SoundChannel;
function AvoiderGame()
{
/*useMouseControl = false;
downKey = false;
if( useMouseControl )
{
avatar.x = mouseX;
avatar.y = mouseY;
}
else
{
avatar.x = 200;
avatar.y = 250;
}
*/
backgroundMusic = new BackgroundMusic();
bgmSoundChannel = backgroundMusic.play();
bgmSoundChannel.addEventListener( Event.SOUND_COMPLETE, onBackgroundMusicFinished );
enemySound = new EnemySound();
army = new Array();
//Initial Position of the Enemy
var newEnemy = new Enemy( 2700, 600 );
army.push( newEnemy );
addChild( newEnemy );
avatar = new Avatar();
addChild( avatar );
avatar.height = 220;
avatar.width = 120;
avatar.addEventListener(MouseEvent.CLICK, shoot);
gameTimer = new Timer( 25 );
gameTimer.addEventListener( TimerEvent.TIMER, onTick );
gameTimer.start();
//addEventListener( Event.ADDED_TO_STAGE, onAddToStage );
}//End AvoiderGame
function shoot(e:MouseEvent):void
{
var b:Shot = new Shot();
b.addEventListener(Event.ENTER_FRAME, bulletflies);
stage.addChild(b);
bullets.push(b);
}
function bulletflies(e:Event):void
{
e.currentTarget.y -= 5;
if(e.currentTarget.y < 0 || e.currentTarget.y > stage.height)
{
stage.removeChild(e.currentTarget);
bullets.splice(bullets.indexOf(e.currentTarget), 1);
}
}
public function onBackgroundMusicFinished( event:Event ):void
{
bgmSoundChannel = backgroundMusic.play();
bgmSoundChannel.addEventListener( Event.SOUND_COMPLETE, onBackgroundMusicFinished );
}
public function onKeyPress(keyboardEvent:KeyboardEvent):void
{
if ( keyboardEvent.keyCode == Keyboard.DOWN )
{
downKey = true;
}
}
public function onKeyRelease( keyboardEvent:KeyboardEvent ):void
{
if ( keyboardEvent.keyCode == Keyboard.DOWN )
{
downKey = false;
}
}
public function onAddToStage(event:Event):void
{
stage.addEventListener( KeyboardEvent.KEY_DOWN, onKeyPress );
stage.addEventListener( KeyboardEvent.KEY_UP, onKeyRelease );
}
public function onTick( timerEvent:TimerEvent ):void
{
if ( Math.random() < 2800 )
{
var randomY:Number = Math.random() * 2800;
var newEnemy:Enemy = new Enemy( width, randomY );
army.push( newEnemy );
addChild( newEnemy );
gameScore.addToValue( 1 );
//sfxSoundChannel = enemySound.play();
}//End if statement
/*
if( useMouseControl )
{
avatar.x = mouseX;
avatar.y = mouseY;
}
else
{
if ( downKey )
{
avatar.moveDown();
}
}
*/
avatar.x = mouseX;
avatar.y = mouseY;
for each ( var enemy:Enemy in army )
{
enemy.moveDownABit();
if ( avatar.hitTestObject( enemy ) )
{
bgmSoundChannel.stop();
gameTimer.stop();
dispatchEvent( new AvatarEvent( AvatarEvent.DEAD ) );
}//End if statement
}//End for loop
}//End onTick function
public function getFinalScore():Number
{
return gameScore.currentValue;
}
}//End AvoiderGame class
}//End package
Line 90 is stage.removeChild(e.currentTarget);
With this, you need to cast e.currentTarget to a DisplayObject:
stage.removeChild(e.currentTarget as DisplayObject);
Just a guess: you've started your ENTER_FRAME loop, (which will remove 'b') before you've said addChild(b). Try putting 'b' on the display list before you try to remove it!!
Aha! I think I may have found your problem, though I am unsure of how it relates to the error code...
Take a look at your Shot class (which I have found here https://stackoverflow.com/questions/22244959/why-does-this-not-shoot). Every frame, you tell the Shot class to test whether it is in the boundaries of the stage still, and if so, to remove itself from the stage. In line 90, you also tell the stage to determine if the bullet is still in bounds, and if so, to remove it again.
You have tried to remove the bullet from the stage twice!
Again, I stress, this seems to be unrelated to the error code, but hopefully it points you in the right direction.

Change Alpha on Rollover; Not Changing Back on Mouse Out?

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

looping custom cursor opacity falling in infinite loop

I am trying to make my custom cursor glow slowly by changing its opacity. The problem is that the only way I can see it working is by making a while, which creates an infinite loop. Is there a way to proceed so my cursor changes from 0 opacity to 1 opacity and go up and down. Here is my code at the moment... I'm trying to find another way to proceed, but I really don't see any other way.
public var Alpha:Number = 1;
public var sense:String = "down";
private function thisMouseOver(e:MouseEvent):void{
Mouse.hide();
//draws the cursor
drawCursor();
//Animates cursor
if(!this.animationStarted)
{
this.animationStarted = true;
animateCursor();
}
}
private function animateCursor():void{
while(this.animationStarted)
{
if(this.Alpha==1)
{
this.sense = "down";
}
else if(this.Alpha == 0)
{
this.sense = "up";
}
if(this.sense == "up")
this.Alpha += 0.1;
else
this.Alpha -= 0.1;
this.graphics.beginFill(0x333333);
this.graphics.drawRect(0,0,25,25);
this.graphics.endFill();
drawCursor();
}
}
private function drawCursor():void{
this.graphics.beginFill(0x00BFFF,this.Alpha);
//top left
this.graphics.drawRect(0,0,6,2);
//bottom left
this.graphics.drawRect(0,23,6,2);
//left top
this.graphics.drawRect(0,0,2,6);
//left bottom
this.graphics.drawRect(0,19,2,6);
//top righ
this.graphics.drawRect(19,0,6,2);
//right top
this.graphics.drawRect(23,0,2,6);
//bottom right
this.graphics.drawRect(19,23,6,2);
//right bottom
this.graphics.drawRect(23,19,2,6);
this.graphics.endFill();
}
The best way is to use tweener, my favorite is GTween:
private function test():void
{
var shape:Shape = new Shape();
addChild(shape);
shape.graphics.beginFill(0xFF0000, 1);
shape.graphics.drawCircle(100, 100, 50);
shape.graphics.endFill();
var tween:GTween = new GTween(shape, 1, {alpha:0}, {reflect:true, repeatCount:2});
tween.nextTween = tween;
}
Use tween.paused = true/false to play()/stop() the tween.
There is another variant without tweener (but I recommend to use tween because code is more clear, readable and it's less resources cost) that is more like your, but instead of while loop use EnterFrame event approach - remove while loop from animateCursor() method, add Event.ENTER_FRAME listener in the point of animateCursor(); call:
if(!this.animationStarted)
{
this.animationStarted = true;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame():void
{
animateCursor();
}
One way to avoid your problem with the infinite loop is to put your animateCursor code inside an ENTER_FRAME event handler.
Here's how it can look: http://www.swfcabin.com/open/1360303185
( Your custom cursor shape looks awesome ; )
Here's your code remade in MiniBuilder ( functions are arranged alphabetically ):
package com.glowingcursor {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.ui.*;
public class Application extends Sprite {
private var cursor:Sprite;
private var cursorOffset:Point;
private var sense:Boolean;
public function
Application() {
addEventListener( Event.ADDED_TO_STAGE, onAdded );
}
private function
animateCursor( e:Event ):void {
if ( cursor.alpha >= 1 ) sense = false;
else if ( cursor.alpha <= 0.2 ) sense = true;
if( sense ) cursor.alpha += 0.08;
else cursor.alpha -= 0.08;
}
private function
hideCursor( e:MouseEvent ):void {
Mouse.show();
removeChild( cursor );
removeEventListener( Event.ENTER_FRAME, moveCursor );
removeEventListener( Event.ENTER_FRAME, animateCursor );
}
private function
initCursor():void {
cursor = new Sprite();
cursor.graphics.beginFill( 0xff0000 );
cursor.graphics.drawRect( 0, 0, 6, 2 ); // top left
cursor.graphics.drawRect( 0, 23, 6, 2 ); // bottom left
cursor.graphics.drawRect( 0, 0, 2, 6 ); // left top
cursor.graphics.drawRect( 0, 19, 2, 6 ); // left bottom
cursor.graphics.drawRect( 19, 0, 6, 2 ); // top right
cursor.graphics.drawRect( 23, 0, 2, 6 ); // right top
cursor.graphics.drawRect( 19, 23, 6, 2 ); // bottom right
cursor.graphics.drawRect( 23, 19, 2, 6 ); // right bottom
cursor.graphics.endFill();
// So InteractiveObjects react to the custom cursor properly
cursor.mouseEnabled = false;
// For cursor centering
cursorOffset = new Point( cursor.width / 2, cursor.height / 2 );
}
private function
moveCursor( e:Event ):void {
cursor.x = mouseX - cursorOffset.x;
cursor.y = mouseY - cursorOffset.y;
}
private function
onAdded( e:Event ):void {
initCursor();
showCursor();
}
private function
showCursor():void {
Mouse.hide();
addChild( cursor );
addEventListener( Event.ENTER_FRAME, moveCursor );
addEventListener( Event.ENTER_FRAME, animateCursor );
}
}
}
You can put your code from the animateCursor inside a different method, and use a Timer to call that method. This way you can control how "fast" the cursor blinks and when.
Timer timer = new Timer( 25, 0 );
private function animateCursor():void
{
timer.addEventListener( TimerEvent.TIMER, timerHandler );
timer.start()
}
private function timerListener( e:TimerEvent ):void
{
if(this.Alpha==1)
{
this.sense = "down";
}
else if(this.Alpha == 0)
{
this.sense = "up";
}
if(this.sense == "up")
this.Alpha += 0.1;
else
this.Alpha -= 0.1;
this.graphics.beginFill(0x333333);
this.graphics.drawRect(0,0,25,25);
this.graphics.endFill();
drawCursor();
}
also it's a good idea to change your alpha conditions from this.Alpha == 0 to this.Alpha <= 0 as you may choose to change the amount by which you modify the alpha to values that don't always add up to 0 or 1.

AS3 Tweening a tint change

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

How to change the pixels in an image

i actually try to do the following: I have loaded an external image in a bitmapdata object and create a bitmap from it which i attach it to a sprite/MovieClip in order to have mouse events on it. Now under the previous logic i loaded two images (let's say circles) of the same size one that has a particular color and is covered by its black foreground circle. When i press left mouse button and hold it down i want while the mouse is moved to erase the foreground circle's pixels and so the background image starting to appear. I tried this to achieve but had no luck. In my best attempt i achieve to draw a line in the foreground image but i cannot reveal the background!
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.BlendMode;
public class Test2 extends MovieClip
{
// properties - state
// to attach the image and have mouse events
private var frontImage:Sprite;
private var backImage:Sprite;
// to load the image
private var myLoader:Loader;
// to get the bitmap data of the image
private var frontBitmapData:BitmapData;
private var frontBitmap:Bitmap;
// test
private var frontMask:Bitmap;
// constructor
function Test2():void
{
// load the background image
backImage = new Sprite();
attachImageToSprite1(new URLRequest("btest.jpg"));
backImage.mouseEnabled = false;
this.addChild( backImage );
// load the front image
frontImage = new Sprite();
attachImageToSprite2(new URLRequest("test.jpg"));
frontImage.mouseEnabled = true; // enable mouse
frontImage.buttonMode = true; // set button mode
this.addChild(frontImage); // load to stage
this.frontImage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
this.frontImage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
// methods
private function attachImageToSprite1(Name:URLRequest):void
{
this.myLoader = new Loader();
this.myLoader.load(Name);
this.myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete1);
}
private function attachImageToSprite2(Name:URLRequest):void
{
this.myLoader = new Loader();
this.myLoader.load(Name);
this.myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete2);
}
private function getImageBitmapDataFromSprite(srcImage:Sprite):BitmapData
{
var tmpBitmapData:BitmapData = new BitmapData(frontImage.width, frontImage.height, true, 0xFFCCCCCC);
tmpBitmapData.lock();
tmpBitmapData.draw(frontImage);
tmpBitmapData.unlock();
return tmpBitmapData;
}
private function isPixelAlpha(bitmapdata:BitmapData):Boolean
{
var pixelValue:uint = bitmapdata.getPixel32(mouseX, mouseY);
var alphaValue:uint = pixelValue >> 24 & 0xFF;
//var red:uint = pixelValue >> 16 & 0xFF;
//var green:uint = pixelValue >> 8 & 0xFF;
//var blue:uint = pixelValue & 0xFF;
return (alphaValue == 0x00) ? true : false;
}
private function deletePixelUnderMouse(bitmapdata:BitmapData, bitmap:Bitmap):void
{
bitmapdata.lock();
if ( !isPixelAlpha(bitmapdata) ) {
bitmapdata.setPixel32(mouseX, mouseY, 0xFF << 24); // how to make the current pixel's alpha
} // equal to zero.
bitmap = new Bitmap(bitmapdata);
bitmap.x = frontImage.x;
bitmap.y = frontImage.y;
this.frontImage.addChild(bitmap);
bitmapdata.unlock();
}
// events
public function onLoadComplete1(e:Event):void
{
frontImage.addChild(this.myLoader.content);
}
public function onLoadComplete2(e:Event):void
{
backImage.addChild(this.myLoader.content);
}
public function onMouseDown(e:MouseEvent):void
{
// delete a pixel from the sprite under the mouse
frontBitmapData = getImageBitmapDataFromSprite(frontImage);
deletePixelUnderMouse(frontBitmapData, frontBitmap);
frontImage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseDown);
trace("start");
}
public function onMouseUp(e:MouseEvent):void
{
frontImage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseDown);
trace("stop")
}
}
}
Not sure if I got it right, but if you want a 'reveal' effect, as in you draw a mask to display a hidden image for example, this could be achieved slightly easier:
var bitmapToReveal:BitmapData = new BitmapToReveal(0,0);
var brush:BitmapData = new Brush(0,0);
var canvasData:BitmapData = new BitmapData(bitmapToReveal.width,bitmapToReveal.height,true,0x00FFFFFF);
var cursor:Point = new Point();//used as destination point when painting
var zero:Point = new Point();//reused for painting
var reveal:Bitmap = new Bitmap(bitmapToReveal);
var canvas:Bitmap = new Bitmap(canvasData);
reveal.cacheAsBitmap = canvas.cacheAsBitmap = true;
addChild(reveal);
addChild(canvas);
reveal.mask = canvas;
stage.addEventListener(MouseEvent.MOUSE_DOWN, brushDown);
stage.addEventListener(MouseEvent.MOUSE_UP, brushUp);
function brushDown(event:MouseEvent):void {
this.addEventListener(Event.ENTER_FRAME, paint);
}
function brushUp(event:MouseEvent):void {
this.removeEventListener(Event.ENTER_FRAME, paint);
}
function paint(event:Event):void {
cursor.x = mouseX-brush.width*.5;
cursor.y = mouseY-brush.height*.5;
canvasData.copyPixels(brush,brush.rect,cursor,brush,zero,true);
}
I'm using two Bitmaps form the library(bitmapToReveal and brush).
The main thing to look at is the copyPixels() method. I copy
the brush bitmap into the canvas(an empty transparent bitmap data),
using the offset cursor position(so the brush centered), and using the
alpha channel to do that. Note that I've set cacheAsBitmap to true
for both mask and maskee. You need to do that to get a transparent mask,
which is key to the effect.
Here is the result:
You can 'paint' the mask here. CS4 Source is here.
HTH,
George