ActionScript 3 MovieClip class linkage - actionscript-3

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.

Related

Getting the error 1119: Access of possibly undefined property visible through a reference with static type Class

I am attempting to hide a symbol (Grill image) as soon as my animation loads.
Currently I am getting the error, E:\Burger Game\DragandDrop\Dragable.as, Line 4, Column 8 1119: Access of possibly undefined property visible through a reference with static type Class. As you can probably tell, I am new to flash.
package DragandDrop
{
Grill.visible=false;
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Point;
public class Dragable extends MovieClip
{
protected var homePos:Point;
var totalToBowl:int =3;
var i:int = 0;
public function Dragable ()
{
homePos=new Point( x, y);
buttonMode =true;
addEventListener ( MouseEvent.MOUSE_DOWN, move);
}
//egg functions
protected function move(event:MouseEvent) :void
{
parent.addChild(this);
startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP, stageUp)
}
//item drop function
protected function stageUp(event:MouseEvent):void
{
stopDrag();
if (event.target.dropTarget != null &&dropTarget.parent.name == "Bowl")
{
scaleX=scaleY=0;
alpha=0.5;
y= stage.stageHeight-height -700;
x=stage.stageWidth-width- 1400;
buttonMode=false;
removeEventListener(MouseEvent.MOUSE_DOWN, stageUp)
i++
}if (i == totalToBowl){
i=10
trace(i);
event.target.dropTarget.visible = false;
}
if (i==10 )
{
dropTarget.parent.visible = false;
}else{
returnToHome();
}
}
protected function returnToHome():void
{
x = homePos.x;
y= homePos.y;
}
}
Any idea why I am getting this error?
Any help would be massively appreciated.
Many thanks,
Rob
There are two issues:
Grill is a class, but it would seem you are trying to use it like an instance. This is what it's expecting to see when used like you're doing:
public class Grill extends MovieClip {
public static var visible:Boolean;
}
But more than likely, what you need to do is work with an instance, not the class itself:
var g:Grill = new Grill();
g.visible = false;
If this class is linked to a timeline instance, you'd have to use the instance name you gave it (and make sure that instance name doesn't clash with any Class names - or use getChildByName).
Assuming this is not meant to be static code, you have code outside of a function/method that will cause another error.
In class files, all non-static functional code needs to be in a function. You need to move that line in question (Grill.visible=false) into a function. Most likely, you want this to be the equivalent of timeline code. So the best place to put would be this:
public function Dragable ()
{
homePos=new Point( x, y);
buttonMode =true;
addEventListener ( MouseEvent.MOUSE_DOWN, move);
//addedToStage is the best equivalent of when timeline code would run
addEventListener(Event.ADDED_TO_STAGE, addedToStage);
}
private function addedToStage(e:Event):void {
//where grillinstance is the instance name of your grill
grillInstance.visible = false;
}
Now, this assumes you have this class linked at timeline that has an instance of Grill on it. If this is an incorrect assumption, please clarify with a comment or by updating your question.

Access of undefined property issues in AS3

