AS3 cloning an object - actionscript-3

I've an object contain all types of data
var obj1:Object={boo:true,num:0,str:"me",arr:[0,"me2",[0,1]],mc:myMc,obj:{boo:false,num:0,str:"me3",arr:[0,"me4",[0,1]]}};
when I clone this object to obj2 using ByteArray with writeObject(obj1)& readObject()properties, everything is fine except obj2.mc (mc is a variable that hold the linkage of a movie clip in the library whose class is set to myMc) can not be added to stage,
addChild(new obj2.mc)
//TypeError: Error #1007: Instantiation attempted on a non-constructor.
Help please!!

You cannot duplicate movie clips that easy. It should be something similar to:
var objectClass:Class = Object(obj2.mc).constructor;
var instance:MovieClip = new objectClass() as MovieClip;
It would be much easier if you pass a Class rather than instance. In your case, that should be myMc - the class name of the object that is in the library, right?
If so, you can simply instantiate it directly: var instance:MovieClip = new myMc();
The important think to remember is that you don't need to hold reference to an instance, but the class instead!

Guys After 2 hours of experimenting, I came out with this, This is simply the perfect solution... I changed to another way than using ByteArray, which is writing each variable in obj2 to its corresponding value in obj1, but faced another problem: when I change arrays in obj2, I found that arrays in obj1 is changed too, this means when writing variables of obj2, arrays were only referenced to that of obj1.. so I had to loop through arrays to write each value in an array individually..
var obj1:Object={mc:myMc,bo:true,num:0,str:"me",arr:[myMc,true,0,"me2",[0,1,[0,1]]],obj:{mc:myMc,bo:false,num:0,str:"me3",arr:[myMc,true,0,"me4",[0,1]]}};
var obj2:Object=clone(obj1);
function clone( source:Object ):* {
var myOBJ:Object=new Object();
for (var property in source) {
if (source[property] is Array) {
myOBJ[property]=clone(source[property]);
} else {
myOBJ[property]=source[property];
}
}
return (myOBJ);
}
Thanks for all, you've inspired me..

Related

AS3 MovieClip name ambiguity

