Create a different class from a string - actionscript-3

Hello I have this bit of code, and it what it must do is when there is some class (always extending the Box class) that must be spawned if there is already one of the same type it loads that one and if there is no one it creates a new one.
private var _l:Vector.<Box> = new Vector.<Box>();
public function respawn(shapeId:int, className:String = "Box"):Class {
var l:int = _l.length, i:int;
var c:Class;
var ct:Class = getDefinitionByName(className) as Class;
for (i = 0; i < l; i++) {
c = _l[i];
if (!c.active && c.shapeId == shapeId) {
return c;
}
}
c = new ct();
_l[l] = c;
return c;
}
If I try this code it generates these errors:
Implicit coercion of a value of type com.shapes:Box to an unrelated type Class.
Implicit coercion of a value of type Class to an unrelated type com.shapes:Box
How can I fix this so I can create different types of classes that all extend the Box class and get them into a Vector.<Box>?

Object is the superclass of all ActionScript classes, not Class.
Besides, you can:
var box:Object = new Box();
But you can not:
var box:Box = new Object();

Like Max Golovanchuk said I had to target the Object and not the class.
public function respawn(shapeId:int, className:Class):Object {
var l:int = _l.length, i:int;
var c:Box;
for (i = 0; i < l; i++) {
c = _l[i];
if (c.shapeId == shapeId) {
return c;
}
}
c = new className();
_l[l] = c;
return c;
}

Related

How do i change an array based on another text field?

i have a TheList.as class..in which i have created a list for an android app.
Here is TheList.as(Cut down to the specific stuff for this question)
public var _ListItem:ListItem;
public var _Data:Array;
public var _Values:Array;
public var $CurrentValue:String;
public var _TextLabel:TextField;
public function TheList(Data:Array,Values:Array)
{
_Data = Data;
_Values = Values;
initialize();
}
private function initialize():void
{
_TextLabel = new TextField();
addChild(_TextLabel);
_TextLabel.text = "Data";
_Container = new ListContainer ;
addChild(_Container);
_Container.x = 0;
_Container.y = 0;
currentY = _Container.y;
lastY = _Container.y;
for (var i:int = 0; i < _Data.length; i++)
{
_ListItem = new ListItem ;
_Container.addChild(_ListItem);
_ListItem.y = _ListItem.height * i;
_ListItem.addEventListener(MouseEvent.MOUSE_DOWN,onItemDown,false,0,true);
_ListItem.addEventListener(MouseEvent.MOUSE_UP,onItemUp,false,0,true);
_ListItem.mouseChildren = false;
_ListItem.value = _Values[i];
_ListItem.name = _Data[i];
_ListItem.ItemLabel.text = _ListItem.name ;
}
}
Here is the class "TheList" is being used in (Again Cut Down to specific stuff)
$myList = new TheList($Data,$Values);
addChild($myList);
$myList.x = -240;
$myList.y = -203;
$myList.visible = false;
$ListFrom = new TheList($DataFromTo, $ValuesFromTo);
addChild($ListFrom);
$ListFrom.x = -240;
$ListFrom.y = -203;
$ListFrom.visible = false;
$ListFrom._TextLabel.text = $DataFromTo[0];
$ListTo = new TheList($DataFromTo, $ValuesFromTo);
addChild($ListTo);
$ListTo.x = -240;
$ListTo.y = -203;
$ListTo.visible = false;
$ListTo._TextLabel.text = $DataFromTo[0];
Now what i am trying to achieve is that i want to change "$Data" and "$Values" Arrays..as you can see i have a main list and two sublists... when "Time" is selected in the main list, i want the sub-lists to be populated with "Time" related unit names...i tried
if($myList._TextLabel.text == "Time")
{
$ListFrom._Data = ["this", "this", "this" etc]
}
But its not working. I am not getting any error either. I'd really appreciate any help!
What you try to achieve is not pissible in this way. You initialize you lists with data fields. When you reset the data, you need to invalidate your list again. You can achieve this with an item setter
private var __Data:Array;
public function get _Data():Array
{
return __Data;
}
public function set _Data(value:Array):void
{
this.__Data = value;
initialize();
}
make sure that you first cleanup you list before you rebuild it again.
your code:
$ListFrom._Data = ["this", "this", "this" etc]
will automaticly call the setter. A getter and setter method looks like a function but is invoked like a property. means:
object.property = "something" //will call the setter
var something:String = object.property //will call the getter

AS3: Casting to Vector

