Awkwardness Between Scenes (What happened to my symbol?) - actionscript-3

Say we have a flash file, and all the code and objects on the file are described below:
Scene One:
only one symbol with the instance name "char" is on the stage
Code for Scene One:
import flash.events.Event;
stage.addEventListener(Event.ENTER_FRAME,update);
function update(e:Event){
trace(char);
}
play();
Scene Two:
only one symbol with the instance name "char" is on the stage
Code for Scene Two:
stop();
If you try this out yourself, you will find that the Flash traces the object char to be "null" for a split moment, and then traces it properly once it has discovered the symbol on the second scene. Does anyone know why this is, since there is a symbol with the instance name "char" on both consecutive scenes?

I could not find any specific documentation related to this other than that which is provided by Adobe for the Event class, but I believe what you are experiencing is related to the differences between the events Event.ENTER_FRAME and Event.EXIT_FRAME and how the Flash runtime initlializes objects for use.
I ran a test using your code with Event.ENTER_FRAME, and experienced the same results you encountered; however, when I used the Event.EXIT_FRAME event, the display object did NOT trace as null at all.
Then I took it a step further and set up my timeline exactly as yours; however, changed the event code in Scene 1, Frame 1 to be:
import flash.events.Event;
import flash.display.MovieClip;
stage.addEventListener(Event.ENTER_FRAME,update);
stage.addEventListener(Event.EXIT_FRAME,update);
function update(e:Event){
if( e.type == Event.ENTER_FRAME ) {
trace("ENTER FRAME: " + currentScene.name);
}
else if( e.type == Event.EXIT_FRAME ) {
trace("EXIT FRAME: " + currentScene.name);
}
trace(char);
}
play();
And when executed noticed something interesting:
EXIT FRAME: Scene 1
[object MovieClip]
ENTER FRAME: Scene 2
null
EXIT FRAME: Scene 2
[object MovieClip]
ENTER FRAME: Scene 2
[object MovieClip]
EXIT FRAME: Scene 2
[object MovieClip]
...
The Event.ENTER_FRAME event was never called on Scene 1. Probably because that event had already occurred prior to the code on Scene 1, Frame 1 being executed.
The null reference was actually in relation to the char instance not yet initialized on Scene 2. Once the playhead was exiting the frame, probably when the instance was able to be referenced, it read as a MovieClip.
These behaviors are [probably] the reason why so many people recommend using a document class to add objects to the stage as necessary, attaching listeners to the Event.ADDED_TO_STAGE to know when they were added, so that you can handle functionality at the proper point in time that they are actually added to the stage; instead of waiting for the object to be able to be referenced via the timeline. My best guess is that if the ENTER_FRAME event had fired on Scene 1, it too probably would have traced null for char, just like it traced null on Scene 2. It may be null because the display object on the stage isn't yet initialized and so the code reference to that object isn't yet initialized either.
I wish I had more time to afford to investigating this for you, but this is the best test and explanation I could come up with to describe the behavior you are experiencing.
Cheers!

Related

Type coercion in AS3 Flash

