As3 magnify image - actionscript-3

I want to create a image magnify application like following:
A masked small window showig big image area corresponding to the mouse X and Y on the small image. There are many magnifying image application exaples online such as:
http://www.flashandmath.com/intermediate/magglass/mag_glass.html
But here the mouse and mask moves with same X and Y. What i want is that masked window display only certain area corresponding to mouse X and Y on Small image.
Any help would be highly appreciated. thanks.

i wrote a recipe last year for exactly what you're looking for. i do not guarantee that's it's as refactored or efficient as it could be, but it works really well. change it up as much as you like. i post the code hear for anyone to freely use.
however, the photograph and loupe asset i do not permit anyone to use without prior request, please.
the class lets you alter your own magnification strength, even at runtime if you want. you can use your own loupe graphic, but one is also included in the source files (please ask me first if you want to use it in your project).
Description:
Magnifier: Creating A Customizable
Magnifier For Image Assets
The following code demonstrates the
solution for creating a customizable
magnifier for image assets using the
Magnifier class.
The Magnifier constructor receives 6
parameters. The first
loupeDisplayObject:DisplayObject
required parameter is a reference to a
display object that is used as the
virtual loupe. In order for the class
to function properly, the
loupeDisplayObject:DisplayObject must
contain a circular or elliptically
shaped void or alpha transparency at
its center.
The second imageURL:String required
parameter supplies the URLLoader’s
load function’s URLRequest with the
URL of the target image asset. The
image provides BitmapData for both
thumbSprite:Sprite and
magnificationSprite:Sprite objects,
which are scaled using the third
thumbScale:Number and fourth
magnificationScale:Number optional
parameters. The scale of the
thumbSprite:Sprite is exhibited on
stage, while the scale of the
magnificationSprite:Sprite is visible
during magnification.
The Magnifier class operates by
employing mouse events to toggle the
visibility of a virtual loupe over an
image asset. A maskSprite:Sprite
ellipse, both indexed below and based
on the size of the
loupeDisplayObject:DisplayObject, is
created to mask the
magnificationSprite:Sprite. However,
the fifth maskWidth:Number and sixth
maskHeight:Number optional parameters
can be set to manually size a
maskSprite:Sprite that is more
suitable for a
loupeDisplayObject:DisplayObject with
a complex shape.
Calling the public deallocate()
function of the Magnifier instance
prior to its nullification will mark
it as being available for garbage
collection.
Class FIle:
package
{
import flash.display.Sprite;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.geom.Matrix;
import flash.net.URLRequest;
import flash.ui.Mouse;
import fl.transitions.Tween;
import fl.transitions.TweenEvent;
import fl.transitions.easing.Regular;
public class Magnifier extends Sprite
{
//Class Variables
private var loupeDisplayObject:DisplayObject;
private var imageWidth:Number;
private var imageHeight:Number;
private var thumbScale:Number;
private var magnificationScale:Number;
private var maskWidth:Number;
private var maskHeight:Number;
private var imageBitmapData:BitmapData;
private var maskSprite:Sprite;
private var magnificationSprite:Sprite;
private var thumbSprite:Sprite;
private var loupeTween:Tween;
private var magnificationTween:Tween;
//Constructor
public function Magnifier (
loupeDisplayObject:DisplayObject,
imageURL:String,
thumbScale:Number = 0.5,
magnificationScale:Number = 1.0,
maskWidth:Number = NaN,
maskHeight:Number = NaN
)
{
this.loupeDisplayObject = loupeDisplayObject;
this.thumbScale = Math.max(0.1, Math.min(thumbScale, 1.0));
this.magnificationScale = Math.max(0.1, magnificationScale);
this.maskWidth = maskWidth;
this.maskHeight = maskHeight;
init(imageURL);
}
//Load And Handle Image
private function init(imageURL:String):void
{
var imageLoader:Loader = new Loader();
imageLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageHandler);
imageLoader.load(new URLRequest(imageURL));
}
private function errorHandler(evt:IOErrorEvent):void
{
throw(evt.text);
}
private function imageHandler(evt:Event):void
{
evt.target.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
evt.target.removeEventListener(Event.COMPLETE, imageHandler);
imageWidth = evt.target.content.width;
imageHeight = evt.target.content.height;
imageBitmapData = new BitmapData(imageWidth, imageHeight);
imageBitmapData.draw(evt.target.content);
createComponents();
}
//Create Components
private function createComponents():void
{
//Loupe Visibility
loupeDisplayObject.alpha = 0;
//Mask
if (isNaN(maskWidth)) maskWidth = loupeDisplayObject.width;
if (isNaN(maskHeight)) maskHeight = loupeDisplayObject.height;
maskSprite = new Sprite();
maskSprite.graphics.beginFill(0x00FF00, 0.5);
maskSprite.graphics.drawEllipse(0, 0, maskWidth, maskHeight);
maskSprite.graphics.endFill();
maskSprite.mouseEnabled = false;
//Magnification
magnificationSprite = scaleImage(new Matrix(magnificationScale, 0, 0, magnificationScale));
magnificationSprite.mouseEnabled = false;
magnificationSprite.alpha = 0;
magnificationSprite.mask = maskSprite;
//Thumb
thumbSprite = scaleImage(new Matrix(thumbScale, 0, 0, thumbScale));
thumbSprite.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
//Add Components To The Display List
addChild(thumbSprite);
addChild(magnificationSprite);
addChild(maskSprite);
addChild(loupeDisplayObject);
}
private function scaleImage(matrix:Matrix):Sprite
{
var scaledResult:Sprite = new Sprite();
scaledResult.graphics.beginBitmapFill(imageBitmapData, matrix, false, true);
scaledResult.graphics.drawRect(0, 0, imageWidth * matrix.a, imageHeight * matrix.d);
scaledResult.graphics.endFill();
return scaledResult;
}
//Mouse Event Handlers
private function mouseDownHandler(evt:MouseEvent):void
{
thumbSprite.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
thumbSprite.addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
mouseMoveHandler(evt);
setLoupeAsVisible(true);
}
private function mouseMoveHandler(evt:MouseEvent):void
{
loupeDisplayObject.x = evt.localX - loupeDisplayObject.width / 2;
loupeDisplayObject.y = evt.localY - loupeDisplayObject.height / 2;
maskSprite.x = evt.localX - maskSprite.width / 2;
maskSprite.y = evt.localY - maskSprite.height / 2;
magnificationSprite.x = 0 - evt.localX / thumbSprite.width * (magnificationSprite.width - thumbSprite.width);
magnificationSprite.y = 0 - evt.localY / thumbSprite.height * (magnificationSprite.height - thumbSprite.height);
}
private function mouseOutHandler(evt:MouseEvent):void
{
thumbSprite.addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
setLoupeAsVisible(false);
}
private function mouseOverHandler(evt:MouseEvent):void
{
thumbSprite.removeEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
setLoupeAsVisible(true);
}
private function mouseUpHandler(evt:MouseEvent):void
{
if (thumbSprite.hasEventListener(MouseEvent.MOUSE_OVER)) thumbSprite.removeEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler);
thumbSprite.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
thumbSprite.removeEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler);
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
setLoupeAsVisible(false);
}
//Loupe Tween And Visibility
private function setLoupeAsVisible(response:Boolean):void
{
var targetAlpha:Number;
if (response)
{
targetAlpha = 1.0;
Mouse.hide();
}
else
{
targetAlpha = 0.0;
Mouse.show();
}
loupeTween = new Tween(loupeDisplayObject, "alpha", Regular.easeIn, loupeDisplayObject.alpha, targetAlpha, 0.25, true);
magnificationTween = new Tween(magnificationSprite, "alpha", Regular.easeIn, magnificationSprite.alpha, targetAlpha, 0.25, true);
}
//Clean Up
public function deallocate():void
{
thumbSprite.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
}
}
}

