Timeline instances not on first frame - actionscript-3

It's been a while since I've had to write Actionscript that really needs to integrate with the timeline (in this case, controlling a series of frames that must happen in a certain sequence) and I am trying to figure out what to do.
In the first few frames, I have a button "next_1".
At frame 10, I need to have another button "next_2". I really really need this button to not be on frame one (I could possibly just make it invisible, but that's going to create a clickable area that I don't want).
The problem is, anything I don't put on "frame_1" renders as null in my Document class.
Is there any solution to this? I would rather not have to write my script on the timeline if possible (it seems easier in the long run to keep it in a document class)...

Items on the timeline are created on the fly, so if the playhead has not reached frame 10, next_2 is not created.
Easiest Document-class solution:
Create an array of frame labels like ["label1", "label2"]
Create sectionIndex var and set it to 0
Create a next button on its own layer so it is always showing.
When the next button is clicked, increment sectionIndex, then gotoAndPlay(myLabels[sectionIndex])

Okay, directly lifted from "Real World Flash Game Development":
/**************************************************
* FRAME LABELS *
**************************************************/
private function enumerateFrameLabels():void {
for each (var label:FrameLabel in currentLabels) {
addFrameScript(label.frame-1, dispatchFrameEvent);
}
}
private function dispatchFrameEvent():void {
dispatchEvent(new Event(currentLabel, true));
}
This dispatches an event at each frame label on the timeline.
Then you can just add event listeners for each frame:
addEventListener("name_of_my_framelabel", frameHandler);
addEventListener("another_framelabel", frameHandler);
And write a switch statement to add event listeners for the buttons when they actually show up on the timeline.
private function frameHandler(e:Event):void {
switch(e.type) {
case 'screen_2':
stop();
next_2.addEventListener(MouseEvent.CLICK, click2, false, 0, true)
break;
}
}

Related

Simple click event

I don't know why I can't figure out this problem that is really basics !! (sometimes the brain is tired I guess).
I've got a movieclip with a guitar string.
I want the string to move everytime I click on it.
I've created a movie clip with 2 lables. the first = non movement, the second = movement.
I've placed in the second one a stop(); action. (in order to stop the loop)
I've put this code :
stringOne.addEventListener(MouseEvent.CLICK, accord1, false, 0, true);
public function accord1(e:MouseEvent):void{
var stringOne;
trace("DING");
stringOne.gotoAndStop("first");
}
It works but, of course, it only play the string movement at the first click.
Do you know how I could play the string movement EVERYTIME that I click on the string ?
Thank you very much and sorry for this easy question (little ashamed)..,
EDIT
Ah ! It seems to work with goToAndPlay !
if (stringOne.currentLabel=="premier") {
stringOne.gotoAndStop("default");
} else {
stringOne.gotoAndStop("first");
}
Just a thing, I have to click twice..
(one click = the string vibrate (label2))
(one click again = the string does nothing (going to label 1))
(one click again = the string vibrate (label 2))
Is there anyway to automatically skip the 2nd click (the one that tells the string to go back at label 1), and let do the code like : - When animation of label 2 is finished, automatically go back to label 1 ? –
Presumably, the "movement" label of the string is some sort of animation?
It seems to me what you want in your "guitar string" movieClip is, on the last frame of the timeline animation for "movement", a script that says gotoAndStop('non movement'). The click handler should gotoAndPlay('movement').
Then, when the string 'movement' animation is finished, it will reset itself, so that the next time you click it will play again.
So, your original code is fine (before the edit; but remove the "var stringOne;" since that will break the reference to stringOne). The only thing you need to add is a script in the timeline on the last frame of the movement animation ("first" label?) that says gotoAndPlay("default") (assuming default is the 'non movement' label). You may need a stop() in the timeline frame for "default".
Something like that :
stage.addEventListener( MouseEvent.CLICK, onStageClick);
protected function onStageClick(event:MouseEvent):void
{
switch( event.target )
{
case stringOne:
trace("String one stuff");
break;
case stringTwo:
trace("String 2 stuff");
break;
}
}
Or add your movieClip into a Sprite and listen click event on the Sprite and not on the MovieClips.
Thank you for the answer. I've found an other way, instead of mouse click I've used mouse down for going to frame 2 and mouse up for going to frame 1

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();
}
}

Changing individual movieclip's frame rate with TweenMax

My aim is to change the frame rates of my individual (looping) movie clips through clickable controls (slow/med/fast). I've heard it isnt possible to achieve this through as3/flash alone, so I've tried greensock's TweenMax... However I can't seem to figure out how to do this. Is there anyone that could help?
box1.addEventListener(MouseEvent.MOUSE_DOWN, box1down);
function box1down(event:MouseEvent):void {
//FRAMERATE CODE HERE
}
Many thanks!
Here is the API doc for TweenMax: http://www.greensock.com/as/docs/tween/com/greensock/TweenMax.html
If you have multiple movieclips that you are trying to control, you can just create an abstract class with the functionality you want and extend that class. So something like:
public class ControlledMovieClip extends MovieClip {
public function ControlledMovieClip() {
stop();
}
public function animate(frameRateInSeconds:Number):void {
TweenMax.to(this, frameRateInSeconds, { frame: this.totalFrames - 1, repeat: -1, ease: Linear.easeNone });
}
}
Have all your movieclips that are looping extend that class, and then you could call the animate function on the objects in your box1down event handler.
I haven't tested that code so you might need a gotoAndStop(1) at the end of each iteration.
It's possible through Actionscript alone it just requires you to handle the frame progression yourself (instead of using mc.play() you stop the movieclip and call nextFrame() yourself).
Lets say a Movieclip (myMC) has 20 frames of animation. To manually run the animation at normal speed you simply call myMC.nextFrame(); on every frame of your project (using an ENTER_FRAME listener for example).
To have the animation run at half speed you can use a frame count and a frame trigger:
var frameTick = 0;
var frameAnimTrigger = 2;
function Update(e:Event):void
{
frameTick++;
if(frameTick == frameAnimTrigger)
{
myMC.nextFrame();
frameTick = 0;
}
}
Because nextFrame is only called every other frame the animation appears to run at half speed.

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
}
}