I am making a simple jumper game in AS3 in Flash, and at this moment everything works but I get this note:
Error #1034: Type Coercion failed: cannot convert 2 to flash.display.Scene.
at scratch_theGame_kat_fla::MainTimeline/startkeyPressed()
I understand there must be a type of an instance that is incorrect when this note appears, but as I search around in my code to find the perpetrator, I realized the "2" that it must be referring to is this:
function startkeyPressed(event:KeyboardEvent):void
{
if (event.keyCode,Keyboard.ENTER)
{
trace("new player");
startGame = true;
gotoAndPlay(( 1, Scene (2)));
}
};
This part of the code is what makes it go (when ENTER is pressed) from scene 1 to scene 2, where the actual game begins. Does anyone have any idea what I should change?
That line makes absolutely no sense in terms of AS3 logic:
gotoAndPlay(( 1, Scene (2)));
If you look into "Example" section of the official gotoAndPlay(...) help, there are two possible uses of this method:
You pass a single "frame" argument: it is either a 1-based int frame index, or it is a String label of the desired frame.
Two arguments where the second one is the String name of a Scene that is a portion of the main timeline, and the first is, again, the frame index or frame label inside the said Scene.
Now let's decipher what you have there. You are passing as gotoAndPlay(...) arguments. Feel the difference:
// Your version: one argument grouped with additional brackets.
gotoAndPlay(( 1, Scene (2)));
// Alternate version: no additional brackets, two arguments.
gotoAndPlay(1, Scene (2));
Then, what is Scene (2) expression, you might probably ask? It is called typecasting, an operation where you:
Explicitly state the exact class of something you are working with, because there are moments where compiler does not know exactly, like what is the exact class of Event.target object. There's a nice example, well explained: AS3: cast or "as"?
You want to explicitly convert data from one type to another (the said type coercion), mostly used between int or Number and String types.
Lets see:
function onEvent(e:Event):void
{
// Explicit typecasting.
MovieClip(e.target).nextFrame();
// Explicit typecasting through "as" operator.
var aFrame:int = (e.target as MovieClip).currentFrame;
// Explicit type conversion.
trace("The current frame is", String(aFrame));
So, you are trying to convince Flash Player that integer value 2 is somehow a Scene object, but there's no way it is, hence the exception thrown by the Flash Player because it does not understand what do you want it to do.
The correct notation of what you are trying to achieve (moving the playhead to the second Scene) would be probably:
gotoAndPlay(1, "Scene2");
The "Scene2" argument is a string literal that should represent the exact name of that second scene of yours, I couldn't know what it is but it should probably be named "Scene2" or "Scene 2" by default.

Exit Event when move to other frame in AS3

I trying to get an event when move from one frame to another in AS3.
I have tried with the EXIT_FRAME it always calling.
I need to get state when move from one frame to another.
addEventListener(Event.EXIT_FRAME,exitfunc);
function exitfunc(e:Event):void{
trace("EXIT_FRAME");
}
as Nagarajan sugges, you can dynamically add a script to a frame.
For example in your main class
package {
import flash.display.MovieClip;
public class Test extends MovieClip
{
public function Test()
{
this.addFrameScript(4,frameFunction); // (add script to frame 5, zero based)
}
private function frameFunction():void {
trace ('Do something when play head enters frame 4')
}
}
}
because their names are misleading. Event.EXIT_FRAME doesn't execute once when the playhead exits a frame. it executes repeatedly.
likewise, Event.ENTER_FRAME doesn't execute once when the playhead enters a frame. it executes repeatedly.
you can execute a function when the playhead enters a a frame by adding a function call to the frame:
f(); // attached to a frame will call the function f when the playhead enters this frame. and there are other ways to do this.
you can execute a function when a playhead exists a frame by invalidating the stage and using a render event when a goto is executed:
stage.invaidate();
this.addEventListener(Event.RENDER,ExitingF);
this.gotoAndPlay('whatever');
function exitingF(e:Event):void{
// this code executes when this frame is exited and 'whatever' is rendered
(=displayed);
}
There's only one good way but that might be beyond your skill level. Create a class that extends MovieClip and override the gotoAndStop and gotoAndPlay methods then simply make them dispatch a custom event (don't forget the call to super). That custom event can carry the frame label, index, etc ... You'll have to make sure your MovieClips/Document class implement that class and everything will be done automatically.
This will allow you to keep track of when you leave a frame and move to another with a call to gotoAndStop or gotoAndPlay. If you only want to keep track of normal playhead move then the ENTER_FRAME event is enough.

Error code #1009: Cannot access a property or method of a null object reference

I got an error on the output window. I got serval layers, the first layer on frame 2 there is this function wich goes to frame 3 and stops(Located below). But the frame 3 is located on a diffrent layer. The frame 3 dosent has any codes of the frame 2, its simply a empty layer with some graphics. I think it is trying to run the code from frame 2, but it dosen't finds it. I dont know how to solve this problem, but it slows down the application, because the error is looping.
When it goes to a different frame i get the error
(Cannot acces a property of null)
stage.addEventListener(Event.ENTER_FRAME, SquareCircleHit);
function SquareCircleHit(event:Event):void{
if (square.hitTestObject(circle)) {
gotoAndStop(3);
}
}

Property null is read-only

