AS3 Instance Name of a custom class - actionscript-3

I'm trying to get the instance name from a dropTarget of an object.
import flash.display.Sprite;
import flash.events.MouseEvent;
import com.components.DragDropBucket;
var circle:Sprite = new Sprite();
circle.graphics.beginFill(0xFFCC00);
circle.graphics.drawCircle(0, 0, 40);
var target:Array = new Array();
target[0] = new Sprite();
target[0].graphics.beginFill(0xCCFF00);
target[0].graphics.drawRect(0, 0, 100, 100);
target[0].name = "target1";
target[1] = new Sprite();
target[1].graphics.beginFill(0xCCFF00);
target[1].graphics.drawRect(0, 200, 100, 100);
target[1].name = "target2";
var testv:DragDropBucket = new DragDropBucket("test", 500, 500, 175, 40,false);
testv.name ="test2";
var test:DragDropBucket = new DragDropBucket("test", 0, 0, 175, 40,true);
addChild(target[0]);
addChild(target[1]);
addChild(circle);
addChild(testv);
addChild(test);
circle.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown)
function mouseDown(event:MouseEvent):void {
circle.startDrag();
}
circle.addEventListener(MouseEvent.MOUSE_UP, mouseReleased);
function mouseReleased(event:MouseEvent):void {
circle.stopDrag();
trace(circle.dropTarget.name);
}
DragDropBucket is a custom class that extends Sprite Class.
So when I execute this code, when I drop the circle to target[0] or target[0] it successfully output "target1" and "target2".
Meanwhile when im drop the circle to testv object, the program output its name as instance#
Yet when I execute this code
trace(testv.name);
It prints "test2" well, no instance# or anything.
I'm not understand what is happening here, since DragDropBucket Class only extending the Sprite class and have nothing fancy. Maybe someone here can enlighten me, Thanks.

Your DragDropBucket class is not different of a library class. It's the same logic. There's an object contained in 'testv', your instance of DragDropBucket class, that is being detected as dropTarget.
function mouseReleased(event:MouseEvent):void {
circle.stopDrag();
trace(circle.dropTarget.name, circle.dropTarget.parent.name);
// output : instance1, test2
}
If 'test2' is not the parent of 'instance1', that's its parent.parent, or more.

Related

Changing class properties in AS3

