Access a AS3 instance dynamically by iterating with variables - actionscript-3

I want to be able to access a instance on the stage dynamically by looping through an array containing Strings that describes the path.
private var clockKeeper:Array = new Array("LB.anim.clock.lbclock");
trace(stage.LB.anim.clock.lbclock.text);
for (var key in clockKeeper) {
trace(stage[clockKeeper[key]].text);
}
When i access it manually with the first trace statement, it works.
When i do it dynamically it seems like Flash tries to find an object named "LB.anim.clock.lbclock" not LB.anim....
How can i change this behaviour and make it work?

You should try splitting the "path" which should then consist of locally available names, and address each object in order. "Locally available names" means there should be stage.LB, and that object should have a property anim, etc etc.
function getObjectByPath(theRoot:DisplayObjectContainer,
thePath:String,separator:String='.'):DisplayObject
{
var current:DisplayObjectContainer=theRoot;
var splitPath:Array=thePath.split(separator);
while (splitPath.length>0) {
var named:DisplayObject = current.getChildByName(splitPath[0]);
var addressed:DisplayObject=current[splitPath[0]];
// either named or addressed should resolve! Otherwise panic
if (!addressed) addressed=named; else named=addressed;
if (!named) return null; // not found at some position
splitPath.shift();
if (splitPath.length==0) return named; // found, and last
current=named as DisplayObjectContainer;
if (!current) return null; // not a container in the middle of the list
}
// should never reach here, but if anything, just let em
return current;
}
This provides two ways of resolving the path, by name or by property name, and property name takes precedence. You should then typecast the result to proper type.
Yes, call this as follows:
trace((getObjectByPath(stage,clockKeeper[key]) as TextField).text);

Related

DisplacementMapFilter not showing up in flash

I have a problem with creating and applying displacement maps filters on a container Sprite. The setup is like this
public class ExplosionManager
{
[Embed...] // this is an image I tested, basically a spherical displacement
private var explodeDisplaceAsset:Class;
private var explodeDisplace:Bitmap;
private var displacementFilters:Array = new Array();
private var displacementMaps:Vector.<BitmapData> = new Vector.<BitmapData>();
private var unusedFilters:Vector.<DisplacementMapFilter> = new Vector.<DisplacementMapFilter>();
private var unusedMaps:Vector.<BirmapData> = new Vector.<BitmapData>();
public function ExplosionManager(container:Sprite)
{
explodeDisplace = new explodeDisplaceAsset();
container.filters = displacementFilters;
}
public function ExplodeAt(pos:Point, force:int) : void
{
var newDisplaceMap:BitmapData;
var newDisplaceFilter:DisplacementMapFilter;
if(unusedFilters.length == 0)
{
newDisplaceMap = new BitmapData(64,64,true, 0x808080);
newDisplaceMap.draw(explodeDisplace);
newDisplaceFilter = new DispalcementFilter(newDisplaceMap, pos, BitmapDataChannel.RED, BitmapDataChannel.GREEN, force, force);
}
else
{
newDisplaceMap = unusedMaps.pop();
newDisplaceFilter = unusedFilters.pop();
newDisplaceFilter.componentX = force;
newDisplaceFilter.componentY = force;
newDisplaceFilter.mapPoint = pos;
newDisplaceFilter.mapBitmap = newDisplaceMap;
}
displacementMaps.push(newDisplaceMap);
displacementFilters.push(newDisplaceFilter);
}
}
I'm trying to make an adaptive object pool that reuses and creates filters as needed, my initial thought was that if I have about 2-3 explosions tops it'd be more efficient to have 2-3 filters that only get applied to a part of the scene rather than have one filter with a single big bitmap that gets updated every frame.
The problem is that I can't see any displacement no matter what combination of parameters I try, is there something I'm doing wrong ?
PS: I'm sorry if the code has some typos, I'm not at my development machine right now, so I had to rewrite it, but from the algorithms' point of view that's exactly what I wrote.
It seems like you're assigning the array displacementFilters to the filters property within the constructor (at setup of the ExplosionManager). It then looks like you're adding and modifying filters within that array at a later date.
Unfortunately, changes made to the filters stored within the array you used as a source last time will not be applied to the object. This is because when you assign an array to filters, a copy of that array is actually created and used. From the documentation:
To modify an existing filter object, you must use the technique of
modifying a copy of the filters array:
Assign the value of the filters array to a temporary array, such as
one named myFilters.
Modify the property by using the temporary array,
myFilters. For example, to set the quality property of the first
filter in the array, you could use the following code:
myFilters[0].quality = 1;
Assign the value of the temporary array to
the filters array.
You will need to assign the updated displacementFilters array to filters whenever there are changes made.

