How to remove element from Array and child from stage - actionscript-3

So I am currently attempting to remove an element from the array 'zombie_horde' as well as remove the child from the stage. My aimed result, a movie clip that is part of an array israndomly played and when finished playing, the frame changes to a gameover frame.
This is my code:
part of the big loop:
for each (var zom:Betherino in zombie_horde)
{
var frame = zom.currentFrame
trace(frame)
if(frame == zom.lastframe)
{
updatearray()
}
else{
zom.gotoAndStop(frame+1)
}
functions:
function updatearray()
{
zombie_horde.splice();
trace('spliced')
}
function removeBetherino()
{
stage.removeChild(Betherino)
}
This is what I have so far. I am wondering how I am supposed to continue to tackle this situation of removing the movie clip (AS Linkage 'Betherino') from not only the array but also the stage
Sorry I am still new to stack Overflow :(
I havent gotten up to the change frame part any suggestions on ideas would be great!

To "Remove the element from the array and the stage then go to a gameover frame", there's three steps:
Remove the element from the array
Remove the element from stage
Jump to a game over frame.
The last one, I think that's best left to you. There's no code related to gameover frames in your question, so I can't help you there.
The other elements, however...
for each (var zom:Betherino in zombie_horde){
var frame = zom.currentFrame
trace(frame)
if(frame == zom.lastframe)
{
updatearray()
}
else{
zom.gotoAndStop(frame+1)
}
}
You go through each zombie in the zombie horde, and if it's at its last frame, you try to remove it.
This implies that these zombies simply play through an animation and then disappear. Sounds strange to me. Is that really want you want the code to do?
Next... you use updatearray to remove the zombies from the array. But you do so via zombie_horde.splice(). That doesn't work. If you look at the documentation for splice then you'll see that it takes 2+ arguments: startIndex:int, deleteCount:uint, ... values. That is, the first argument is the start index to start deleting at, the second argument specifies how many you want to delete, and any arguments after that are added back in the list.
zombie_horde.splice(zombie_horde.indexOf(zom), 1);
will do what you're looking for, when inlined.
As for removing the element from stage, you need to pass an object. stage.removeChild(Betherino) is not the correct way, inline and use stage.removeChild(zom) instead. That makes for this function:
for each (var zom:Betherino in zombie_horde){
var frame = zom.currentFrame
trace(frame)
if(frame == zom.lastframe)
{
zombie_horde.splice(zombie_horde.indexOf(zom), 1);
stage.removeChild(zom);
//go to gameover frame and exit for loop
}
else{
zom.gotoAndStop(frame+1)
}
}
The "go to gameover frame" comment still needs to be replaced with the relevant code.

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.

Having trouble advancing frame in AS3 to advance frames

I'm creating a quiz with buttons and I'm new to ActionScript 3.0, but very familiar with 2.0.
I have a variable inside of a MC called NextQuestion. When it reaches a certain frame, it changes to 1, then back to 0.
On the main timeline, when NextQuestion == 1, it's supposed to NextFrame();. I can't get it to work though, this is the last thing I'm having trouble with.
This is my main code with 4 buttons, 3 wrong, 1 right. The feedback MC plays an animation, and when it finishes, it sets the VAR NextQuestion to 1, which is supposed to make the main timeline advance to the NextFrame.
stop();
right.addEventListener(MouseEvent.CLICK, rightClick1);
wrong1.addEventListener(MouseEvent.CLICK, wrongClick1);
wrong2.addEventListener(MouseEvent.CLICK, wrongClick1);
wrong3.addEventListener(MouseEvent.CLICK, wrongClick1);
feedback1.addEventListener(Event.ENTER_FRAME, answerRight1);
function answerRight1()
{
if (feedback1.NextQuestion == 1)
{
trace(feedback1.NextQuestion);
nextFrame();
}
else
{
trace("do nothing");
}
}
function rightClick1(ev:MouseEvent):void
{
trace(feedback1.NextQuestion);
feedback1.gotoAndPlay("right1");
}
function wrongClick1(ev:MouseEvent):void
{
trace("wrong");
feedback1.gotoAndPlay("wrong");
}
Any help is greatly appreciated! :)
The nextFrame() method in AS3 doesn't loop trough your movieClips, it just set's the movie clip to the next frame provided there is a next frame, otherwise it does nothing.
you might want to re-write the nextFrame() to:
if (totalFrames == currentFrame)
{
gotoAndStop(1); // or gotoAndPlay(1) if you need
}
else
{
nextFrame();
}
Thats regarding why the movie clip might not start from the beginning.
Another thing that look weird is that you need a FRAME_ENTER event to check if the answer is correct. You must have a lot of spam in the output log. I'd recommend you to totally ditch the ENTER_FRAME event listener for this and do it all with the CLICKED event and dispatching the event from the feedback1 object.
As much as I understand the movie clip plays when you click a button and when the animation is over you want to either progress to next frame or do nothing. If so, on the feedback1 object add a following line in the end of animation for label "right1":
dispatchEvent(new Event("right"));
and instead of the line feedback1.addEventListener(Event.ENTER_FRAME, answerRight1); have:
feedback1.addEventListener("right", answerRight1);
That way you won't need to check the answer on every frame and you don't need to check if the answer is right or not, because when the dispatchEvent(new Event("right")); fires - it's always right.
Hope I didn't misunderstand your question :)

AS3 Button to stop Movieclip after its finished playing

Ok, so I'm a beginner at AS3 and Flash and I managed to put this code together for an animation. A Button called start_btn is supposed to start and stop a movieclip called main_mc. On the first click of the Button, the Movieclip is supposed to play (which it does), however on the second click, the movie stops in the middle of its animation (which I don't want). My question is, when you click the Button a second time, how can i get the Movieclip to finish playing its animation then stop on the last frame?
I thought about using if (main_mc.currentFrame == main_mc.totalFrames); {main_mc.stop(); but the Movieclip still does not stop on the last frame. The Movieclip itself also has a gotoAndPlay(2); command on the last frame so that the animation repeats before the Button is clicked a second time.
here is the code i have:
`start_btn.addEventListener(MouseEvent.CLICK, mainaniS);
function mainaniS(event:MouseEvent):void
{
main_mc.play();
start_btn.removeEventListener(MouseEvent.CLICK, mainaniS);
start_btn.addEventListener(MouseEvent.CLICK, mainaniSt);
}
function mainaniSt(event:MouseEvent):void
{
if (main_mc.currentFrame == main_mc.totalFrames);
{main_mc.stop();}
start_btn.removeEventListener(MouseEvent.CLICK, mainaniSt);
start_btn.addEventListener(MouseEvent.CLICK, mainaniS);
}`
Try main_mc.gotoAndStop(main_mc.totalFrames).
I was going to provide a quick and dirty solution, but decided instead to try and explain a few of the issues with your current implementation and attempt to refactor and explain and better one. Unfortunately I don't have access to Flash right now, so the code is untested.
You're adding and removing event listeners often, which is generally a bad idea. Instead, since you're using a single button to perform multiple functions it would make sense to track the button state in a separate variable. In this case, a boolean for whether or not the movieclip is currently playing.
var playing:Boolean;
Now we can combine the mainaniS and mainaniSt into one and perform a different action based on whether or not the movieclip is playing, and just keep the one eventlistener on the button. I've also taken the liberty of naming the method something more meaningful:
start_btn.addEventListener(MouseEvent.CLICK, onStartClick);
function onStartClick(event:MouseEvent):void
{
if(playing) {
playing = false;
}
else {
playing = true;
main_mc.play();
}
}
You may be wondering why we don't call main_mc.stop() in the first block: the reason is that you don't want to stop the movieclip as soon as you click the button, but after the movieclip has finished playing if the button has been clicked. Therefore, we just set playing to false to indicate that we want it to stop later.
Finally, we need to make sure the movieclip stops upon completion, but only if playing is false. To do this we add a listener to movieclip that is called every frame, and checks whether playing is false, and if it's on the last frame. Note that the last frame is actually totalFrames - 1: this is because the frame numbers start from zero rather than one (i.e. if totalFrames is 3, the frame numbers will be 0, 1, 2).
main_mc.addEventListener(Event.ENTER_FRAME, animate);
function animate(event:Event):void {
if(!playing && main_mc.currentFrame == main_mc.totalFrames - 1) {
main_mc.stop();
}
}
All the refactored code together:
var playing:Boolean;
start_btn.addEventListener(MouseEvent.CLICK, onStartClick);
main_mc.addEventListener(Event.ENTER_FRAME, animate);
function onStartClick(event:MouseEvent):void
{
if(playing) {
playing = false;
}
else {
playing = true;
main_mc.play();
}
}
function animate(event:Event):void {
if(!playing && main_mc.currentFrame == main_mc.totalFrames - 1) {
main_mc.stop();
}
}

Removing Children in AS3

My flash game exists of a timeline with multiple frames (I know I should avoid the timeline)
The point of the game is a point and click adventure. The object that you are able to pick up get spawned and destroyed accordingly as you enter and leave the room. now my problem is when entering frame 14 (accessibel from frame 12) it creates a piece of paper which you are able to pick up if you have another item. Now my problem is when you can't or don't pick up the paper and go back to frame 12 (only exit is to frame 12), you can't click on any other object and you are basicly stuck on frame 12. When leaving and entering other rooms it works properly but for some reason it doesn't for on the paper on frame 14.
My code to remove objects works as following
In my Main.as Documentclass I have a function that called as soon as the game starts which does the following
if (lastframe == 14)
{
trace (prop.numChildren);
while (prop.numChildren )
{
prop.removeChildAt(0);
}
}
The lastframe variable is established when moving from frames
this function is found on the frame itself (each exit function on it's own respective frame)
function exitKantine(event:MouseEvent):void
{
Main.lastframe = 14;
gotoAndStop(12);
}
The function to remove the prop actually removes it but then causes all other clickable objects to be unusable.
Thanks for looking at my question and thanks in advance for your suggestions
I would say instead of removing children, add it once in the beginning, add all the listeners in the beginning, and toggle the visibility instead of trying to addChild and removeChild every time you want to hide it. Use an array so you can have a few happening at the same time.
something like this:
private function init():void
{
assignVars();
addListeners();
stage.addChild // make sure this is in document class or you are passing stage to the class using it
}
for (var i = 0; i < _thingsAry.length; i++)
{
if (_thingsAry[i] == 14)
{
_thingsAry[i].visible = false;
trace("the visibility of _thingsAry[" + i + "] is " + _thingsAry[i].visible
}
}

ActionScript 3: Bullet Ricocheting

I've been having a problem with my Actionscript code. I am fairly new to Flash and AS3, so I apologize if my code seems crude or rudimentary, but I'm doing this as best as I can.
Well, in this project I'm trying to get a bullet to ricochet off a wall once. If it hits a wall again after ricocheting, the bullet will disappear.
I've created a for loop which moves the bullets, in an array. At the same time, I try to keep track of each bullet's individual number of ricochets. This works fine when I shoot a first bullet - it will ricochet and then disappear after hitting another wall. However, every bullet I fire after that disappears on the first wall it hits, before it has ricocheted. I've tried to get this to work but I just can't seem to do it.
I would be grateful if somebody could show me the problem, or suggest a change to my code.
Here is a link to my code as it is now.
Thanks, to anybody who helps.
Here are some suggestions I have:
1: Create a Bullet class that tracks its own collisions against walls. I'd also move the clearBullet() method into the bullet class itself.
public class Bullet extends Sprite
{
public var collisions:int = 0;
public var xv:Number = 0;
public var yv:Number = 0;
public function clear():void
{
if(parent)
parent.removeChild(this);
}
}
2: Update your loop to deal with this new info.
for each(var i:Bullet in bulletholder)
{
// Move bullet.
// Check for collision.
// When there is a collision, do this:
i.collisions ++;
if(i.collisions >= 2)
{
var n:int = bulletholder.indexOf(i);
bulletholder.splice(n, 1);
i.clear();
}
else
{
// Deal with changing bullet position.
}
}
I see at least a couple of problems with your code:
Your ricochetcount is clearly out of sync. i.e. you need to delete an element from that array as well.
When you delete an element from the bulletholder array (via clearBullet), you're still incrementing i, which means you end up inadvertently skipping an element.
Also I'm not sure why you need clearBullet(). You already have the index i as well as a reference to the bullet object right there in the main loop.