Related

Creating inline function after loading an image causes memory leak

I was analyzing an unexpected memory leak in our game project and found some strange results. I am profiling using Adobe Scout and eliminated all other factors like starling, texture or our loading library. I reduced the code to simply load a png and immediately allocate an empty inline function on its complete event.
Loading a png allocates image on default and if you do nothing after loading gc clears that image. But creating an inline function seems to prevent that image to be garbage collected somehow. My test code is;
public class Main extends Sprite
{
private var _callbacks:Array = new Array();
public function Main()
{
load("map.png", onPngLoaded);
}
private function onPngLoaded(bitmap:Bitmap):void
{
_callbacks.push(function():void { });
}
public function load(url:String, onLoaded:Function):void
{
var loader:Loader = new Loader;
var completeHandler:Function = function(e:Event):void {
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, completeHandler);
onLoaded(loader.content);
}
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loader.load(new URLRequest(url));
}
}
If you remove the code which creates an inline function;
private function onPngLoaded(bitmap:Bitmap):void
{
// removed the code here!
}
gc works and clears the image from memory.
Since having no logical explanation for this, I suspect of a flash / as3 bug. I will be glad to hear any comments who tests my code and gets the same results.
Note: To test, replace the main class of an empty as3 project with my code and import packages. You can load any png. I am using flashdevelop, flex-sdk 4.6.0 and flash player 14.
When you create an inline function, all local variables get stored with it in the global scope. So in this case, that would include the bitmap parameter.
For more information, see this:
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f54.html
Here is the relevant part:
Any time a function begins execution, a number of objects and properties are created. First, a special object called an activation object is created that stores the parameters and any local variables or functions declared in the function body....Second, a scope chain is created that contains an ordered list of objects that Flash Player or Adobe AIR checks for identifier declarations. Every function that executes has a scope chain that is stored in an internal property. For a nested function, the scope chain starts with its own activation object, followed by its parent function’s activation object. The chain continues in this manner until it reaches the global object.
This is another reason why inline/anonymous functions are best avoided in most situations.
So using asc2, Flash/Air 19 : Yes I get the same results that you are seeing, but due to the anonymous function holding global references I expected that (like my original comment stated).
I rewrote it in my style based upon Adobe's GC technical articles and bulletins and no leaks are seen as all the global references are removed.
A cut/paste AIR example:
package {
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.Loader;
import flash.events.Event;
import flash.net.URLRequest;
import flash.system.System;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Main extends Sprite {
var timer:Timer;
var button:CustomSimpleButton;
var currentMemory:TextField;
var highMemory:TextField;
var hi:Number;
var _callbacks:Array = new Array();
public function Main() {
button = new CustomSimpleButton();
button.addEventListener(MouseEvent.CLICK, onClickButton);
addChild(button);
currentMemory = new TextField();
hi = System.privateMemory;
currentMemory.text = "c: " + hi.toString();
currentMemory.x = 100;
addChild(currentMemory);
highMemory = new TextField();
highMemory.text = "h: " + hi.toString();
highMemory.x = 200;
addChild(highMemory);
timer = new Timer(100, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerHandler);
timer.start();
}
function timerHandler(e:TimerEvent):void{
System.pauseForGCIfCollectionImminent(.25);
currentMemory.text = "c: " + System.privateMemory.toString();
hi = System.privateMemory > hi ? System.privateMemory : hi;
highMemory.text = "h: " + hi.toString();
timer.start();
}
function onClickButton(event:MouseEvent):void {
for (var i:uint = 0; i<100; i++) {
//load("foobar.png", onPngLoaded);
load2("foobar.png");
}
}
private function onPngLoaded2(bitmap:Bitmap):void {
var foobarBitMap:Bitmap = bitmap; // assuming you are doing something
foobarBitMap.smoothing = false; // with the bitmap...
callBacks(); // not sure what you are actually doing with this
}
private function callBacks():void {
_callbacks.push(function ():void {
});
}
public function completeHandler2(e:Event):void {
var target:Loader = e.currentTarget.loader as Loader;
// create a new bitmap based what is in the loader so the loader has not refs after method exits
var localBitmap:Bitmap = new Bitmap((target.content as Bitmap).bitmapData);
onPngLoaded2(localBitmap);
}
public function load2(url:String):void {
var loader2:Loader = new Loader;
loader2.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler2, false, 0, true);
loader2.load(new URLRequest(url));
}
}
}
import flash.display.Shape;
import flash.display.SimpleButton;
class CustomSimpleButton extends SimpleButton {
private var upColor:uint = 0xFFCC00;
private var overColor:uint = 0xCCFF00;
private var downColor:uint = 0x00CCFF;
private var size:uint = 80;
public function CustomSimpleButton() {
downState = new ButtonDisplayState(downColor, size);
overState = new ButtonDisplayState(overColor, size);
upState = new ButtonDisplayState(upColor, size);
hitTestState = new ButtonDisplayState(upColor, size * 2);
hitTestState.x = -(size / 4);
hitTestState.y = hitTestState.x;
useHandCursor = true;
}
}
class ButtonDisplayState extends Shape {
private var bgColor:uint;
private var size:uint;
public function ButtonDisplayState(bgColor:uint, size:uint) {
this.bgColor = bgColor;
this.size = size;
draw();
}
private function draw():void {
graphics.beginFill(bgColor);
graphics.drawRect(0, 0, size, size);
graphics.endFill();
}
}