It might not be the null property, but here's what's up:
Let's say I have this code -
1. someclipthatsinanarray[i].addEventListener(Event.ENTER_FRAME, arrayframe);
2. function arrayframe(e:Event):void
3. {
4. e.currentTarget.removeEventListener(Event.ENTER_FRAME, arrayframe);
5. e.currentTarget.parent.removeChild(e.currentTarget);
6. e.currentTarget = null;
7. }
- and pay attention to line six. I run this in the debugger and get this error:
Error 1119: Line 6, arrayframe: Property is read - only.
What is read only? If null is read - only, then why?
currentTarget is a property of the Event. It is read only and you cannot modify that property.
Here is what I think you desire to do :
someclipthatsinanarray[i].addEventListener(Event.ENTER_FRAME, arrayframe);
// event handler
function arrayframe(e:Event):void
{
var clip:MovieClip = e.currentTarget as MovieClip;
clip.removeEventListener(Event.ENTER_FRAME, arrayframe);
clip.parent.removeChild(clip);
clip = null;
}
As mentioned in the comments this line is not doing what you likely believe it is :
clip = null;
clip was just a local reference to that MovieClip, just the same as the element in the array is just a reference to the MovieClip. So setting clip to null, is not deleting the MovieClip, it's merely just nulling out our reference, which really is not even needed since it's a local variable and it's scope ends upon completion of the handler.
An object is only truly marked for garbage collection once there are no references to the object remaining.
Also important to note that being on the Display List of another object is considered a reference.
e.currentTarget is a property of your event. It is read-only because an event should not be modified after having been dispatched.
Don't worry though, as soon as all the functions listening to this particular event are finished executing their code, the reference to your clip stored in the event will be garbage collected.

illogical remove child error when looking through DisplayObjects, flash AS3

Argument Error #2025:
The supplied DisplayObject is not a child of the caller
In my program I have a structure of display objects representing enemy units on screen, arranged like this:
0: "enemy handler" ➔ [object EnemyHandler]
0: "enemy" ➔ [object Enemy1]
0: "enemy's skin"(MovieClip) ➔ [object EnemySkin1]
0: "skin image" ➔ [object Shape]
The document class contains one instance of EnemyHandler, and it contains multiple instances of Enemy1, Enemy2 ect.. each of these has a skin MovieClip attatched.
The Enemy class (from which Enemy1/2/3 ect inherits) contains a property expired, which is set to true, from within the Enemy class (enemy.update), when the Enemy has reached a certain point.
In the enemy handler class is a function, and is where the problem lays, that loops through an array of all the Enememy display objects, updating there position and then,
if(tempEnemy.expired)
{
tempEnemy.destroy(); // removeChild(skin)
enemyList.splice(tempEnemy);
removeChild(tempEnemy)
}
when run, if all of the enemies reach the end-point in the order in which they were created, there is no problem, however if one for instance travels faster, and reaches the endpoint before, an error #2025 (The supplied DisplayObject is not a child of the caller) is thrown.
I've narrowed it down to the fact that the program attempts to remove the enemy twice, for reasons that i cannot discern. It loops through and removes the desired enemies, then attempts to remove it again, even though it is spliced from the array (which happens correctly, and the first attempt at removeChild is allways succesfull)
It is probably something fairly simple on my behalf, so forgive me, but any help is appreciated. here's the files;
[code on frame]
pastebin.com/vcXzQpr9
[Enemy.as]
pastebin.com/RNXgK8Ex
[EnemyHandler.as]
pastebin.com/6fytxbMW
[Enemy0.as] & [Enemy1.as]
pastebin.com/5bW3Aa0H
[Utils.as]
pastebin.com/PQ2LPV0v
[traceDl.as] {debuggnig the display list}
pastebin.com/9vQGKcYP
Array.splice() takes an integer for the position where you want to start splicing, then how many items you want to remove. So you need to use
enemyList.splice(enemyList.indexOf(tempEnemy), 1);
instead of passing the Enemy instance. It may have appeared to work correctly when the order didn't change, because coercing tempEnemy to int (which splice() will have done automatically) produces a zero, so in your destroyEnemy function it was actually just removing the first item in the list each time.