Summary: I create instances of various MovieClips via AS3, using MovieClip class objects that are defined in the library.
As each MC is instantiated, I push it into an array for later reference.
Finally I create an XML file that contains data related to each MC, including its name. This is the problematic part – the name has to be able to identify the respective MC when the XML is read back in. I don’t want “instance17” etc, which I assume will be meaningless in another session.
Background: I am not a career OO programmer and this is a temporary assignment, forming only a very small part of my long-term interests. It will probably be a couple of years before my next Flash project.
Create instance
Library object
Type: MovieClip, linkage _brakepipe
Instantiation
var brakepipe: _brakepipe = new _brakepipe();
shapes.push(brakepipe);
Then later
var clip: MovieClip = shapes(i);
Trace (clip);
This yields
[object _breakpipe]
So it is giving me the class name, not the MC instance name. What property or method of MC would yield “breakpipe”? (Or even "_breakpipe" - without the "object" prefix?)
You can use an associative array. It could look like this:
var shapes:Array = new Array();
and then
shapes.push({item:_brakepipe,_name:"brakepipe"};
Essentially the curly brackets create an Object instance and the name before the colon (:) is the name you create that you want associated with the value after the colon.
so now you can do this in a loop
trace(shapes[i]._name+"\n"+shapes[i].item);
// output:
// brakepipe
// [object _brakepipe]
The nice thing about this method is you can extend it for any number of properties you want to associate with your array element, like this:
shapes.push({item:_brakepipe,_name:"brakepipe",urlLink:"http://www.sierra.com",_status:"used",_flagged:"false"};
and now
shapes[i]._status
would return the string "used". And you could change that value at runtime to "new" by doing
shapes[i]._status = "new";
The Instantiation / Then later / This yields... Seems to be unclear for me, but you may try this and change the code...
Because I'm not sure not sure about the instance name you want to store...
In your loop you may do this if clip is a MovieClip! :
var clip: MovieClip = shapes(i);
clip.name = "breakpipe_" + i
trace (clip.name);
// will output : breakpipe_1 - > breakpipe_n...
You may deal with the clip.name later by removing the extra "_number" if you want.
If i == 13
var clip: MovieClip = new MovieClip();
clip.name = "breakpipe_" + 13
trace(clip.name);
// output breakpipe_13
var pattern:RegExp = /_\d*/g;
trace(clip.name.replace(pattern,""));
//output :
//breakpipe
So here, you may push your Array or Vector with the instance name.
Am I wrong?

ActionScript 3 - use [brackets] instead of getChildByName

I have a MovieClip inside library, linkaged to MyObject and it contains a textField.
I don't know how I can access this textField without using the getChildByName method.
Apparently, the 3rd section works when object is on stage (without using addChild). But when using addChild I think there has to be some kind of casting; which I don't know how.
var childElement: MyObject = new MyObject();
childElement.name = "theChildElement";
container.addChild(childElement);
btn.addEventListener(MouseEvent.CLICK, changeText);
function changeText(event: MouseEvent): void
{
var targetBox:MovieClip = container.getChildByName(childElement.name) as MovieClip;
targetBox.textField.text = "hello"; // THIS WORKS
// This works too:
// MovieClip(container.getChildByName("theChildElement"))["textField"].text = "hello"; // THIS WORKS TOO.
// THIS DOESN'T WORK. why?
// container["theChildElement"]["textField"].text = "hello";
}
As confusing as it may seem, instance name, and name are not the same. From your code you should always be able to get to your MC by it's variable name. To get your last like to work you could just use this.
childElement["textField"].text = "hello";
There is a difference between Symbols created by the Flash IDE, which aggregate other DisplayObjects and programmatically created DisplayObjects.
When a DisplayObject is created in the Flash IDE, it's instance name can be used to resolve the instance as a property - which means it can be accessed via []. The [] can be used to access properties or keys of dynamic declared classes - like MovieClip. This necessary because you'll most likely down cast to MovieClip instead of using the symbol class created by Flash. That is not possible when simply using addChild, addChildAt or setChildAt from the DisplayObjectContainer API.
It is always the save way to access it via getChildByNameand check for null because otherwise your app, website or whatever is doomed for 1009 errors as soon as someone is changing the symbols.
I'd create a bunch of helper methods, like
// not tested
function getChildIn(parent:DisplayObjectContainer, names:Array):DisplayObject {
var child:DisplayObject, name:String;
while (names.length > 0) {
name = names.shift();
child = parent.getChildByName(name);
if (!child) {
// log it
return null;
}
if (names.length == 0) {
return child;
}
}
// log it
return null;
}
function getTextFieldIn(parent:DisplayObjectContainer, names:Array):TextField {
return getChildIn(parent, names) as TextField;
}
function getMovieClipIn(parent:DisplayObjectContainer, names:Array):MovieClip {
return getChildIn(parent, names) as MovieClip;
}
Your third method doesn't work because you are trying to call the ChildElement by it's name
without using getChildByName method. On the other hand, you shouldn't call your textField textField, because that's already an actionScript property.
Your should rather call it 'displayText' for example.
For a textField called 'displayText' contained in childElement :
function changeText(event:MouseEvent): void
{
childElement.displayText.text = "hello";
}

ActionScript:ArrayCollection declaration

I am new to ActionScript and Flex.I need to learn the application developed using Flex and ActionScript.I saw an ArrayCollection declaration :
[Bindable]
public var someThing:ArrayCollection = new ArrayCollection([[]]);
What does that declaration mean.Is it multi dimensional?What is it?
This would be an ArrayCollection which is a wrapper for an Array basically to give you sort and filter function capabilities (and other methods). The constructor optionally takes an Array as an argument, [] is a new array with no elements. [[]] is an array with one element in it that is an array with no elements in it. So this is saying make a new ArrayCollection with it's source as an array which in turn contains one element that is an empty array. Not sure why they would be doing this, but that's what it does.
To sum up, you can declare and instantiate an array in AS3 like:
var myArray:Array = [];
or
var myArray:Array = new Array();
To add since this is I believe ECMAScript specific as well you can instantiate an object similarly using {}. Such as:
var myObj:Object = {};
or
var myObj:Object = new Object();
Either of these sites is good reference material for AS3:
http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7ee5.html#WS5b3ccc516d4fbf351e63e3d118a9b90204-7ee1
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Array.html
When I first got started with Flex (having a background in HTML/JS, C, C++, and Java) I found these videos to be really useful (if not always 100% correct/up to date, they explain the overarching concepts):
http://www.adobe.com/devnet/flex/videotraining.html

How do I reference an object, add a tween to it and put this in an Eventlistener in AS3?

I'm having quite some trouble to try and get an app I wrote in AS2 to AS3. The reason I need to go to AS3 is something icky, so I won't go into detail about it.
I've got 90% of the application running with the new code.
Now I've come to the point where I have to convert this code from AS2,
function setAnimation(theObject,id)
{
theObject.vensterid=id;
theObject.onEnterFrame = function()
{
var myHoriTween:Tween = new Tween (this,"_x",Strong.easeOut,this._x,(130+((theObject.vensterid-frameno)*260)),1,true);
}
}
setAnimation(venster0,0);
, to AS3. My attempt of doing this ended up like
function setAnimation(anObject,id) {
var theObject = this[anObject];
theObject.vensterid=id;
function slideHorizontal(event:Event)
{
var myTween:Tween = new Tween (theObject,"x",Strong.easeOut,this.x,(130+((theObject.vensterid-frameno)*260)),1,true);
}
theObject.addEventListener(Event.ENTER_FRAME,slideHorizontal);
}
setAnimation(venster0,0);
and gives me the following non-error (it doesn't show as a compiler error, but as output):
TypeError: Error #1010: A term is undefined and has no properties.
at sliding_windows_as3_fla::SlideMenu_1/setAnimation()
at sliding_windows_as3_fla::SlideMenu_1/frame1()
I think this is very strange since it doesn't say anything about which term (and there are quite a lot) and googling didn't find me an explanation either.
I didn't get the chance to test your code, because it's difficult to set up a context for it, but my thoughts would be:
You should declare the parameter types: function setAnimation(anObject:Object,id:uint):void. It's at least good practice.
var theObject = this[anObject]; is completely unnecessary if your variable anObject is an object. I think var theObject = this[anObject]; doesn't work, theObject ends up being null and that's why you get your error. If you have declared a variable called venster0, that is the instance of a class that extends Object, then you can pass the reference to it without any other trouble.
Depending on the object you work with, theObject.vensterid=id; might not work. The class that theObject instances must have the 'vensterid' property, or you will get `1119: Access of possibly undefined property vensterid through a reference with static type ...
I think your problem here is following string:
var theObject = this[anObject];
Just replace it with
var theObject = anObject;
I hope that's what you need.
Alternatively instead of
setAnimation(venster0,0);
you could pass an instance name (i.e. String):
setAnimation("venster0",0);
That will work because by this['propertyname'] you are actually accessing Object's property by name.
Just going to throw out that using the built-in Tween classes in Flash/Flex is a pain. Look into using Tweening libraries instead: Tweener, TweenLite, etc. They are much easier to work with, and you don't have to worry about maintaining references until the Tween completes.

Actionscript - Variable Assignment without reference?

Should be easy. I have an object. I want to modify it, but before i do I want to save a copy of it that I can go back to. I tried setting copy = original but when i modify the attributes of the original the copy also shows the changes. I am assuming this is because in actionscript any time you assign, it really just stores a reference to the original object. So whats the best way for me to store a copy of the original object for later use?
var newObj:Object = Object(ObjectUtil.copy(oldObj));
"Copies the specified Object and returns a reference to the copy. The copy is made using a native serialization technique. This means that custom serialization will be respected during the copy.
This method is designed for copying data objects, such as elements of a collection. It is not intended for copying a UIComponent object, such as a TextInput control. If you want to create copies of specific UIComponent objects, you can create a subclass of the component and implement a clone() method, or other method to perform the copy."
http://livedocs.adobe.com/flex/3/langref/mx/utils/ObjectUtil.html#copy()
What you are looking for is a deep copy of the object rather then passing by reference. I found the answer here which uses the new ByteArray class in AS3:
http://www.kirupa.com/forum/showthread.php?p=1897368
function clone(source:Object):* {
var copier:ByteArray = new ByteArray();
copier.writeObject(source);
copier.position = 0;
return(copier.readObject());
}
Which you then use like this:
newObjectCopy = clone(originalObject);
Cheers!
// duplicate any given Object (not MCs)
Object.prototype.copy = function()
{
ASSetPropFlags(Object.prototype,["copy"],1);
var _t = new this.__proto__.constructor(this) //
for(var i in this){
_t[i] = this[i].copy()
}
return _t
};
Usage
x = ["1","2","3",[4,5],[{a:1,b:2}]]
y = x.copy()
y[0] = 0
y[3][0]="d"
trace(x)
trace(y)