So I've never worked with Vectors in Flash before and I wanted to write a little test application with a Vector using a custom object. But I'm getting: error 1000: Ambiguous reference to Vector when I try launching the application. I can't figure out for the life of me what's wrong. I tried not using a custom object and just instantiating a string Vector from an online tutorial and I'm getting the same thing.
Here's what I got:
package
{
import TestPlayer; // The custom player class
import flash.display.MovieClip;
public class Vector extends MovieClip
{
private var array:Array = new Array();
private var vector:Vector.<TestPlayer>;
public function Vector()
{
array[0] = [0, 0, "Bob", false];
array[1] = [1, 0, "Frank", true];
array[2] = [2, 1, "Sarah", true];
Load();
}
private function Load():void
{
var aPlayer:Player = null;
vector = new Vector.<TestPlayer>();
try
{
var numRows:int = array.length;
for (var i = 0; i < numRows; i++)
{
aPlayer = new Player();
aPlayer.playerID = array[i][0];
aPlayer.playerName = array[i][1];
aPlayer.playerTypeID = array[i][2];
aPlayer.hasProgress = array[i][3];
vector.push(aPlayer);
}
}
catch (error:Error) { }
}
}
The custom player class looks like this:
package
{
public class TestPlayer
{
private var _playerID:int;
private var _playerName:String = "";
public function get playerID():int
{
return _playerID;
}
public function set playerID(value:int):void
{
_playerID = value;
}
public function get playerName():String
{
return _playerName;
}
public function set playerName(value:String):void
{
_playerName = value;
}
[...]
}
}
I don't know if it matters, but I'm working in Flash CS5, and I have a blank FLA that imports the class. No other errors so far. Hope you can help. Let me know if you need anymore info, thanks.
The ambiguous reference is because you've got a naming collision. The class you've written is named "Vector", which it can't distinguish from the top-level class Vector. The fix is simple, avoid naming your classes the same as a pre-existing class.
If both classes belong to separate namespaces, you can reuse class names, as long as you use thier fully-qualified name whenever you call the class.
Assume you have a class:
package foo.bar
{
class MovieClip
...
}
You could instantiate both types of MovieClips as follows:
flashMovieClip = new flash.display.MovieClip();
myMovieClip = new foo.bar.MovieClip();
Unfortunately, both your Vector and the flash Vector exist in the top-level namespace, so (AFAIK) there's no way of removing the ambiguity without renaming your class. For simplicity sake, avoid naming collisions and you should be golden.
Related
So, i've been working with ByteArrays a lot recently and i'm running into some annoying problems that make me want to rip my hair out.
basically, i'm trying to save project data for an application that i'm making to compile characters for a game into one file. the project consists of custom objects, vectors, vectors of vectors, and even vectors of vectors of custom objects! i figured the best way to write all this data properly would be to use the IExternalizable interface with the readExternal and writeExternal commands. so here's what i'm doing.
i write all the project data to an object, then write that object into a ByteArray, and save it to a file:
// probject means project object !
mProbject= { };
// Register vector as class, just to prevent any errors about that just in case
registerClassAlias("vec_core.timeline.KeyFrame", Vector.<KeyFrame> as Class);
// single KeyFrame Object
mProbject.currentFrame = Main.getInstance().animationList.selectedItem.currentKeyFrame;
// a Vector.<Vector.<KeyFrame>>
mProbject.frames = Main.getInstance().animationList.keyFrameVectorVector;
// an unsigned int
mProbject.selectedItemIndex = Main.getInstance().animationList.entries.indexOf(Main.getInstance().animationList.selectedItem);
// Vector.<String>
mProbject.animationNames = Main.getInstance().animationList.animationNames;
// String
mProbject.projectPath = nativePath;
//String
mProbject.projectName = name;
mByteArray = new ByteArray();
mByteArray.writeObject(mProbject);
mByteArray.compress();
return mByteArray;
inside the KeyFrame class though, there is two more vectors of custom objects:
private var mHitboxes:Vector.<Hitbox>;
private var mHitboxSprites:Vector.<HitboxSprite>;
so i set up both of those classes and my KeyFrame class to use IExternalizable:
public class HitboxSprite extends Sprite implements IExternalizable
{
public function readExternal(input:IDataInput):void
{
trueBounds.x = input.readFloat();
trueBounds.y = input.readFloat();
trueBounds.width = input.readFloat();
trueBounds.height = input.readFloat();
mHitbox = input.readObject();
}
public function writeExternal(output:IDataOutput):void
{
output.writeFloat(trueBounds.x);
output.writeFloat(trueBounds.y);
output.writeFloat(trueBounds.width);
output.writeFloat(trueBounds.height);
output.writeObject(mHitbox);
}
}
public class Hitbox implements IExternalizable
{
public function readExternal(input:IDataInput):void
{
mName = input.readUTF();
mType = input.readUnsignedInt();
mEnabled = input.readBoolean();
mKnockback = input.readBoolean();
x = input.readFloat();
y = input.readFloat();
width = input.readFloat();
height = input.readFloat();
addMultipleTags(input.readUTF());
}
public function writeExternal(output:IDataOutput):void
{
output.writeUTF(mName);
output.writeUnsignedInt(mType);
output.writeBoolean(mEnabled);
output.writeBoolean(mKnockback);
output.writeFloat(mX);
output.writeFloat(mY);
output.writeFloat(mWidth);
output.writeFloat(mHeight);
output.writeUTF(getAllTags());
}
}
public class KeyFrame implements IExternalizable
{
public function readExternal(input:IDataInput):void
{
mID = input.readUnsignedInt();
mLabel = input.readUTF();
}
public function writeExternal(output:IDataOutput):void
{
output.writeUnsignedInt(mID);
output.writeUTF(mLabel);
}
}
but when it gets to the writeObject() method of the "root" ByteArray, i get the error:
[Fault] exception, information=ArgumentError: Error #2004: One of the parameters is invalid.
this is probably the single most annoying problem i've ever had. it seems like i've tried everything and nothing is working.
does anyone else have experience with this? am i doing something wrong??
i'd appreciate any help i can get on this. i just wanna continue making my game :<
Like mentioned in the comment section, you were looking for this. What rang the bell for me was the "Sprite" class you extended. That made me suspicious in the matter that you were trying to externalize visualizable content.
This is my vector that I want to fully clone (meaning that if I change the cloned vector it doesn't affect the original vector).
var vector:Vector.<Path_Tiles> = new Vector.<Path_Tiles>();
vector = path_finder.Find_Path(Gird.TILE_SET, start, end, R_G_B, SCAREDNESS);// return a vector of path_tiles in order
and I'm trying to put it into this vector
var vector2:Vector.<Path_Tiles> = clone(vector);
and clone method is this (which I found this method on a website so I do not fully understand it)
public function clone(source:Object):*
{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}
But I'm getting this error: "[Fault] exception, information=TypeError: Error #1034: Type Coercion failed: cannot convert AS3.vec::Vector.#85973d1 to AS3.vec.Vector.."
How do I convert Path_Tiles into an object?
Assure your Path_Tiles class has been registered:
flash.net.registerClassAlias("tld.domain.package.Path_Tiles", Path_Tiles);
Then, you may copy by serializing the data to a ByteArray:
var tiles:Vector.<Path_Tiles>;
var tilesCloned:Vector.<Path_Tiles>;
var byteArray = new ByteArray();
byteArray.writeObject(tiles);
byteArray.position = 0;
tilesCloned = byteArray.readObject() as Vector.<Path_Tiles>;
Cast the readObject() deserialization to Vector.<Path_Tiles> using the as keyword.
Constructors for objects serialized must accept default parameters.
To put this all together, say this was your Path_Tiles class:
Path_Tiles.as
package
{
public class Path_Tiles
{
public function Path_Tiles(property1:String=null, property2:int=undefined) {
this.property1 = property1;
this.property2 = property2;
}
public var property1:String;
public var property2:int;
}
}
Here is your main class, showing an example of deep cloning the Path_Tiles collection:
Main.as
package
{
import flash.display.Sprite;
import flash.net.registerClassAlias;
import flash.utils.ByteArray;
public class Main extends Sprite
{
public function Main() {
super();
var source:Vector.<Path_Tiles> = new <Path_Tiles>[
new Path_Tiles("Hello", 1),
new Path_Tiles("World", 2)
];
var cloned:Vector.<Path_Tiles> = clone(source);
}
public function clone(source:Vector.<Path_Tiles>):Vector.<Path_Tiles> {
flash.net.registerClassAlias("Path_Tiles", Path_Tiles);
var byteArray = new ByteArray();
byteArray.writeObject(source);
byteArray.position = 0;
return byteArray.readObject() as Vector.<Path_Tiles>;
}
}
}
Finally, we can see the object was deep copied; confirmed by memory address:
Whenever I try to extend the Object prototype, I get an error:
Error #1056: Cannot create property my_extension on mx.core.UIComponentDescriptor.
I searched around, and found these:
Flash AS3: ReferenceError: Error #1056: Cannot create property
ReferenceError: Error #1056 - instance name Error
I'm not using a visual IDE for designing a stage, but MXML and AS3 files, so I'm not sure what to make of this error.
My code:
Object.prototype.keys = function(): Array {
var keys: Array = [];
for (var key: * in this) {
keys.push(key);
}
return keys;
}
Object.prototype.values = function(): Array {
var values: Array = [];
for each (var value: * in this) {
values.push(value);
}
return values;
}
Using prototype to extend a class seems very ActionScript 1 or 2.
In AS3, you may be able to prototype if the class is dynamic.
There are downsides to prototype:
Only dynamic classes can be extended, one can not add methods to Math for example.
Calls to methods stored in the prototype take longer to execute.
Since methods are added at run-time, editors can not show them with code hinting or use the correct syntax highlighting.
Since all classes extend object, it is not necessary to explicitly declare Object as a base; however, you could define an AbstractObject class to be extended:
package
{
public dynamic class AbstractObject extends Object
{
public function AbstractObject()
{
super();
}
public function get keys():Array
{
var keys:Array = [];
for (var key:* in this)
{
keys.push(key);
}
return keys;
}
public function get values():Array
{
var values:Array = [];
for each (var value:* in this)
{
values.push(value);
}
return values;
}
}
}
Subtype AbstractObject for your classes.
If an AS3 method returns a reference to a complex type, is there any way to make that 'readonly', like how you can have const member functions in C++? An architecture I want to use calls for a class building itself from a passed template object... and really the template object should not be modifiable. I'm currently forced to add call-back enumerators and/or lots of extra accessor methods.
Flex has an ObjectUtil.clone() method that will make a deep copy. The copy will still by modifiable, but since it's a copy, the changes won't propagate back to the original.
The method is no complicated so if you're not using Flex, just add this to a util class:
public static function copy(value:Object):Object
{
var buffer:ByteArray = new ByteArray();
buffer.writeObject(value);
buffer.position = 0;
var result:Object = buffer.readObject();
return result;
}
There is no way to do that in AS3, there is Sam's way of doing it, but it still requires copying that object before you return it, depending on the complexity of that object, it can impact the performance.
Immutable interfaces are a near-equivillant to const-correctness. Here's an example:
interface CPoint {
function get x():Number;
function get y():Number;
}
class Point implements CPoint {
private var _x:Number;
private var _y:Number;
public function get x():Number { return _x; }
public function get y():Number { return _y; }
public function set x(val:Number) { _x = val; }
public function set y(val:Number) { _y = val; }
public function normalize():void {
var length:Number = Math.sqrt(_x*_x + _y*_y);
_x /= length;
_y /= length;
}
public function Point(x:Number, y:Number) {
_x = x; _y = y;
}
}
If you return a Point as a CPoint reference, then its fields cannot be altered. You can do an explicit cast to a Point from a CPoint to force access, but you can do the same thing with const casting in C++.
Unfortunately, AS3 doesn't support covariance like it should, so things get unnecessarily difficult for const sub-objects. For example, if you had a Line class that was made up of two points, you might want to say line.start.x = 47; if you have full access to the line, but allow reading of line.start.x through an immutable interface. You could do this if there was covariance, but instead you'll need to add separate get properties for mutable and immutable properties. So, you'd end up instead with line.cstart.x for reads from a CLine. Something like this:
interface CLine {
function get cstart():CPoint;
function get cend():CPoint;
}
class Line implements CLine {
private var _end:Point;
private var _start:Point;
public function get cend():CPoint { return _end; }
public function get cstart():CPoint { return _start; }
public function get end():Point { return _end; }
public function get start():Point { return _start; }
public function Line(x1:Number, y1:Number, x2:Number, y2:Number) {
_start = new Point(x1, y1);
_end = new Point(x2, y2);
}
}
I would create a flash.utils.proxy object. You could create a proxy object that has read only implementation of a child that is passed in.
Here is the documentation for creating a proxy object. http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/utils/Proxy.html
Note: Proxy is pretty damn slow, since you'll be bypassing native object checking, and replacing it with a function call -- which when using a lot will be slow. I would do some simple performance testing first.
note: This is pseudo-code.
use namespace flash_proxy;
dynamic class ReadOnly extends flash.utils.Proxy {
private var target:Object;
public function ReadOnly(target:Object) {
this.target = target;
}
flash_proxy function getProperty(name:*):*
return target[name];
}
flash_proxy function setProperty(name:*, value:*):void
// throw an error or do nothing
}
}
You could then do:
var readOnly:ReadOnly = new ReadOnly(stage.loaderInfo.parameters);
readOnly.someparameter = 'newvalue';
trace(readOnly.someparameter); // should be old value
I'm simply playing around with basic ActionScript 3 using Flash CS3 Pro.
I put in a keyframe this very simple code to duplicate n "brander" symbols:
for (var i:Number=0; i<20; i++) {
var m = new brander("MS_"+i);
addChild(m);
m.name = "MS_"+i;
m.x = 20*i;
m.alpha = a;
a-=0.05;
m.y = 20;
}
The symbol is linked to brander.as class.
The class is this one:
package {
import flash.display.*;
public class brander extends MovieClip {
var n:String;
//
public function brander(name) {
setName(name);
}
//
function setName(name) {
this.n = name;
}
//
function getName() {
return n;
}
}
}
and it is simple too.
Now: I noticed I can't really set anything in this class. So, when I call setName (at the creation of a "brander" instance), I don't set anything. Is this possible?
I tested without debugging, by simply writing:
btn.addEventListener(MouseEvent.MOUSE_DOWN, test);
//
function test(EVT) {
trace(this.getChildByName("MS_2").getName());
}
Why do we link a class when this class can't store information? What am I doing wrong?
EDIT:
I found this is working:
function fun(EVT) {
trace((this.getChildByName("M_2") as brander).getName());
}
but I can't understand WHY: could you please tell me why?
The reason is that the getChildByName() funcction returns a DisplayObject. The DisplayObject has no getName function. The brander class however inherits from (extends) the DisplayObject, and therefore you can store it as a DisplayObject. But if you want to call any of the brander functions, you need to cast it to brander first, using as.
There is lots of information on casting, polymorphism and inheritance several places on the internet.