I am trying to create a vector from unknown class, but it fails, any ideas about how to do it?
This is what i tried:
var vector:Vector = new Vector(); // throw exception
function base():void{
var vector:Vector.<String> = createVector(String);// throw classCastException
}
function createVector(cls:Class):*{
var array:Array = new Array();
for(var i:int = 0; i < 10; i++){
var element:cls = new cls();
array.push(element);
}
return Vector(array);
}
Vector is expecting a parameter type so you can't do this like you want, but using getQualifiedClassName to get class info you can construct a string that will enable you to call the Vector. constructor using getDefinitionByName :
Ex.
// get class parameter name
var className:String=getQualifiedClassName(String);
// get the Vector class object for the given class
var o:Object=getDefinitionByName("__AS3__.vec::Vector<"+className+">");
// call the constructor
var v:*=o.prototype.constructor(["hello", "world"]);
So your function can be written as:
public function createVector(cls:Class):*{
var cn:String = getQualifiedClassName(cls);
var o:Object = getDefinitionByName("__AS3__.vec::Vector.<"+cn+">");
var array:Array = [];
for(var i:int = 0; i < 10; i++){
var element:* = new cls();
array.push(element);
}
return o.prototype.constructor(array);
}
live example at wonderfl:
http://wonderfl.net/c/pkjs
Based on #Patrick answer I found a working solution.
Check it out:
function createVector(cls:Class):*{
var className:String = getQualifiedClassName(cls);
var vectorClass:Class = getDefinitionByName("__AS3__.vec::Vector.<"+className+">") as Class;
var vector:* = new vectorClass(10);
for(var i:int = 0; i < 10; i++){
var element:MyClass = new cls(); // may be Object or Object extends cls
vector[i] = element;
}
return vector;
}

Actionscript 3 compare two MovieClips