Okay, so I've recently been trying to get my head properly around OOP in AS3. Right now I have a really simple scenario where I've got a class, Paddle, which draws a rectangle. In my document class I create two instances of the Paddle class, paddle1 and paddle2.
I've also created a property for my Paddle class which I want to change the colour of the rectangle that it draws. I want to be able to adjust this property from the main class. I know I could do this by passing in attributes when instantiating the class but it seems like a property would be a better way, and now I want to know if this is the right way of thinking or not.
main class:
package
{
import flash.display.Sprite;
import flash.events.Event;
public class Engine extends Sprite
{
private var paddle1:Paddle = new Paddle();
private var paddle2:Paddle = new Paddle();
public function Engine()
{
paddle1.x = 30;
paddle1.color = 0xFF00FF;
stage.addChild(paddle1);
paddle2.x = stage.stageWidth - 45;
paddle2.color = 0xFF0000;
stage.addChild(paddle2);
}
}
}
Paddle class:
package
{
import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Graphics;
import flash.events.Event;
public class Paddle extends MovieClip
{
public var color:uint = 0xFFFFFF;
public function Paddle()
{
var child:Shape = new Shape();
child.graphics.beginFill(color);
child.graphics.drawRect(0, 260, 15, 80);
child.graphics.endFill();
addChild(child);
}
}
}
If changing the properties in this way is not the best way of doing things then of course say so. Otherwise, what am I doing wrong that it doesn't work? Seems like it's something to do with the order (by the time the main class changes the colour attribute, it's already created the rectangle and it's too late to change it?)
Thanks :D
EDIT: realised it might help to say what happens when I execute this code. Basically changing the color attribute from the Engine class doesn't change the colour of the rectangle and they both just stay white (FFFFFF)
The issue you're having is that when you do:
new Paddle();
Your constructor code is run. What this means is that the Rectangle has already been drawn with the color defined at the top of the class. You're then changing the color property after this, which as you can see has no effect.
I suggest you make a draw() function for your Paddle. It could accept a color and be used to draw the Rectangle. It might look like this:
public class Paddle extends MovieClip
{
private var _child:Shape;
public function Paddle()
{
_child = new Shape();
addChild(_child);
}
public function draw(color:uint):void
{
_child.graphics.clear();
_child.graphics.beginFill(color);
_child.graphics.drawRect(0, 260, 15, 80);
_child.graphics.endFill();
}
}
This way provides an advantage which is that you can modify the arguments of draw() to accept dimensions for your Rectangle or other elements that will affect the visuals. This will be cleaner and faster than having to add more properties to the class itself if you decide you want to do this.
You're then able to do this:
var paddle1:Paddle = new Paddle();
var paddle2:Paddle = new Paddle();
paddle1.draw(0xFF00FF);
paddle2.draw(0xFF0000);
What you might do is to allow the constructor to assign a color in addition to creating a setter for the color, having both calls subsequently drawing the paddle (which, by the way, could also be a simple flash.display.Shape):
Paddle.as:
package
{
//Imports
import flash.display.Sprite;
//Class
public class Paddle extends Sprite
{
//Constants
private static const DEFAULT_COLOR:uint = 0xFF0000;
//Properties
private var mColor:uint;
//Constructor
public function Paddle(color:uint = DEFAULT_COLOR)
{
mColor = color;
draw();
}
//Draw
private function draw():void
{
graphics.clear();
graphics.beginFill(mColor);
graphics.drawRect(0, 0, 15, 80);
graphics.endFill();
}
//Set Color
public function set color(value:uint):void
{
mColor = value;
draw();
}
//Get Color
public function get color():uint
{
return mColor;
}
}
}
so now you can create and position as many Paddle instances as you want, each having their own color setter:
Red Instance:
var paddleRed:Paddle = new Paddle();
paddleRed.y = 10;
addChild(paddleRed);
Green Instance:
var paddleGreen:Paddle = new Paddle(0x00FF00);
paddleGreen.y = 126;
addChild(paddleGreen);
Blue Instance:
var paddleBlue:Paddle = new Paddle();
paddleBlue.color = 0x00FF00;
paddleBlue.y = 260;
addChild(paddleBlue);
Why not do both? :D
public class Paddle extends MovieClip
{
private var color:uint;
private var rec:Shape;
public function Paddle(newColor:uint = 0xFFFFFF) // default color
{
color = newColor;
rec = new Shape();
drawShape();
addChild(rec);
}
public function drawShape()
{
child.graphics.clear();
child.graphics.beginFill(color);
child.graphics.drawRect(0, 260, 15, 80);
child.graphics.endFill();
}
public function setColor(newColor:uint)
{
color = newColor;
drawShape();
}
}

How to use hitTestObject on many objects