how to use "this" to MovieClip(root)

I have this
function fl1(floor)
{
this.("fl"+floor).visible=true;
}
how to visible it, if the location of the object in "MovieClip(root)"
i try this, but is'nt work... (sorry of my bad english)
function fl1(floor)
{
this.("MovieClip(root).fl"+floor).visible=true;
}
You should do
this["fl" + floor].visible = true
In general, if you want to access the property by the instance name, then you should use the array subscript operator ( [] ) directly on the object without using dot (.)
What is floor's variable type passed to the function fl1?
If it is String and you construct the name of the object which visibility you want to change you need to use getChildByName.
var myFloor:* = parentObject.getChildByName(floor);
if(myFloor)myFloor.visible = true;
To access so called root, you can use stage property of any object added to display list.
var root = this.stage;
If floor is already object, you simply:
floor.visible = true;

Trying to understand a function

Im trying to understan a function that I found on the web.
Iknow what the function does, It get the information about the webcam in your computer and post it on the textArea,
But the individual line are just a bit confused.
Any help ?
Thanks
private var camera:Camera;
private function list_change(evt:ListEvent):void {
var tList:List = evt.currentTarget as List;
var cameraName:String = tList.selectedIndex.toString();
camera = Camera.getCamera(cameraName);
textArea.text = ObjectUtil.toString(camera);
}
private var camera:Camera;
This line creates a variable of the class type Camera. It does not create an instance of the variable.
private function list_change(evt:ListEvent):void {
This line is a standard function heading. Because the argument is a ListEvent, it makes me think that this function is probably written as an event handler. Because of the name of the function, it is most like listening to the change event on a list.
var tList:List = evt.currentTarget as List;
This line creates a reference to the list that dispatched the event, which caused this handler to be executed.
var cameraName:String = tList.selectedIndex.toString();
This line converts the selectedIndex to a string. It's a bit odd to convert an index to a string, as opposed to some value. But the reason they do that looks to be on the next line..
camera = Camera.getCamera(cameraName);
This uses that camera variable (defined back in line 1) and actually gets an instance of the camera. It uses the "cameraName" which makes me think that the list that dispatched this change event contains a list of cameras available on the system.
textArea.text = ObjectUtil.toString(camera);
This converts the camera object to a string and displays it in a text area. Normally you wouldn't try to do this as it provides no valuable data. A default object will display strings as [Object object] or something similar. Perhaps the camera object has a custom string function; I don't have experience with that. Normally, you'd want to access properties of the object to get useful information, not try this on the object itself.
}
This line is the end of the function. The open bracket was in the 2nd line of code in the function definition.

How to get value before it changes? In knockout.js

I'm using mapping utils to load some mega JSON data. I know how to detect changes with an 'update' callback.
But how do I compare the old value with new value? In the 'update' callback I get access only to new value.
Of course - when I put update to JSON - I use mapping utils again.
I'd like to know whether the value increases or decreases. How to do this?
An update callback for the ko.mapping plugin takes one options argument, which is an object containing
data
parent
target
The parent object still holds the old value.
var mapping = {
'prop':
update: function(options) {
var oldval = options.parent.prop;
var newval = options.data;
// do something that uses oldval and newval here
return newval;
}
}

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)