Why does this not work? Flash As3, if added child is at frame something? - actionscript-3

This is my code help me please its really frustrating!
I have a movieclip in my library and added it with AS3 to the stage.
That part was easy. But now i want to control that movieclip.
If introScene "introClass" Reaches frame 120 then i want to remove that movieclip
and replace it with another one. The problem is the if statement doesn't work.
I also tried getChildByName but that didn't work either.
var introClass = new introScene;
addChild(introClass);
introClass.x = 640;
introClass.y = 387;
/*******INTRO-SCENE*******/
introClass.addEventListener(Event, introLoaded);
function introLoaded(event):void{
if(introClass == 120 ){
trace("Frame Reached")
}
}
i tried this and this also doesn't work :(
introClass.addEventListener(Event, introLoaded);
function introLoaded (e:Event):void{
if(MovieClip(introClass).currentFrame == 120){
trace("120 complete")
}
}

This is wrong statement:
introClass.addEventListener(Event, introLoaded);
You need to pass a string to addEventListener. Event type name is converted to a string at runtime which adds a event listener to "flash.events.Event" or something. And your object obviously doesn't have this event. You need to use Event.ENTER_FRAME for example.

Related

AS3: how do i stop two of the same function from playing at once?

i am using AS3 to create a function that will automatically play a movieclip all the way through and then remove it. my project is going to have a lot of animated cutscenes, so id like to be able to call this function, use the cutscene id like as a parameter, and then move on to the next. the problem is, im trying to use the function multiple times in a row to play clips sequentially, but they're all playing at the same time. is there a fix, or a better way to do this altogether?
playClip(new a_walk); //find a way to make these stop playing at the same time
playClip(new a_door);
//a_walk and a_door are the AS linkage class names for the movieclips im referring to
function playClip (clip:MovieClip):void {
addChildAt(clip, 0);
clip.mask = myMask;
clip.x=412.4;
clip.y=244.5;
clip.addEventListener(Event.ENTER_FRAME, checkframes);
function checkframes(event:Event) {
if (clip.currentFrame == clip.totalFrames) {
//trace("wow! youre an idiot!");
if (clip.parent) {
clip.parent.removeChild(clip);
trace (100);
return;
}
}
}
}
Sounds like you want a mechanism to play a queue of MovieClips? If so, here is a way you can accomplish this:
//create an array with the clips you want to play (in order), in my example here, the items can be a MovieClip derived Class, or a MovieClip instance
var playQueue:Array = [a_walk, a_door];
//create a var to store the currently playing clip
var currentClip:MovieClip;
playNext(); //call this when you want the queue of clips to start playing
function playNext():void {
//if there was an item previously playing (currentClip has a value), stop it and remove it/dispose of it
if(currentClip){
currentClip.stop(); //stop it from playing
currentClip.addFrameScript(currentClip.totalFrames-1, null); //remove the frame script that was added
currentClip.parent.removeChild(currentClip); //remove it from the display
currentClip = null;
}
//check if there's anything left to play
if(playQueue.length < 1) return;
var nextItem:* = playQueue.shift(); //shift retrieves and removes the first item in the array;
if(nextItem is Class){
//if it's a class, instantiate it
currentClip = new nextItem();
}else{
currentClip = MovieClip(nextItem);
}
//initialize the movie clip
addChildAt(currentClip, 0);
currentClip.gotoAndPlay(1);
//this is just what you were doing before:
currentClip.mask = myMask;
currentClip.x=412.4;
currentClip.y=244.5;
//add a command on the last frame of the movie clip to play the next item in the queue
currentClip.addFrameScript(currentClip.totalFrames-1, playNext);
//addFrameScript is 0 based, so 0 would refer to the first frame. This is why we subtract 1 to get the last frame
}
I should note, that addFrameScript is an undocumented function. It serves as a nice shortcut so you don't have to have an ENTER_FRAME listener checking currentFrame vs. totalFrames. Being undocumented however, one can not count on it's continued existence in future versions of the Flash/AIR runtimes (though it's been around for a long long time)
note
This answer is a work in progress. I'm waiting on a response from the OP.
// playClip(new a_door); don't call this yet, or they will just both play.
var clipData:CustomClass = new CustomClass(); // add an instance of a custom class to hold the value of the movie
//clip being played (so that you can use this value later in the event handler.)
// it will also hold a value of the next clip
clipData._currentClip = a_walk;
clipData._nextClip = a_door;
playClip(new a_walk);
function playClip (clip:MovieClip):void {
addChildAt(clip, 0);
clip.mask = myMask;
clip.x=412.4;
clip.y=244.5;
clip.addEventListener(Event.ENTER_FRAME, checkframes);
}
function checkframes(event:Event) {
if (clipData._currentClip.currentFrame == clipData._currentClip.totalFrames) {
//trace("wow! youre an idiot!");
if (clipData._currentClip.parent) {
playClip(clipData._nextClip);
clipData._currentClip.parent.removeChild(clipData._currentClip);
clipData._currentClip = clipData._nextClip; // moves the clips down
//clipData._nextClip = here we have
//a problem. Do these clips play in a set
//order, first to last? Or do the play out of
//order jumping back and forth? If so, how
//are you planning on controlling which clip
//plays next?
trace (100);
return;
}
}
}
I haven't checked this in Flash yet to see if it works, but I noticed that you are defining a function inside another function, which I don't think is good practice, so this might clean things up for you. Give it a try and let us know.
I'll try to fix my code above when I get a chance. In the meantime, you answered my question about playing the clips in order, so a simple solution would be to put all the clips in an array and then play them by playClip(clipArray[i]) and then when the clip ends and gets removed, do i++ and call the same function playClip(clipArray[i]) which will play the next clip in the array.

Unable to reference MovieClip inside Button AS3

I have this annoying issue that I hope someone might be able to help me with.
I have a mute button that I created and I have another movieclip inside of that button. All I want it to do is when I toggle the mute the movieclip inside will go to the according frame.
However, every time I try to call the movieclip inside of the button, this error comes up:
Access of possibly undefined property mcMuteToggle through a reference with static type flash.display:SimpleButton.
The instance name for the movieclip within is "mcMuteToggle".
Why not make movieClips that act like buttons?? Since I dont think actual button (simpleButton) types can deal with sub-MovieClips (especially if they too have code). Even if possible don't do it, I can predict a mess whereby Button does things it shouldn't do depending on what code you have in those MClips.
Try an alternate button method, just for a test... You didnt show any test code to work with so I will make assumptions..
1) Make a shape (rectangle?) and convert to MovieClip (or if all coded, then addchild shape to new MovieClip). Let's assume you called it mc_testBtn.
2) Make that MC clickable by coding mc_testBtn.buttonMode = true;
3) Add your mcMuteToggle inside the mc_testBtn
(or by code: mc_testBtn.addChild(mcMuteToggle);
Now you can try something like..
mc_testBtn.addEventListener (MouseEvent.CLICK, toggle_Mute );
function toggle_Mute (evt:MouseEvent) : void
{
if ( whatever condition )
{
mc_testBtn.mcMuteToggle.gotoAndStop(2); //go frame 2
}
else
{
mc_testBtn.mcMuteToggle.gotoAndStop(1); //go frame 1
}
}
This is likely due to strict mode. You can either disable it in the ActionScript settings dialog, access it with a different syntax myButton['mcMuteToggle'], or make a class for the symbol that includes a property mcMuteToggle.
You can also check to make sure the symbol is actually on the stage and that clip is actually in the button:
if('myButton' in root) {
// ...
}
if('mcMuteToggle' in myButton) {
// ...
}
i think u just overwrite that codes. You u can use something like this:
var soundOpen:Boolean = true;
var mySound:Sound = new Sound(new URLRequest("Whatever your sound is"));
var mySc:SoundChannel = new SoundChannel();
var mySt:SoundTransform = new SoundTransform();
mySc = mySound.play();
mcMuteToggle.addEventListener(MouseEvent.CLICK, muteOpenSound);
function muteOpenSound(e:MouseEvent):void
{
if(soundOpen == true)
{
mcMuteToggle.gotoAndStop(2);
/*on frame 2 u need to hold ur soundClose buton so ppl can see :)*/
soundOpen = false;
mySt.volume = 0;
mySc.soundTransfrom = st;
}
else
{
mcMuteToggle.gotoAndStop(1);
soundOpen = true;
mySt.volume = 1;
mySc.soundTransfrom = st;
}
}
This is working for me everytime. Hope u can use it well ;)

