Type coercion in AS3 Flash - actionscript-3

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.

Related

Actionscript 3 - How to access integer variable in main timeline from inside MovieClip

First, sorry if my english is bad and I'm new to Actionscript 3.
I have a movieclip, I give it an instance name "symbol1" which include a code inside it, like this :
var a: int = 2;
var b: int = 3;
var total: int = a + b;
How can I access the "total" integer variable inside that movieclip in the main timeline? I try to trace it but the result is 0. In the main timeline I wrote this code :
trace(symbol1.total);
I appreciate the help, thanks
The "problem" is the order of execution of frames. The parent is executed first.
The value is 0 and not undefined because the property does indeed exist since the creation of the object which happens in a previous separate step.
You should be able to verify that by stepping through your code with the debugger.
I've made 6 games. each game is in the MovieClip including the game functions, times, scores, variables, etc. I want the total score of each game summed outside each MoviClips, which is in the main timeline. is there a solution to that problem?
This makes your timing problem even more apparent.
You arrive at a frame, which contains a game and you immediately want to access the total score of it. It should be obvious that the game first has to be played in order to obtain a score from it.
Asking a newborn baby what his favourite moment in the first 60 years of his live was doesn't make much sense.
You have to notify the main timeline that the game was finished. The best way to do this is to dispatch an Event from the game. Frames are totally unnecessary.
Your code could look something like this:
var game:Game = new Tetris();
addChild(game);
game.addEventListener(GameEvent.FINISH, onFinish);
function onFinish(e:GameEvent):void
{
trace("finished game with score " + game.score);
}
If you want to update the exterior score sum while the game is running (to immediately reflect any change in the score, not just when the game is finished), your best bet is to create a ScoreModel for the score which you pass to the game, the Game. The Game modifies the ScoreModel, which in turn causes it to dispatch Events:
var score:ScoreModel = new ScoreModel();
var game:Game = new Tetris(score);
addChild(game);
score.addEventListener(Event.CHANGE, onScoreChange);
function onScoreChange(e:Event):void
{
trace("score changed to " + score);
}
Both examples are "what your code could look like"-type of examples. There are many questions about how to dispatch events that explain how to do this in more detail.
Something that came up in the comments from #Jezzamon:
I'm pretty sure you're accessing the variable total correctly, otherwise I would expect it to cause an error (you can test this by trying to run trace(symbol1.variableNameThatDoesntExist)).
No, there cannot be an error for accessing a variable as seen in the question. The reason for that is that the property is accessed on a MovieClip object, which is a dynamic class. As such, the compiler doesn't know if accessing a particular property is valid, because that can change at runtime. And because nothing else relies on the value to be valid, there isn't a runtime error either.
Here's some example code to illustrate this:
trace("toString: " + {}.toString); //toString: function Function() {}
trace("bananas: " + {}.bananas); //bananas: undefined
This is one of the reasons why using MovieClip can be a bad idea. In addition to that, the Flash IDE modifies the code behind the scenes. That can lead to unexpected execution of code. A purely code based workflow sure is advantageous in this regard and recommended.

How to pass object, MouseEvent.CLICK and function to trigger

