Error: Access of undefined property in AS3 - actionscript-3

I'm attempting to learn ActionScript 3 as my first programming language (before this I only did in past some little crap with PHP).
I have this code:
package
{
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
/**
* ...
* #author Mattia Del Franco
*/
[Frame(factoryClass="Preloader")]
public class Main extends Sprite
{
[Embed(source = "img/pgnew.png")]
internal var MyImage:Class;
// La riga embed importa l'immagine, la riga sotto la assegna ad una classe chiamata MyImage
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
trace ("Hello World!");
var myBitmap:Bitmap = new MyImage; //nuova variabile myBitmap al quale viene assegnato la creazione di un nuovo MyImage (trattato come un oggetto)
addChild( myBitmap );
var writeText:TextField = new TextField();
writeText.text = "Ciao Mondo!";
this.addEventListener(MouseEvent.CLICK, function(){
addChild(writeText);
var clicked:Boolean = true;
return clicked;
});
this.addEventListener(MouseEvent.CLICK, function() {
if (clicked == true) {
removeChild(writeText);
} else {
addChild(writeText);
}
});
}
}
}
In the second EventListener I'm trying to get the boolean value of clicked (specified in the first EventListener) but when i go to debug this program i get this error:
col: 9 Error: Access of undefined property clicked.
if (clicked == true) {
Why this happens?

The reason that you cannot access the "clicked" variable is because this variable is held in a different scope. When you declare a variable within a function (your first Event Listener), it is only accessible from within that function. Your second Event Listener has no access to that variable.
Here is a good way to work around the problem:
var clicked:Boolean = false;
var writeText:TextField = new TextField();
writeText.text = "Ciao Mondo!";
this.addEventListener(MouseEvent.CLICK, function(){
addChild(writeText);
clicked = true;
return clicked;
});
this.addEventListener(MouseEvent.CLICK, function() {
if (clicked == true) {
removeChild(writeText);
} else {
addChild(writeText);
}
});

Related

Error #1009- Only when there is code present in main class

Please do forgive me if this is a stupid question, by I really need to know the solution. So here I have a program that generates particles every set distance of space. My program consists of a document class, called supportForce and an object class(of the particle) called TheDot.
In the TheDot object class, I have the following code-
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class TheDot extends MovieClip
{
var base:Object = MovieClip(root);
public function TheDot()
{
this.addEventListener(Event.ENTER_FRAME, eFrame);
}
private function eFrame(event:Event):void
{
if (base.currentFrame == 1){
trace ("G");
}
}
}
}
This code works perfectly (outputs G) until I add the following code into the document class, suportForce, under an ENTER_FRAME event-
var ctX:int = 0,ctY:int = 0,done:Boolean = false;
while (done == false)
{
var dots:TheDot = new TheDot ;
dots.alpha = 0;
dots.x += (25 * ctX);
dots.y += (25 * ctY);
ctX++;
if (ctX == 22 && ctY == 20)
{
done = true;
break;
}
else if (ctX == 22)
{
ctX = 0;
ctY++;
}
stage.addChild(dots);
}
So now, there is an Error #1009: Cannot access a property or method of a null object reference at TheDot/eFrame(). I have declared all the variables in the correct place, and also the functions. Thanks in advance. I have the link to the .fla and .as files in my drive here, do use it if necessary.
https://drive.google.com/folderview?id=0B8QnUfRAn9lKLUVqRjNSRHNpRkU&usp=sharing
FIRST
var dots:TheDot = new TheDot(stage);
public class TheDot extends MovieClip
{
var base:Object;
public function TheDot(stageRef:Stage)
{
base = stageRef;
this.addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event) {
this.removeEventListener(Event.ADDED_TO_STAGE, init);
this.addEventListener(Event.ENTER_FRAME, eFrame);
}
private function eFrame(event:Event):void
{
if (base.currentFrame == 1){
trace ("G");
}
}
Try this!

How can I solve this error in Flash game?

I have a problem in Flash puzzle game. If I create the game in the first frame of my timeline it's working, but if the game has been created (for example) in 5th frame it does'nt work!
It send me this error:
TypeError: Error #1009: Cannot access a property or method of a null
object reference.
at Map() TypeError: Error #2007: Parameter hitTestObject must be non-null.
at flash.display::DisplayObject/_hitTest()
at flash.display::DisplayObject/hitTestObject()
at DragDrop/drop()
dragdrop class
package
{
import flash.display.*;
import flash.events.*;
public class DragDrop extends Sprite
{
var origX:Number;
var origY:Number;
var target:DisplayObject ;
public function DragDrop()
{
// constructor code
origX = x;
origY = y;
addEventListener(MouseEvent.MOUSE_DOWN, drag);
buttonMode = true;
}
function drag(evt:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, drop);
startDrag();
parent.addChild(this);
}
function drop(evt:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_UP, drop);
stopDrag();
if(hitTestObject(target))
{
visible = false;
target.alpha = 1;
Object(parent).match();
}
x = origX;
y = origY;
}
}
}
I think the problem is in var target! and I don't know how to solve it.
Map.as
enter code here package
{
import flash.display.*;
import flash.events.*;
public class Map extends MovieClip
{
var dragdrops:Array;
public function Map()
{
// constructor code
dragdrops = [tt1];
var currentObject:DragDrop;
for(var i:uint = 0; i < dragdrops.length; i++)
{
currentObject = dragdrops[i];
currentObject.target = getChildByName(currentObject.name + "_target");
}
}
public function match():void
{
}
}
}
Edit:
There are multiple problems with the code. Too many to list, I'm afraid, but the biggest one is:
You're declaring a map, and trying to add your object to it, before your object exists. It doesn't exist until frame 5, so this won't work. I've re-written the code below, but honestly, there is so much wrong with the code that it's just not possible to fix without re-writing significant portions of it.
package
{
import flash.display.*;
import flash.events.*;
public class Map extends MovieClip
{
var dragdrops:Array;
public function Map()
{
// constructor code
dragdrops = new Array();
}
public function addElement(gamepiece:DragDrop):void {
dragdrops.push(gamepiece);
}
public function addChildElements():void {
var currentObject:Object;
for(var i:uint = 0; i < dragdrops.length; i++)
{
currentObject = dragdrops[i];
currentObject.test();
currentObject.target = (currentObject.name + "_target"); // this should work now, but doesn't. Why?
currentObject.target.test();
}
}
public function match():void
{
}
}
}
Then, on frame one, I added:
var map:Map = new Map();
Then, on frame five, I added:
map.addElement(tt1);
map.addChildElements();
This got tt1 added to map, at least, but that's as far as I got. Your problem now is;
currentObject.target = (currentObject.name + "_target");
It's the correct name, now, but it won't add it to target. That's as much as I can do.
It's because your hitTestObject method isn't correctly invoked. This method must be invoked in a Display Object instance to test if another instance of a Display Object hits it:
if (myDisplayObject.hitTestObject(anotherDisplayObject))
{
// do stuff
}
Adobe help about hitTestObject method.
Edit
So you should write you class like that:
package
{
import flash.display.*;
import flash.events.*;
public class DragDrop extends Sprite
{
var origX:Number;
var origY:Number;
var target:DisplayObject;
public function DragDrop()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event):void {
origX = x;
origY = y;
stage.addEventListener(MouseEvent.MOUSE_DOWN, drag);
buttonMode = true;
}
private function drag(evt:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, drop);
startDrag();
parent.addChild(this);
}
private function drop(evt:MouseEvent):void
{
target = (evt.target as DisplayObject);
stage.removeEventListener(MouseEvent.MOUSE_UP, drop);
stopDrag();
if(target.hitTestObject(target))
{
visible = false;
target.alpha = 1;
Object(parent).match();
}
x = origX;
y = origY;
}
}
}
Remark
You shouldn't call your variable target, because its the name of a Flash native variable. Rename it targ for example.