I am having a bit of trouble with some AS3. First time using this language and have more experience with web development then OOP so am getting a bit confused.
I am trying to make it so that when someone clicks a 'powerbutton' which is a "movieclip" symbol within flash then another symbol should then become visible. This is all being done within the Kitchen class.
The code for the main class is which i got from a youtube tutorial video i followed;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.events.Event;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
public function DragFood() {
myKitchen = new Kitchen;
originalPosition = new Point (x, y);
buttonMode = true;
addEventListener (MouseEvent.MOUSE_DOWN, down);
}
protected function down (event:MouseEvent):void
{
parent.addChild(this);
startDrag();
stage.addEventListener (MouseEvent.MOUSE_UP, stageUp);
}
protected function stageUp (event:MouseEvent):void
{
stage.removeEventListener (MouseEvent.MOUSE_UP, stageUp);
stopDrag();
if (dropTarget)
{
if(dropTarget.parent.name == "bowl")
{
trace("The " + this.name + " is in the bowl");
this.visible = false;
} else {
returnToOriginalPosition();
}
} else {
returnToOriginalPosition();
}
}
protected function returnToOriginalPosition():void
{
x = originalPosition.x;
y = originalPosition.y;
}
}
}
Within it i call the other class;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
The code for the kitchen class is;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
public class Kitchen extends MovieClip
{
// This is a function. This particular function has the same name as our class and therefore will be executed first
public function Kitchen()
{
// This is a "call" to another function that is defined later in the program.
init();
trace("Hello world");
}
public function init():void
{
// If we want an object (on the screen or otherwise) to be notified about an event we must add a listener for that event to that object.
// We also need to specify what happens everytime the event we are listening for happens.
PowerButton.addEventListener(MouseEvent.CLICK, handleButtonClicks);
}
//This function is called when the oven on button recieves a click.
public function handleButtonClicks(event:MouseEvent):void
{
OvenOn.visible = true;
trace("the oven is being switched on");
}
}
}
The issue i keep getting is that OvenOn and PowerButton are giving me a undefined access issue and im not sure how to fix it. I have found posts on similar subjects like - Access of Undefined property? Actionscript 3
but im not quite sure how to apply it to my issue if anyone could offer any help that would be great.
When you're programming on the timeline, code is referencing the local namespace, and objects you make there (movieclips, textfields, etc.) are automatically instantiated in that namespace so that you can simply call OvenOn.visible = true. However, for each class, their local namespace is whatever is inside the class, so unless you actually created a property on your class called OvenOn, it will most definitely give you Access of Undefined Property errors.
Think of each class as its own island. For them to touch eachother, they need some sort of connection. That connection can be made once the parent instantiates the class in its own namespace. For example...
var foo:String = "Hello!";
var bar:MyClass = new MyClass();
// At this point, whatever code runs inside of MyClass has no concept of foo, or how to access it.
addChild(bar);
// Now that we've added it to the stage, the bar has some properties that have automatically been populated such as "root", "parent", or "stage".
foo.someProperty = "World";
// Since this namespace has a variable pointing to the instance, we can change properties on that class.
Now that we've instantiated MyClass on the stage, we can reference parent properties the class didn't know about. Mind you, this is not necessarily best practice.
package
public class MyClass extends MovieClip {
var someProperty:String = "cheese";
public function MyClass() {
trace(parent.foo) // this will fail
addEventListener(Event.ADDED_TO_STAGE, test);
}
public function test(e:Event):void {
trace(this["parent"].foo); // this will succeed
}
}
}
If you absolutely must change something that is not part of your Kitchen class, pass either the parent of OvenOn or that object specifically as a property of Kitchen. You could do this a couple ways.
with the Constructor...
var something:*;
public function MyClass(someObject:*) {
something = someObject;
}
public function test():void {
something.visible = false;
}
...or by Assigning the Property...
var bar:MyClass = new MyClass();
bar.something = OvenOn;
bar.test(); // will turn off the OvenOn now that 'something' is pointing to it.

AS3 code with an interface has suddenly started giving "Call to a possibly undefined method"

GameWorld.as, Line 96 1180: Call to a possibly undefined method initialize.
I am adding a controller to my GameWorld that implements IController:
addController(new BackgroundController(this));
public function addController(controller:IController):void
{
controller.initialize();
controllers.push(controller);
}
public interface IController
{
function initialize():void; //setup the controller
function getType():String; //define the controller by a type string
function update():void; //perform update actions
function destroy():void; //cleanup the controller
}
initialize is a method from IController but is now undefined suddenly
I am getting no syntax errors and cant seem to revert my code to a working state.
What could be causing this?
Here is the BackgroundController:
package controller
{
import Entity;
import flash.display.Bitmap;
import flash.display.Sprite;
public class BackgroundController implements IController
{
private var world:GameWorld;
private var images:Vector.<Bitmap>;
private var bgImage:Sprite;
public function BackgroundController(world:GameWorld)
{
this.world = world;
}
public function initialize():void
{
bgImage = new Sprite();
images = new Vector.<Bitmap>();
var ypos:int = 0;
for (var i:int = 0; i < 3; i++ )
{
var tempBmp:Bitmap = new Bitmap(new grasstile(0, 0));
images.push(tempBmp);
bgImage.addChild(tempBmp);
tempBmp.y = ypos;
ypos += 500;
}
GameWorld.lowerLayer.addChild(bgImage);
}
public function update():void
{
//update the background tiles
for (var i:int = 0; i < 3; i++ )
{
images[i].y -= world.gameSpeed;
if (images[i].y < -500 )
{
images[i].y += 1500;
}
}
}
public function getType():String
{
return "Background";
}
public function destroy():void
{
}
}
}
Some global checks
Are you using runtime shared assets, multiple files? Make sure you've build them all.
Make sure there are no other runtime/build errors
In FDT (which editor do you use?) there is a feature called 'reset the MXML compiler and force full build'. That clears the cache and forces to do a complete new build instead of an incremental build.
In Flashdevelop you have to use tools > flash tools > rebuild class path
In the Flash IDE you could clear the ASO files(CS5-) / clear publish cache (CS6).
Restart/kill the editors + related processes to make sure there are no weird cache conflicts and all syntax checking is up to date.
Code checks
// make sure it has implemented the IController
trace("controller is IController: " + (controller is IController) );
and..
// detect what kind of class it really is. Goto that class, check the interface.
trace("controller is : " + getQualifiedClassName(controller) );
Also make sure there are no other IController interfaces, or check all the import statements, so your sure everywhere the right interface is used.
Found myself in the same situation.
Discovered that the problem was due to a name-clashing issue between the package and the defined variable.
So, in your case, just changing
public function addController(controller:IController):void
{
controller.initialize();
controllers.push(controller);
}
to
public function addController(controllerImpl:IController):void
{
controllerImpl.initialize();
controllers.push(controllerImpl);
}
should have solved it.
An interface just defines rules for a class, in this case stating that any class implementing IController must contain definitions for those four methods. Do you actually have an initialize method defined in your controller class?