I want to pass to function object, const of type MouseEvent.CLICK and function to trigger. In my case:
my class Assistant:
public static function addEventListenerTo(obj:Object, MouseEventConst:String, functinToTrigger:Function) {
obj.addEventListener(MouseEventConst, functinToTrigger:Function);
}
and my class Engine which invokes
Assistant.addEventListenerTo(deck,"MouseEvent.CLICK",showObject);
Please give me advice how to make it work. Thanks.
In the code you provide there is one compiler error (the one Tahir Ahmed pointed to in his second comment).
Fixing this by removing the second :Function in the first code block:
public static function addEventListenerTo
(obj:Object, MouseEventConst:String, functinToTrigger:Function)
{
obj.addEventListener(MouseEventConst, functinToTrigger);
}
will let the code compile. (I wrapped the Method signature to avoid the scrollbar, this is not required to make it compile.)
The other major problem is a configuration error (or maybe a typo): the one about MouseEvent.CLICK. (the one Tahir Ahmed pointed to in his first comment)
Looking at the documentation it is defined to have the value "click" (a String literal following the AS3 convention of the lowercase constant name). So to pass it to your method you can either put in a reference to the constant by writing MouseEvent.CLICK (without the "s around it) or reach the same goal with passing its value by writing "click".
As using the reference will prevent mistyping because the compiler checks it, the first approach should be preferred.
So calling the Method should look like this:
Assistant.addEventListenerTo(deck, MouseEvent.CLICK, showObject);
If you want to know why your version didn't work you should read a simple introduction to AS3 Events and EventDispatchers. As a short hint: if deck would dispatch an Event that has its type property set to "MouseEvent.CLICK" your listener would get fired.
While you are at it, you could improve the quality of your code by to major things:
the first one is about avoiding getting runtime Errors and prefering compile time errors: Not every instance of type Object has a method called addEventListener. In your current code, when you pass an instance to Assistant.addEventListenerTo as first parameter, that doesn't have this method (e.g. {} or an instance of type Array), the error will get thrown while your swf is displayed and it might stop displaying anything and might show an error message to the user.
If the type of the parameter is IEventDispatcher instead, the compiler will already tell you that you passed an incompatible instance.
The second one is about names and conventions, which helps other developers to read your code (an having more fun helping you).
what you called MouseEventConst is called an event type in AS3, which provides a better name for a parameter, as it being a String nobody stops anybody from passing contants of other event types like Event
the functionToTrigger is what is called a listener (or event listener)
the first letter of parameter names should be lower case
So if I would have written the static method it would look like this:
import flash.events.*;
public class Assistent{
public static function addEventListenerTo
(dispatcher:IEventDispatcher, eventType:String, listener:Function)
{
dispatcher.addEventListener(eventType, listener);
}
}

Having problems with hitTestObject-ing a child

I've just started to learn actionscript for a month or so, and I've been stuck on this part of the code for about 2 days now ><
So basically, I wanted to write a hitTestObject in a movieclip ("fire_mc") to detect if it overlaps the the child I added on stage (enemy)
So here's what I wrote in the main stage...
var newtarget:enemy=new enemy();
stage.addChild(newtarget);
newtarget.x=40;
newtarget.y=30;
and every time I traced the newtarget in the fire_mc, it turns out to be NULL...
So should I be tracing enemy or newtarget? (Cuz I tried both and nothing works).
And how can I hitTestObject in the fire_mc movieclip?
Is it possible for me to hitTestObject newtarget if I were to create multiple newtarget-s?
If not, what should I do?
And can someone tell me the difference between root, and MovieClip(root) (Because sometimes in a movieclip I have to use the former one to work, and sometimes the latter, and I have no idea why cuz I'm all referencing to the same place)
Sorry for these simple and lengthy questions, I'm really just a noob and I tried looking up for answers in the web for hours, but nothing helpful turned up><
Thanks in advance :)
In this statement
var newtarget:enemy=new enemy();
var - keyword used to define varibles, newtarget - variable name in which pointer to new class instance stored, :enemy - data type (the class name), new - keyword used to create new class instances, and finally enemy is class constructor (by the way there is a rule of good manners by which class names are capitalized)
So answer for you question which should you use when you want check is some is overlapping is 'newtarget'.
Now about hit test - all you need do to check if two objects hit each other is correctly use their references from the part of project where your code is writen.
For example if you have your fire_mc on MainTimeline created by IDE, and code of creation of you enemy instance stored in newtarget sameplace, then if you check will be placed in frame of MainTimeline where both object present it will be like this
fire_mc.hitTestObject(newtarget);
or this
newtarget.hitTestObject(fire_mc);
All these statements give you same result - if objects intersect each other you have true returned.
If you created 'newtarget' on MainTimeline and checks will be from fire_mc (which is on MainTimeline to) frame, then code will something like that
this.hitTestObject(MovieClip(root).newtarget);
Now about root. Primarily it is a property of DisplayObject in which reference to the top-most display object in swf-file structure is stored. So as such it is inherited by all child classes. So here's the trick. When you try get your objects in swf structure using root here the differences are based on the fact that root always return object as DisplayObject and that means what if you object contains something that DisplayObject shouldn't you can't get it. So you must convert returned reference to need data-type usign MovieClip(...).

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.

1067: Implicit coercion of a value of type Class to an unrelated type flash.display:DisplayObject

So for instance, I've got three .as files called 'Helicopter.as, Game.as, Blue.as'
and I also have a .fla file called Helicopter.fla (These files are all suppose to link together, to make the helicopter game) . In the Game.as file, I have the following;
if (blue1.hitTestObject(Helicopter))
{
trace("YOU HIT THE BLOCK!");
Helicopter.x = 76;
Helicopter.y = 217;
}
I have drawn the so called 'Helicopter'^ using API in a different file called Helicopter.as using this code;
graphics.beginFill(0x00FF00);
graphics.drawCircle(0, 60, 35);
graphics.endFill();
However, I originally had the "Helicopter' symbol drawn in the Helicopter.fla file (which I've now deleted), and now that I've drawn the 'Helicopter' using API, I get this error;
''1067: Implicit coercion of a value of type Class to an unrelated type flash.display:DisplayObject.''
Flash doesn't recognise the original Helicopter symbol (in the Helicopter.fla file, because I deleted it). But I want the system to detect the 'circle' drawn using API (In the Helicopter.as file). And I have no idea how to how to name the API drawn circle 'Helicopter', thus I'm getting an error. So how do I name the API circle to 'Helicopter', so the Game.as file recognises it. If you have no idea what I'm talking about, then don't worry, because I don't know too. Thank you. If you want, I can paste all the code I've done so far.
Helicopter is a class not a variable, therefore you cannot assign Helicopter.x. You need to create a variable var heli:Helicopter = new Helicopter(); and use heli.x
it also could be that you're not following the programming standards, and Helicopter is in fact a variable and not a Class, though the error seems to indicate otherwise.