How can I use a document class in a single AS3 movie clip?

I have a confetti generator that I am tyring to add to a single movie clip within my flash file. The clip is masked and I want to have some graphics and text appear above the confetti (which will be above a background layer as well).
I purchased a decent script and have modified it to work with some original confetti artwork but I can't figure out how to use this class (or change it for use) in just the one movie clip. Pasting the class below. I've been stressing about this for a couple of hours now, any help would be greatly appreciated.
package com.pixeljunkyard
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import caurina.transitions.*;
import fl.motion.Color;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
public class Main extends Sprite
{
//Create Heart Instance
private var hearts:Heart;
//Amount of hearts
private var totalHearts:Number = 30;
//Falling Speed
private var speed:Number = 1.5;
//Constructor
public function Main()
{
//Align top left for screen aspect ratio
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
//Loop through the amount of heart to be created
for (var i = 0; i < totalHearts; i++)
{
//Create new heart
var heart = new Heart();
//Set Random value
var randScale:Number = randRange(50, 100);
var randRotation:Number = randRange( -180, 180);
var randRotationY:Number = randRange( -360, 360);
//Random position and scale
heart.x = randRange(0, stage.stageWidth);
heart.y = randRange( -stage.stageHeight, stage.stageHeight);
heart.scaleX = randScale/100;
heart.scaleY = randScale/100;
//Name each heart with the number of creation
heart.name = "heart" + i;
var Low : int = 1;
var High : int = 8;
var myRandomNumber:int = Math.floor(Math.random()*(1+High-Low))+Low;
heart.gotoAndStop(myRandomNumber);
//Add eventlisteners for interactions
heart.addEventListener(MouseEvent.ROLL_OVER, hit_heart);
heart.addEventListener(Event.ENTER_FRAME, change_shade);
//Initial Animation
Tweener.addTween(heart, {time:randRange(1,5)/speed, rotation:randRotation,rotationY:randRotationY,y:stage.stageHeight+(heart.height/2)+20, transition:"linear", onComplete:rebirth,onCompleteParams:[heart]} );
//Add to Stage
addChildAt(heart, i);
}
}
//Change shade to give lighting effect
private function change_shade(e:Event):void
{
//New color instance
var c:Color = new Color();
//Set properties
c.brightness = e.target.rotation / 300;
//Apply color to heart
e.target.transform.colorTransform = c;
}
//Random Function
private function randRange(min:Number, max:Number):Number
{
var randomNum:Number = Math.floor(Math.random() * (max - min + 1)) + min;
return randomNum;
}
//Interactive animation
private function hit_heart(e:Event):void
{
Tweener.addTween(e.target, { time:randRange(1,3), rotationY:e.target.rotationY+180 } );
}
//Reset heart to top of the screen once fallen
private function rebirth($heart:Heart):void
{
$heart.x = randRange(0, stage.stageWidth);
$heart.y = -$heart.height;
Tweener.addTween($heart, {time:randRange(1,5)/speed, rotation:randRange(-180,180),y:stage.stageHeight+($heart.height/2)+20, transition:"linear", onComplete:rebirth,onCompleteParams:[$heart]} );
}
}
}
Now I understand your problem.
First of all, I suggest to never write code on the timeline, except simple stuff like stop() or gotoAndPlay("loop").
The easiest way to achieve what you want is to do the following:
Make a blank MovieClip in Flash IDE Ctrl + F8
Give it a linkage like this:
Then click the edit button (marked with a red rectangle)
Open in Flash Professional if asked
Save the file in your .FLA directory and copy the contents of your Main.as file into this file
Remove the package name ("com.pixeljunkyard")
Change the public class Main extends Sprite to public class ConfettiContainer extends MovieClip and import flash.display.MovieClip
Now you have a class ConfettiContainer which does the same stuff that you Main.as file did. Don't forget to copy anything that this Main.as class uses from stage to your ConfettiContainer MovieClip.
You can now create and use it like this:
var confetti:ConfettiContainer = new ConfettiContainer();
addChild(confetti);
P.S. If you can't see Export for Actionscript option when creating a Symbol in Flash, click Advanced.