as3 - dispatch mouse event from external class

I am having problems understanding correctly how to dispatch events and capture them in another class.
In this case, I am trying to emulate a mouse click dispatched from an "clickM" class.
On stage I have 2 movieclips to test, a custom cursor and the listeners to capture the click event.
clickM:
package {
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event; //dispatcher
import flash.events.MouseEvent;// mouse event
public class clickM extends MovieClip {
private var delay: uint = 3000;
private var repeat: uint = 0; //se va por todo el tiempo
private var myTimer: Timer = new Timer(delay, repeat);
public function clickM() {
myTimer.start();
myTimer.addEventListener(TimerEvent.TIMER, timerHandler);
}
private function timerHandler(e: TimerEvent): void {
//repeat--;
//statusTextField.text = ((delay * repeat) / 1000) + " seconds left.";
trace ( "simulate click...");
//dispatchEvent(new MouseEvent(MouseEvent.CLICK));
this.dispatchEvent(new MouseEvent(MouseEvent.CLICK, true, false));
}
}
}
Stage code, rojo & morado are movieclips:
import flash.events.MouseEvent;
stage.addEventListener(Event.ENTER_FRAME, myFunction);
var mano: clickM = new clickM();
mano.name = "mano";
addChild (mano);
morado.addEventListener(MouseEvent.CLICK, cl);
rojo.addEventListener(MouseEvent.CLICK, cl);
stage.addEventListener(MouseEvent.CLICK, cl);
function myFunction(event: Event) {
mano.x = mouseX;
mano.y = mouseY;
}
function cl(e: MouseEvent) {
trace("click over " + e.target.name);
}
If I click over morado or rojo, there's no problem - I can get their names. If I just let the code run, I can't get their names, I just get "mano", which is the custom cursor I'm using.
How can I get the desired behavior?
Regards.
Add mouseEnabled=false; inside clickM constructor. This should make Flash to ignore your mano in the event dispatch phase, so the underlying object should be the primary target if there's any, otherwise the target will be the stage. If your custom cursor contains more movie clips, you should also add mouseChildren=false;.
public function clickM() {
mouseEnabled=false;
// possibly add this too
mouseChildren=false;
myTimer.start();
myTimer.addEventListener(TimerEvent.TIMER, timerHandler);
}