I can check if one object is hiting another, but what if I have 10 MovieClip objects, and i want to check if any object is hiting ANY object:
package {
import flash.display.MovieClip;
import flashx.textLayout.events.DamageEvent;
import fl.motion.Animator;
import flash.geom.Point;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
import flash.geom.ColorTransform;
public class Test extends MovieClip {
private var arrows:Array;
private var timer:Timer;
public function Test() {
init();
}
private function init():void {
timer = new Timer(1000, 6);
timer.addEventListener(TimerEvent.TIMER, timerEvent);
arrows = new Array();
timer.start();
}
private function timerEvent(e:TimerEvent):void{
var arrow:Arrow = new Arrow();
arrow.x = 5;
arrow.y = Math.random() * 200 + 10;
addChild(arrow);
arrow.addEventListener(Event.ENTER_FRAME, onEnterFrame);
arrows.push(arrow);
//trace(555);
}
private function onEnterFrame(e:Event):void{
e.target.x += 4;
if(e.target.x > 400)
{
e.target.transform.colorTransform = new ColorTransform(0, 0, 1, 1, 0, 0, 1, 1);
e.target.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
e.target.addEventListener(Event.ENTER_FRAME, goBack);
}
}
private function goBack(e:Event):void {
e.target.x -= 4;
if(e.target.x < 50)
{
e.target.transform.colorTransform = new ColorTransform(1, 1, 1, 1, 0, 0, 1, 1);
e.target.removeEventListener(Event.ENTER_FRAME, goBack);
e.target.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
}
}
}
how can i check if any arrow is touching other arrow object?, doesn't matter what object,I need something like hitTestGlobal
At least you can all objects hitting one point by using method DisplayObjectContainer.getObjectsUnderPoint(point:Point). If boundaries of your main object is not changing you can predefine edge points that you will hit testing every EnterFrame event.
Yes. You will have to check hit test on every object you need. And yes, it's a costy operation, but when writing games there's no other workaround. Try using Vector instead of an Array for a little performance boost, as Vector is type dependant array and it uses less memory. You can check the syntax HERE.
You'd instantiate it like this:
private var arrows:Vector.<Arrow> = new Vector.<Arrow>();

How to send image data to a custom class?

I'm trying to create a custom class that will create a tile (a small rounded square) when requested, with a small image on it. I can successfully create the tile, as shown in the code below, but I don't know how to pass the class the pictures data.
Is it possible to do this using bitmapData, or by referancing it throught the library (if i store my picture in a movieclip in the library?
Here is my class so far:
package com{
import flash.display.MovieClip;
import fl.transitions.Tween;
import fl.transitions.easing.Strong;
public class tileCreator extends MovieClip{
public var tiled:MovieClip;
public var sourceImage:MovieClip = new MovieClip;
public function tileCreator() {
trace("tile creator");
tiled = new MovieClip;
tiled.graphics.beginFill(0x666666, 0.3);
tiled.graphics.drawRoundRect(-55/2, -55/2, 55, 55, 15, 15);
this.addChild(tiled);
}
}
}
yes, it's possible using BitmapData.
import an image to the library and right-click it to change "settings ...".
you have to check "export for actionscript" and put a name into the second textfield underneath the checkbox - let's say 'MyImage'. (flash automatically adds the base-class of type flash.display.BitmapData).
then you can create an instance of the image saying:
var myImage:MyImage = new MyImage();
it's a BitmapData object, because your MyImage class extends BitmapData.
then you just have to add the BitmapData to the constructor as an argument (rename your class to Tile, because it's not a creator but the tile itself you create. and use a capital letter!).
public class Tile extends MovieClip
{
public function Tile (img:BitmapData)
{
var bmp:Bitmap = new Bitmap(img);
addChild(bmp);
tiled = new MovieClip;
tiled.graphics.beginFill(0x666666, 0.3);
tiled.graphics.drawRoundRect(-55/2, -55/2, 55, 55, 15, 15);
addChild(tiled);
bmp.mask = tiled;
}
}
you need to do it in the folowin way:
function createBitmap ( yourMovieClipYouWantToBeAsImage : DisplayObject ) : Bitmap
{
var bitmapData:BitmapData = new BitmapData ( width, height );
bitmapData.draw ( yourMovieClipYouWantToBeAsImage );
var bitmap:Bitmap = new Bitmap ( bitmapData );
return bitmap; // do what ever you want with it but now as an image
}
You can create a "snapshot" of this using bitmapData. You can then pass this to any other class you want. Code is shown below.
//This code goes into your TileCreator-class
public function draw():BitmapData
{
//True and 0 at the end of creating this bitmap ensure transparancy
//for the transparant pixels (else these would be opaque)
var bmp:BitmapData = new BitmapData(width, height, true, 0);
bmp.draw(this);
return bmp;
}

How to merge two bitmaps into one bitmap and save it to local drive

I've searched a lot but nothing seems working for me. Assistance of somebody is very much appreciated in this regard. Thanks a lot. I'm new to AS3. I'm using FlashDevelop. Below is the code I used,
package
{
import flash.display.Loader;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.net.URLRequest;
import flash.events.MouseEvent;
import flash.utils.ByteArray;
import flash.net.FileReference;
import com.adobe.images.JPGEncoder;
import flash.geom.Rectangle;
public class Main extends Sprite
{
private var modelBmp : BitmapData;
private var alphaBmp : BitmapData;
private var destPoint : Point = new Point(0, 0);
private var mask1:Loader = new Loader();
private var mask2:Loader = new Loader();
private var f:Bitmap;
private var fileReference:FileReference = new FileReference();
private var movie:MovieClip = new MovieClip();
private var loadedimage:Bitmap;
private var loadedimage1:Bitmap;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
if (loadAssets()) {
trace('merge loaded');
modelBmp = new BitmapData(loadedimage.width, loadedimage.height);
modelBmp.draw(loadedimage);
alphaBmp = new BitmapData(loadedimage1.width, loadedimage1.height);
alphaBmp.draw(loadedimage1);
var rect:Rectangle = new Rectangle(0, 0, 200, 200);
var pt:Point = new Point(20, 20);
var mult:uint = 0x80; // 50%
modelBmp.merge(alphaBmp, rect, pt, mult, mult, mult, mult);
var bm1:Bitmap = new Bitmap(modelBmp);
addChild(bm1);
bm1.x = 400;
var bm2:Bitmap = new Bitmap(alphaBmp);
addChild(bm2);
bm2.x = 200;}
}
private function loadAssets():void
{
mask2.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete1);
mask1.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
mask2.load(new URLRequest("Photo.png"));
mask1.load(new URLRequest("back.png"));
trace('asset loaded');
}
private function loadComplete(event:Event):void
{
loadedimage = Bitmap(mask1.content)
var bitmap:BitmapData = new BitmapData(loadedimage.width, loadedimage.height, false, 0xffffffff);
bitmap.draw(loadedimage, new Matrix())
var image:Bitmap = new Bitmap(bitmap);
//addChild(image);
trace('image1 loaded');
}
private function loadComplete1(event:Event):void
{
loadedimage1 = Bitmap(mask2.content)
var bitmap:BitmapData = new BitmapData(loadedimage1.width, loadedimage1.height, false, 0xffffffff);
bitmap.draw(loadedimage1, new Matrix())
var image:Bitmap = new Bitmap(bitmap);
//addChild(image);
trace('image2 loaded');
}
}
}
How to use Bitmap.merge():
var bitMapData1:BitmapData = new BitmapData(100,100); //or embedded item
var bitMapData2:BitmapData = new BitmapData(100,100); // "
var bitmap:Bitmap = new Bitmap(bitMapData1);
this.addChild(bitmap);
bitmap.merge(bitMapData2, new Rectangle(0, 0, 100, 100), new Point(0, 0), 128, 128, 128, 128);
As others have noted, Flash is forbidden from creating, altering, modifying, saving or otherwise manipulating files. There are several ways of getting this data out of flash and into a technology that has these abilities (such as PHP), or you can use the flash.filesystem package in Air (as previously noted).
Hope that helps =
= update =
Your code is problematic in that you are writing your urlRequest and then acting upon the loaded content in one function. The URL request simply hasn't had time to fire, and the rest of your function fails, because Mask2.content == undefined or null... I'm surprised it doesn't throw an error.
Other than that, it looks like it should work.
Try this:
private var _mask1:Loader; // _lowerCase naming convention
//constructor... call init()
//init.. call loadAssets()
private function loadAssets():void
{
_mask1 = new Loader(); //generally not a good idea to create objects when declaring variable
_mask1.addEventListener(Event.COMPLETE, onCompleteFunction);
_mask1.load(new URLRequest("Dress04.png"));
private function onCompleteFunction(e:Event):void
{ ...
Note that since you are doing multiple loads, you will need to check if both are loaded before acting upon the loaded content. You can do this with a simple boolean check or... whatever. You might also check out something like LoaderMax, which has built in load queueing like this.
Note also that good asset loading usually involves a try...catch statement and the handling of several events - IOErrorEvent.IO_ERROR , for example.
= update 2 =
Okay - we're just getting into programming logic now.
This is a problem:
private function init(e:Event = null):void
{
if (loadAssets()) {
trace('merge loaded');
//...
//...
private function loadAssets():void
{...
You're essentially asking loadAssets() to a return a value, but its return type is void, and so will absolutely fail. Besides that, the loadAssets() is only instigating the loader, and not tracking whether the load was successful.
Lets break it into a few more steps, and set up a really simple loading queue:
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.net.URLRequest;
public class Main extends Sprite
{
private var modelBmp : BitmapData;
private var alphaBmp : BitmapData;
private var destPoint : Point;
private var mask : Loader;
private var f : Bitmap;
private var movie : MovieClip;
private var loadedImages: Array;
private var imageQueue : Array;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
//initialize variables
private function init(e:Event = null):void
{
//just set up a simple queue of images to load
imageQueue = ['Photo.png', 'back.png'];
loadedImages = [];
destPoint = new Point(0, 0);
mask = new Loader();
movie = new MovieClip();
loadAsset( imageQueue[0] );
}
private function loadAsset(target:String):void
{
mask.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
mask.load(new URLRequest(target));
}
private function loadComplete(event:Event):void
{
loadedimage = Bitmap(mask.content);
var bitmap:BitmapData = new BitmapData(loadedimage.width, loadedimage.height, false, 0xffffffff);
bitmap.draw(loadedimage, new Matrix())
var image:Bitmap = new Bitmap(bitmap);
loadedImages.push(image);
mask.unload();
trace(imageQueue[0] + " loaded");
imageQueue.splice( 0, 1); //remove the first index
if (imageQueue.length > 0){
loadAsset(imageQueue[0]);
}else{
mergeImages(); //if the queue is empty, then merge
}
}
private function mergeImages():void
{
modelBmp = new BitmapData(Bitmap(loadedImages[0]).width, Bitmap(loadedImages[0]).height);
modelBmp.draw(loadedimage);
alphaBmp = new BitmapData(Bitmap(loadedImages[1]).width, Bitmap(loadedImages[1]).height);
alphaBmp.draw(loadedimage1);
var rect:Rectangle = new Rectangle(0, 0, 200, 200);
var pt:Point = new Point(20, 20);
var mult:uint = 0x80; // 50%
modelBmp.merge(alphaBmp, rect, pt, mult, mult, mult, mult);
var bm1:Bitmap = new Bitmap(load);
addChild(bm1);
bm1.x = 400;
var bm2:Bitmap = new Bitmap(alphaBmp);
addChild(bm2);
bm2.x = 200;}
}
}
I haven't checked to see if this works, so it might take a little messing with, the but basic idea should work for you. There are a bunch of ways to deal with chained conditional asset loading, this is a simple example.
Hope that helps -
This might seem a bit on the nose, but you can use the merge() method of the BitmapData class to merge two bitmaps images into one. There's an example using the merge() method at those links.
As far as saving to a local disk goes, Flash Player allows access to the file system using the FileReference class. The FileReference class has the save() method, which prompts the user to browse for a location on their file system.
For Air applications, you can access the file system by using the classes in the flash.filesystem package.

Limit display object's drag coordinates in AS3

how can i reference a display object's coordinates according to it's parent object or stage from within the class that creates the object?
essentially when i create a new sprite object from a custom class and add it to the display list, i'd like to include code within the custom class that limits the drag coordinates to the stage, or a section of the stage.
//Frame Script
import Swatch;
var test:Sprite = new Swatch();
addChild(test);
___________________
//Custom Class
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Swatch extends Sprite
{
public function Swatch()
{
init();
}
private function init():void
{
var swatchObject:Sprite = new Sprite();
swatchObject.graphics.beginFill(0x0000FF, 1);
swatchObject.graphics.drawRect(100, 100, 150, 150);
swatchObject.graphics.endFill();
swatchObject.addEventListener(MouseEvent.MOUSE_DOWN, onDrag, false, 0, true);
swatchObject.addEventListener(MouseEvent.MOUSE_UP, onDrop, false, 0, true);
this.addChild(swatchObject);
}
private function onDrag(evt:MouseEvent):void
{
evt.target.startDrag();
//how to limit it's dragability to the Stage?
}
private function onDrop(evt:MouseEvent):void
{
evt.target.stopDrag();
}
}
}
There is some native support for what you want to do. startDrag() accepts a rectangle as a parameter which restricts the region in which the drag can take place.
function startDrag(lockCenter:Boolean = false, bounds:Rectangle = null):void
Hope that helps,
Tyler.