AS3 MouseEvent and weakReference

Ok, here's a weird thing:
I have a class, which is a MovieClip that has 2 children, MovieClips also.
I add the children to him and base MovieClip to stage.One of the children is animated.
All is perfect.
Now when I add MouseEvent.MOUSE_UP on the children, all works fine.
Yet if I set useWeakReference to true (the 5th parameter) mouse event does not fire anymore,but the items are on stage. Basically, somehow, they are not in the memory.
Of course if I add a simple onEnterFrame that does nothing to base MovieClip, it traces the MovieClip, yet the MouseEvents does not trigger. That means the object is still there, but somehow for flash is not
Now, this is a simplified concept, that is easy to clean, but my code is very big and a simple removeEventListener is not a solution. At least not a simple one.
What are your suggestions to work around this?
I'm not sure how complex your code is, but if each movieclip has MOUSE_UP event handler - some function, you could indeed use removeEventListener MOUSE_UP function. For instance:
var mc:MovieClip = new MovieClip();
mc.addEventListener( MouseEvent.MOUSE_UP, onMU );
function onMU(e:MouseEvent){
var target = MovieClip(e.currentTarget);
target.removeEventListener( MouseEvent.MOUSE_UP, onMU );
}
This way you can have multiple movieclips and remove listeners without knowing object name.
Alternatively you could modify your code to add aray of all added events and then listen to REMOVE_FROM_STAGE event. Something like this:
var mc:MovieClip = new MovieClip();
mc.events = [];
mc.events.push( { evt: MouseEvent.MOUSE_UP, fn: onMU } );
mc.addEventListener( MouseEvent.MOUSE_UP, onMU } )
//or use events array reference to keep events and functions in one place.
//when object is removed you can iterate through events array and automatically remove
//all listeners
Another alternative would be to create Class that extends MovieClip - but since your code is huge you probably don't want to do that.
You can also look on Robert Penner's Signals library, which is interesting alternative to AS3 events. (https://github.com/robertpenner/as3-signals)