Remove Child of Root actionscript3

I've created 4 instances of Notes and I have them moving to the right until their x value is greater than 100. Once they're there, how do I remove them? I ran a trace statement and confirmed that the parent of these instances is root (root1 to be exact). If I type
root.removeChild(this);
I get an error saying "call to a possibly undefined method removeChild"
If I type
removeChild(this);
I get an error saying "The supplied DisplayObject must be a child of the caller". Full code is posted below. The last line before the }'s at the end is the problem line. Thanks so much for the help!
package
{
import flash.display.Bitmap;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.utils.getDefinitionByName;
import flash.utils.Timer;
import flash.events.TimerEvent;
[Frame(factoryClass="Preloader")]
public class Main extends Sprite
{
private var speed:int = 8;
[Embed(source="../lib/Dodgethis.jpg")]
public var Notes:Class;
public var numnotes:Number;
public var timer:Timer = new Timer(500, 1)
public var rootContainer:DisplayObjectContainer = DisplayObjectContainer (root);
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
timer.start();
timer.addEventListener(TimerEvent.TIMER, testevent);
}
private function testevent(e:Event = null):void {
trace("testevent has run");
appear();
}
private function appear() {
var arr1:Array = new Array;
numnotes = 4;
for (var i = 0; i < numnotes; i++)
{
trace (i);
var nbm:Bitmap = new Notes;
stage.addChild(nbm);
nbm.y = i * 50;
arr1.push(nbm);
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
}
private function loop (e:Event):void {
this.x += speed;
trace(this.x) ;
if (this.x > 100) {
removeEventListener(Event.ENTER_FRAME, loop);
trace ("Event listener was removed");
//removeChild(this);
//rootContainer.removeChild (nbm);
/*trace(this.contains)
trace(this.name)
trace(this)*/
trace(this.parent.name); //root
removeChild(this);
}
}
}
}
Try using this in the loop function
e.target.parent.removeChild(e.target);
//or
stage.removeChild(e.target);
You're adding the notes to stage. So you need to remove them from stage.
stage.removeChild( note );
You can only remove a child from its parent, not from any other container. So calling removeChild on a different container will always fail

need some correction in Typewriter effect in flash.