I dynamically add MovieClips to an DisplayObjectContainer. Some of these MovieClips loop through all children of DisplayObjectContainer to check gravitation and collision. Though, when I check if the current child is not equal to the caller MovieClip it seems to check the type only.
So basically, when I check MovieClip equality it seems to check the type only.
Main.as:
var planet:Planet = new Planet(holder);
planet.x = 0;
planet.y = 0;
planet.spawn();
var planet2:Planet = new Planet(holder);
planet2.x = 50;
planet2.y = 50;
planet2.spawn();
Planet.as:
public class Planet {
public var x:Number = 0;
public var y:Number = 0;
private var _holder:DisplayObjectContainer;
private var _mc:MovieClip;
public function Planet(holder:DisplayObjectContainer) {
_holder = holder;
_mc = new PlanetMovieClip();
_mc.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
public function spawn():void {
_holder.addChild(_mc);
}
private function enterFrameHandler(evt:Event):void {
for(var i:int = 0; i < _holder.numChildren; i++) {
var child:MovieClip = _holder.getChildAt(i) as MovieClip;
// the other planet never passes this check
if(child !== _mc) {
trace('child is not the same');
}
}
}
}
So am I doing something wrong, should I approach an other method or should I just add an property that generates a random token used for identification?
you should remove as MovieClip; in _holder.getChildAt(i);
I would change !== with !=
The rest of your code seems ok.
First of all you have error in the code you have given to create Planet movieclip.
It should be
var planet:Planet = new Planet(holder);
planet.x = 0;
planet.y = 0;
planet.spawn();
var planet2:Planet = new Planet(holder)
planet2.x = 50;
planet2.y = 50;
planet2.spawn();
Did you check for null in Planet.as ?
if(child!=null) {
if(child !== _mc)
trace('child is not the same');
else
trace("child same");
}
And ofcourse you can always assign some unique name to the movieclips, and use it for comparing.

as3 error loading "good" "bad" array

I am creating a "good" "bad" array to display on screen which i can later use simple if statements to do something upon if the player has collided with the "good" "bad" objects.
I cant get the objects to randomly generate on screen with the following code.
// Create and Set good/bad random Word objects
public function newObject(e:Event)
{
var goodObjects:Array = ["WordObject1"];
var badObjects:Array = ["WordObject2"];
if (Math.random() < .5)
{
var r:int = Math.floor(Math.random()*goodObjects.length);
var classRef:Class = getDefinitionByName(goodObjects[r]) as Class;
var newObject:MovieClip = new classRef();
newObject.typestr = "good";
} else
{
r = Math.floor(Math.random()*badObjects.length);
classRef = getDefinitionByName(badObjects[r]) as Class;
newObject = new classRef();
newObject.typestr = "bad";
}
newObject.x = Math.random();
newObject.y = Math.random();
addChild(newObject);
objects.push(newObject);
placeWords();
}
// create random Word objects
public function placeWords() {
objects = new Array();
for(var i:int=0;i<numWordObjects;i++) {
// loop forever
while (true) {
// random location
var x:Number = Math.floor(Math.random()*mapRect.width)+mapRect.x;
var y:Number = Math.floor(Math.random()*mapRect.height)+mapRect.y;
// check all blocks to see if it is over any
var isOnBlock:Boolean = false;
for(var j:int=0;j<blocks.length;j++) {
if (blocks[j].hitTestPoint(x+gamesprite.x,y+gamesprite.y)) {
isOnBlock = true;
break;
}
}
// not over any, so use location
if (!isOnBlock) {
newObject.x = x;
newObject.y = y;
newObject.gotoAndStop(Math.floor(Math.random()*1)+1);
gamesprite.addChild(newObject);
objects.splice(newObject);
break;
}
}
}
}
i get the following errors:
1119: Access of possibly undefined property x through a reference with static type Function.
1119: Access of possibly undefined property y through a reference with static type Function.
1067: Implicit coercion of a value of type Function to an unrelated type flash.display:DisplayObject.
Try renaming var x and var y to something else. Those are public properties in any class that extends as a display object (Sprite/MovieClip/Shape).

Is ActionScript 3 Dictionary a hashmap?

http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/
The dictionary does what I need but I do need to care about performance. Does anybody know if the Dictionary is implemented as a hashtable?
Or more specifically, does it perform in O(1)?
it acts as a hashmap. in fact, every ActionScript object that is an instance of a dynamic class, acts as hashmap. of course keys can always collide with properties. this behaviour comes from JavaScript. I consider it a design failure.
Array is different in that it will perform some tricks on integer keys, and Dictionary is different in that it doesn't convert keys to strings, but uses any object value as key. Please note that Number and Boolean are both converted to String.
now why whould you care how it is implemented? if it is well implemented, you probably don't wanna know. You can benchmark it. It has O(1) for all operations and is reasonably fast (inserting costs a about twice as much time as an empty method call, deleting costs less). Any alternative implementation will be slower.
here a simple benchmark (be sure to compile it for release and run it in the right player):
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.utils.*;
public class Benchmark extends Sprite {
public function Benchmark() {
var txt:TextField = new TextField();
this.addChild(txt);
txt.text = "waiting ...";
txt.width = 600;
const repeat:int = 20;
const count:int = 100000;
var d:Dictionary = new Dictionary();
var j:int, i:int;
var keys:Array = [];
for (j = 0; j < repeat * count; j++) {
keys[j] = { k:j };
}
setTimeout(function ():void {
var idx:int = 0;
var out:Array = [];
for (j = 0; j < repeat; j++) {
var start:int = getTimer();
for (i = 0; i < count; i++) {
d[keys[idx++]] = i;
}
out.push(getTimer() - start);
}
txt.appendText("\n" + out);
start = getTimer();
for (var k:int = 0; k < i; k++) {
test();
}
txt.appendText("\ncall:"+(getTimer() - start));
idx = 0;
out = [];
for (j = 0; j < repeat; j++) {
start = getTimer();
i = 0;
for (i = 0; i < count; i++) {
delete d[keys[idx++]];
}
out.push(getTimer() - start);
}
txt.appendText("\n" + out);
},3000);//wait for player to warm up a little
}
private function test():void {}
}
}
Nope, it's not. java hashmaps are based on hash codes, while Dictionary is based on strict equality (===) of keys and therefore must not be used if you plan to put objects as keys.
java:
class MyStuff {
public final int id;
MyStuff(int i) {
this.id = i;
}
public int hashCode() {
return this.id;
}
public int equals(MyStuff o) {
return (this.id - o.id);
}
}
Map<MyStuff, Object> m1 = new HashMap<MyStuff, Object>();
m1.put(new MyStuff(1), new Object());
assert(m1.get(new MyStuff(1)) != null); //true
as3:
class MyStuff {
public var id:Number;
public function MyStuff(i:Number):void {
this.id = i;
}
//no notion of hashCode or equals in AS3 Object class,
//so we can't really control how the Objects are compared.
}
var d:Dictionary = new Dictionary();
d[new MyStuff(1)] = {};
trace(d[new MyStuff(1)]); //outputs null
I'm looking into the right way of implementing hashing in AS3, but it does look very unpromising...
The adobe documentation on associate arrays seems to imply that dictionaries are hashmaps:
"You can use the Dictionary class to create an associative array that uses objects for keys rather than strings. Such arrays are sometimes called dictionaries, hashes, or maps."
http://livedocs.adobe.com/flex/3/html/help.html?content=10_Lists_of_data_4.html