Removing an event listener as well as a sprite at the same time AS3

I’m having trouble removing the an event listener as well as the sprite at the same time. I currently get an error:
TypeError: Error #1009: Cannot access
a property or method of a null object
reference.
And if I comment out removeChild, I have no error but, obviously, the sprite remains on the screen. Any ideas how I can rid myself of that error?
//Bullet extends Sprite Class
bullet:Bullet = new Bullet();
mc.addChild(bullet);
bullet.addEventListener(Event.ENTER_FRAME, shoot);
function shoot(e:Event):void {
var shot:Bullet = e.currentTarget as Bullet;
//check shot is outside the frame
if (shot.x < 0 - shot.width || shot.x > stage.stageWidth || shot.y > 525)
{
//trying to remove the thing and it's listener
e.currentTarget.removeEventListener(e.type,arguments.callee);
e.currentTarget.parent.removeChild(shot);
}
else
{
shot.setInMotion();
}
}
Apart from a missing var before bullet:Bullet, I don't see anything wrong in the example code. You should set a breakpoint right after:
var shot:Bullet = e.currentTarget as Bullet;
And figure out why shot is null. I suspect there is something amiss in a piece of code outside of the little bit you're providing as the example. If the code is working with only the removeChild line commented out, it tells me that e.currentTarget is not null, but that it's also not a reference to an instance of type Bullet (i.e. the "as" cast is returning null).
Try reversing these lines
Maybe the reference to e.currentTarget is getting lost through the object references
e.currentTarget.removeEventListener(e.type,arguments.callee);
e.currentTarget.parent.removeChild(shot);
to
e.currentTarget.parent.removeChild(shot);
e.currentTarget.removeEventListener(e.type,arguments.callee);