I'm using the typewriting effect in that I need to reduce the speed of word printing. I don't know how to reduce the speed of content printing.
This is the code
var format : TextFormat = new TextFormat();
format.size = 14;
format.font = "Arial";
format.bold = true;
format.color = 0x00000;
var _textField : TextField = new TextField();
_textField.width = 400;
_textField.height = 200;
_textField.selectable = false;
_textField.wordWrap = true;
_textField.defaultTextFormat = format;
_textField.x = _textField.y =10;
addChild(_textField);
var _textLoader:URLLoader = new URLLoader(new URLRequest("text.txt"));
_textLoader.addEventListener(Event.COMPLETE, Init, false, 0, true);
function Init(e:Event):void
{
var _text = e.target.data;
_letters = _text.split('');
addEventListener(Event.ENTER_FRAME, Write, false, 0, true);
}
function Write(e:Event):void
{
if (_counter < _letters.length)
{
_textField.appendText(_letters[_counter]);
_counter++;
}
}
Well, since you're using an EnterFrame event you could just reduce the FPS of the SWF, but that probably is not what you want as it would reduce the speed of everything in the SWF not just the textfield printing.
Alternatively you can just maintain some counter variable to keep track of frames and only appendText every 10 frames or so. For example:
var currFrame:int = 0;
//...
function Write(e:Event):void
{
currFrame++;//increase the counter
if(currFrame > 10)
{//only write a letter every 10 frames
currFrame = 0;//reset the counter
if (_counter < _letters.length)
{
_textField.appendText(_letters[_counter]);
_counter++;
}
}
}
Adjust that '10' to change the speed (larger numbers = slower)
First of all, I don't see the variable _counter declared anywhere in the code.
That said, they are a few ways to make it go slower, this is one of the possibilities.
If the "_counter" var is smaller than the length of the string => add a letter.
So to make this go slower you can say:
If the "_counter" var is smaller than the length of the string => wait 2seconds and then add a letter.
You can do this, for example, with the setInterval function:
www.ilike2flash.com/2009/07/time-delay-in-actionscript-3.html
so your code will look something similar to this:
var _prevCounter = "";
function Write(e:Event):void
{
if (_counter < _letters.length && _counter != _prevCounter)
{
setInterval(addLetter, 3000);
_counter++;
}
}
function addLetter()
{
_textField.appendText(_letters[_counter]);
}
This was not tested and could cause some errors, never copy/paste if you don't understand what you are copy/pasting!
Good luck & hope this helps you on your way!
Just use the Timer event instead of the ENTER_FRAME event. You can define the "speed of word printing" as the timer delay.
const DELAY_BETWEEN_LETTERS:int = 100; // here you are setting 100 ms between each letter output
var timer:Timer = new Timer(DELAY_BETWEEN_LETTERS);
function Init(e:Event):void
{
var _text = e.target.data;
_letters = _text.split('');
timer.addEventListener(TimerEvent.TIMER, Write);
timer.start();
}
function Write(e:TimerEvent):void
{
if (_counter < _letters.length)
{
_textField.appendText(_letters[_counter]);
_counter++;
}
}
You could also use timers like in the following example:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.TextEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}// end function
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
var textField:TypewriterTextField = new TypewriterTextField();
textField.autoSize = TextFieldAutoSize.LEFT;
textField.border = true;
addChild(textField);
}// end function
}// end class
}// end package
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.text.TextField;
import flash.utils.Timer;
class TypewriterTextField extends TextField {
public function TypewriterTextField() {
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}// end function
private function onAddedToStage(e:Event):void {
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
}// end function
private function onKeyUp(e:KeyboardEvent):void {
e.preventDefault();
if (stage.focus == this) {
var char:String = String.fromCharCode(e.charCode);
if (char.match(/[a-zA-Z0-9\s\n]/) || e.charCode == 8) {
var timer:CustomTimer = new CustomTimer(e.charCode, 500, 1);
timer.addEventListener(TimerEvent.TIMER, onTimer);
timer.start();
}// end if
}// end if
}// end function
private function onTimer(e:TimerEvent):void {
var customTimer:CustomTimer = e.target as CustomTimer;
customTimer.removeEventListener(TimerEvent.TIMER, onTimer);
var charCode:uint = customTimer.object as uint;
var char:String = String.fromCharCode(charCode);
if (char.match(/[a-zA-Z0-9\s\n]/)) {
this.text += char;
}
else {
this.text = this.text.slice(0, -1);
}// end else if
}// end function
}// ende class
class CustomTimer extends Timer {
private var _cbject:Object;
public function get object():Object {
return this._cbject;
}// end function
public function CustomTimer(object:Object, delay:Number, repeatCount:int = 0) {
super(delay, repeatCount);
_cbject = object;
}// end function
}// end class