AS3 > Starting class on certain frame?

I created an AS file and used it as a class, inside it I called buttons and slideshow images.
After that I decided to create an intro by moving the timeline. My problem is that all the objects are displayed from the very first frame, is there a way to make the entire class start after certain frame?
Code for reference:
package {
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.MovieClip;
public class play extends MovieClip {
private var loader:Loader = new Loader();
private var images:Array = ["img/Layer_1.jpg", "img/Layer_2.jpg", "img/Layer_3.jpg", "img/Layer_4.jpg", "img/Layer_5.jpg", "img/Layer_6.jpg", "img/Layer_7.jpg", "img/Layer_9.jpg", "img/Layer_10.jpg", "img/Layer_11.jpg", "img/Layer_12.jpg", "img/Layer_13.jpg", "img/Layer_14.jpg"];
private var triangleButton:triangle = new triangle;
private var squareButton:square = new square;
private var crossButton:cross = new cross;
private var circleButton:circle = new circle;
public function play() {
loadNextImage();
addChild(loader);
loader.x = 137;
loader.y = 65;
//Buttons
addChild(triangleButton);
triangleButton.width = 28;
triangleButton.scaleY = triangleButton.scaleX;
triangleButton.x = 804;
triangleButton.y = 107;
triangleButton.addEventListener(MouseEvent.CLICK, slideGames);
addChild(circleButton);
circleButton.width = 28;
circleButton.scaleY = circleButton.scaleX;
circleButton.x = 825;
circleButton.y = 130;
circleButton.addEventListener(MouseEvent.CLICK, slideGames);
addChild(crossButton);
crossButton.width = 28;
crossButton.scaleY = crossButton.scaleX;
crossButton.x = 804;
crossButton.y = 155;
crossButton.addEventListener(MouseEvent.CLICK, slideGames);
addChild(squareButton);
squareButton.width = 28;
squareButton.scaleY = squareButton.scaleX;
squareButton.x = 780;
squareButton.y = 130;
squareButton.addEventListener(MouseEvent.CLICK, slideGames);
}
public function slideGames(event:MouseEvent):void {
loadNextImage();
}
public function loadNextImage() : void {
// Increment the image
_imageIndex++;
// If we've reached the end of the array, start over
if (_imageIndex >= images.length) {
_imageIndex = 0;
}
// Now get the image source from the array and tell the loader to load it
var imageSource : String = images[_imageIndex] as String;
loader.load(new URLRequest(imageSource));
}
// Next image to display
protected var _imageIndex : int = -1;
}
}
Yes, instead of initializing everything in the constructor of your class (play()), you can move it to another function, and call that from the timeline. I am assuming you are using the play class as the document class.
So instead of
public function play() {
you would rename it to
public function play_start() {
Create an empty constructor named play() at this point if you want to.
In the flash IDE, select the frame where you want the items to appear, then create a keyframe there.
Select the keyframe and go to the Actions panel (F9) and enter the following code:
this.play_start();
once the playhead is at the keyframe, your code should be executed.

Need some help completing a bumptop-ish selection tool

I'm in the midst of creating a Bumptop styled selection tool. Right now I got as far as creating the tool itself (which actually works pretty good) and spreading some random square items on the stage. This is the class that creates the selection tool :
package com.reyco1.medusa.selectiontool
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
public class SelectionBase extends Sprite
{
private var points:Array = [];
public function SelectionBase()
{
super();
addEventListener(Event.ADDED_TO_STAGE, initialize);
}
private function initialize(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, initialize);
points.push(new Point(mouseX, mouseY)); stage.addEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
}
private function handleMouseMove(e:MouseEvent):void
{
graphics.clear();
graphics.beginFill(0x33CCFF, .5);
graphics.drawCircle(0, 0, 20);
graphics.endFill();
graphics.moveTo(0, 0);
graphics.lineStyle(1.5, 0x33CCFF, .5);
graphics.lineTo(mouseX, mouseY);
points.push(new Point(mouseX, mouseY));
graphics.beginFill(0x33CCFF, .1);
graphics.moveTo(points[0].x, points[0].y);
for (var i:uint = 1; i < points.length; i++)
{
graphics.lineTo(points[i].x, points[i].y);
}
graphics.lineTo(points[0].x, points[0].y);
graphics.endFill();
dispatchEvent(new Event("UPDATE"));
}
public function clear():void
{
stage.removeEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
graphics.clear();
}
}
}
And this is the document class that implements it :
package
{
import com.reyco1.medusa.selectiontool.SelectionBase;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
[SWF(width = '1024', height = '768', backgroundColor = '0x000000')]
public class SelectionToolPrototype extends Sprite
{
private var selectionTool:SelectionBase;
public function SelectionToolPrototype()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.quality = StageQuality.MEDIUM;
stage.addEventListener(MouseEvent.MOUSE_DOWN, handleDown);
stage.addEventListener(MouseEvent.MOUSE_UP, handleUp);
placeShapesRandomly();
}
private function placeShapesRandomly():void
{
for(var a:Number = 0; a<25; a++)
{
var s:Sprite = new Sprite();
s.graphics.beginFill(Math.random() * 0xCCCCCC);
s.graphics.drawRect(0, 0, 50, 50);
s.graphics.endFill();
s.x = Math.floor(Math.random() * 900 - 40) + 40;
s.y = Math.floor(Math.random() * 700 - 40) + 40;
s.rotation = Math.floor(Math.random() * 360 - 40) + 40;
s.buttonMode = true;
addChild(s);
}
}
private function handleUp(e:MouseEvent):void
{
selectionTool.removeEventListener("UPDATE", handleToolUpdate);
removeChild(selectionTool);
selectionTool = null;
}
private function handleDown(e:MouseEvent):void
{
selectionTool = new SelectionBase();
selectionTool.addEventListener("UPDATE", handleToolUpdate);
selectionTool.x = mouseX;
selectionTool.y = mouseY;
addChild(selectionTool);
}
private function handleToolUpdate(e:Event):void
{
// logic to determin if items are within selection goes here
}
}
}
I've tried using collision detection by means of BitmapData and even using collision libraries like CDK but I cant get anything to work. Anybody have an idea what I should use in the handleToolUpdate(e:MouseEvent); ? Thanks!
Update:
I'll break it down. Basically I am trying to create a prototype of the BumpTop Lasso or Selection tool.
I need help in finding out which objects either collide or have a point within the bounds of the drawn lasso.
I have upload what I have so far to my server here : http://labs.reyco1.com/bumptop/SelectionToolPrototype.html. You can see the source by right clicking and selecting "View Source".
Like I said in my earlier post, I tried using Bitmapdata collision testing and even tried using the Collision Detection Kit to no avail. Thanks in advance.
Loop through the display object you are attaching your random sprites to, and using for each, check their value of hitTestObject against your selectionTool instance.
Here are the Adobe docs for hitTestObject():
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#hitTestObject%28%29

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