ActionScript 3 name property is not returning the right name...?

I experienced a problem with the name property in as3, I created this "dot" movieclip and I exported to a class,
then I anonymously created a bunch of dots using a loop. I assigned numbers as name to each dots
private function callDots(num:Number):void
{
for (var i = 0; i < subImagesTotal[num]; i++)
{
var d:Dot = new Dot();
d.x = i*23;
d.y = 0;
d.name = i;
dotContainer.addChild(d]);
}
}
so far so good, I checked that if I trace the name here, I will get the number I want.
However, it's not giving me the numbers if I trace it in other functions.
I added all of my dots to "dotContainer", and if I click on one of the dots, it will call this function
private function callFullSub(e:MouseEvent):void
{
var full_loader:Loader = new Loader();
var temp:XMLList = subImages[sub];
var full_url = temp[e.target.name].#IMG;
full_loader.load(new URLRequest(full_url));
full_loader.contentLoaderInfo.addEventListener(Event.INIT, fullLoaded);
}
e.target.name is suppose to be numbers like 1 or 2, but it's giving me "instance66" "instance70" and I
have no idea why. Because I did the same thing with loaders before and it totally worked.
Any ideas? Thanks.
christine
The e.target returns the inner most object clicked on, this could be a TextField, another MovieClip or posibly a shape (I'm not 100% of the last one) inside the "Dot".
To prevent this you could try to set the mouseChildren property to false on the Dot's when you add them. This should insure that nothing inside the dots can dispatch the click event, and thus the Dot's should do it.
Perhaps you could also in the event handler verify the target type with code like this:
private function callFullSub(e:MouseEvent):void
{
if(!e.target is Dot)
throw new Error("target in callFullSub is not Dot but: " + e.target.toString());
//The rest of you code here
}
The answer is [e.currentTarget.name] I perform this all the time!
Should return "Dot1" "Dot2", etc.
If the value you wish to return is a number or other data type other than a string (name of object) use [e.currentTarget.name.substr(3,1).toString()]
Should return 1, 2, etc.
Navee
I tried to reproduce your problem first with Flex using runtime created movieClips and then with Flash using Dot movieClip symbols exported for ActionScript. Neither application exhibited the problem.
You may already know names like "instance66" "instance70" are default enumerated instance names. So, whatever is dispatching the MouseEvent is NOT the dot instance. Perhaps you are unintentionally assigning callFullSub to the wrong targets, maybe your containers? Try assigning it to dot instance right after you create them, like this:
private function callDots(num:Number):void
{
for (var i = 0; i < subImagesTotal[num]; i++)
{
var d:Dot = new Dot();
d.x = i*23;
d.y = 0;
d.name = i;
d.addEventListener(MouseEvent.CLICK, callFullSub);
dotContainer.addChild(d]);
}
}
Be sure to temporarily comment out your original assignment.
Try this might work,..
d.name = i.toString();
You have not shown enough of your code for me to be able to give you a DEFINATE answer, I will however say this.
//After you create each loader you need to set its mouseEnabled
//property to false if you do not want it to be the target of
//Mouse Events, which may be superseding the actual intended target;
var full_loader:Loader = new Loader();
full_loader.mouseEnabled = false;
//Also you could name the loaders and see if what comes back when you click is the same.
ALSO! Add this to your Mouse Event handler for CLICK or MOUSE_DOWN:
trace(e.target is Loader); //If traces true you have an answer
I believe that the mouse events are being dispatched by the Loaders.
please provide more of your code, the code where the Loader.contentLoaderInfo's COMPLETE handler fires. I assume this is where you adding the loaders to the display list as I cannot see that now.