AS3 Error 1000 on Vector

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.

Re-defining named functions at runtime

What I am trying to do is kind of odd, but I am wondering if anyone can come up with a clever way to do what I want to do. Basically, I want to re-define a named function at runtime. I can do this with anonymous functions, but I can't figure out a way to do it for named functions. I want to do this so that I can implement a "spy" functionality on an object for a testing framework (a port of Jasmine to Flex).
Take, for instance, this class:
public class TestClass
{
public var anonymous:Function = function():void {
trace("original anonymous");
};
public function named():void {
trace("original named");
}
}
I can easily re-define the anonymous function because it is just a variable. Javascript uses this idiom a lot.
var testClass:TestClass = new TestClass();
testClass.anonymous = function():void { trace("overridden anonymous"); }
BUT, when I do the same thing for named functions, you get a compile-time error:
// Does not compile
testClass.named = function():void { trace("overridden named"); }
I tried to make it a bit more "squishy" but this leads to a runtime failure "Cannot assign to a method named on TestClass".
// Compiles with runtime failure
testClass["named"] = function():void { trace("overridden named"); }
Can anyone more clever than I come up with a way to hack this? Can the bytecode be hijacked? Something?
I want to modify an object, not a
class
But object doesn't contain functions, only non-static variables. I tried to use prototype property and replace method there, but original method still gets called instead of injected one.
About "hack" bytecode, do you mean "hack" already loaded SWF in runtime? I think it's not possible. I'm sure, though, you can parse SWF with something like as3swf, find method in bytecode, replace it and save result in new SWF.
I had an idea bout making a function "cache" . This might work with what you need.
Let's say you have a class "Car" with a method you need to redefine at runtime:
public class Car extends Sprite
{
private var functionCache:Function;
public function Car()
{
super();
}
public function flexibleFunction(functionBody:*=null):void{
if(functionBody is Function){
functionBody.call();
functionCache=functionBody;
} else {
functionCache(functionBody);
}
}
}
Usage:
public class Main extends Sprite
{
private var car:Car;
public function Main()
{
car = new Car();
car.flexibleFunction(function(){trace("redefine test #1")});
car.flexibleFunction();
car.flexibleFunction(function(doParametersWork:String="let's see"){trace("redefine test #2: " + doParametersWork);});
car.flexibleFunction("yes they do");
car.flexibleFunction();
}
}
an easy way to accomplish what you want is to simply pass a new function to the original function and execute it from there:
package
{
//Imports
import flash.display.Sprite;
//Class
public class RedefineFunction extends Sprite
{
//Constructor
public function RedefineFunction()
{
originalFunction();
originalFunction(redefinedFunction);
}
//Original Function
public function originalFunction(redefinition:Function = null):void
{
if (redefinition != null)
redefinition();
else
trace("Original Function Definition");
}
//Redefined Function
private function redefinedFunction():void
{
trace("Redefined Function Definition")
}
}
}
traces:
Original Function Definition
Redefined Function Definition