OK so I am having a weird issue. I have some movieclips on screen, 4 of them, each with the following code (with different instance names of course):
stage.addEventListener(MouseEvent.MOUSE_DOWN,globalMouseDown,false,0,true); //add a global mouse listener
function globalMouseDown(e:Event):void {
//find out if the target is a descendant of this, if not, then something else was clicked.
var parent:DisplayObject = e.target as DisplayObject;
while(parent && parent != stage){
if(parent == this) return;
parent = parent.parent;
}
//something else was clicked that wasn't this, so go to the up state
gotoAndStop(1);
}
stop();
addEventListener(MouseEvent.MOUSE_DOWN, onHs1Press);
addEventListener(MouseEvent.MOUSE_OVER, onHs1Over);
addEventListener(MouseEvent.MOUSE_OUT, onHs1Out);
function onHs1Press(event:MouseEvent):void
{
// toggle between frame 1 and 3 on button press
gotoAndStop(this.currentFrame == 3 ? 1 : 3);
parent.addChild(this)
}
function onHs1Over(event:MouseEvent):void
{
if (currentFrame != 3)
{
gotoAndStop(2);
}
}
function onHs1Out(event:MouseEvent):void
{
// only switch back to UP state if the button is "pressed"
if (currentFrame != 3)
{
gotoAndStop(1);
}
}
Basically it lets you hover your mouse and the movieclip changes and then when you click on it a little pop up window appears until you click the movieclip again to close it.
There is also a button on screen that allows you to move forward or backwards to other frames with this code:
Next.addEventListener(MouseEvent.CLICK,Nclick);
function Nclick(event:MouseEvent):void {
nextFrame();
}
Back.addEventListener(MouseEvent.CLICK,Bclick);
function Bclick(event:MouseEvent):void {
prevFrame();
}
The button code is on the main timeline and the movieclip code is on the movieclip's timeline.
For some reason if you have the movieclip in the DOWN state (with the popup window open) and you click the button to go to the next frame, the movieclip follows onto the next and any other frames instead of just going away.
I have this same code present on other frames and none of the other ones behave this way, it's really weird.
You can even click it still when its on the other frames and bring up the popup window where the movieclip and code aren't even present.
What's going on with it?
I tried testing this, and could reproduce your issue. If you add a movieclip to the stage in FlashPro, after changing it's index or parentage, it will from that point on be treated like an object created from code and the timeline will ignore it and even create another instance of it on a frame where it is created.
You'll have to manually remove the buttons from the display list.
function Nclick(event:MouseEvent):void {
nextFrame();
removeBtns();
}
function Bclick(event:MouseEvent):void {
prevFrame();
removeBtns();
}
function removeBtns():void {
if(currentFrame != 2){ //whatever the frame of your buttons is
if(btn1 && btn1.parent) removeChild(btn1); //btn1 being whatever your button instnace name is
if(btn2 && btn2.parent) removeChild(btn2); //repeat for all buttons
}
}
OR If you'd prefer to have encapsulated code, instead of the above, put this on your button class/timeline:
var myFrame:int = MovieClip(parent).currentFrame;
this.addEventListener(Event.ENTER_FRAME,enterFrameHandler);
this.addEventListener(Event.REMOVED_FROM_STAGE,removedHandler);
function enterFrameHandler(e:Event):void {
if(MovieClip(parent).currentFrame != myFrame){
parent.removeChild(this);
}
}
function removedHandler(e:Event):void {
this.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
this.removeEventListener(Event.REMOVED_FROM_STAGE, removedHandler);
}
Related
I have a dropdown menu that lets you select an item to be placed on the stage. The item is drag and droppable so I use event.currentTarget.startDrag(); to start the drag. Ok, everything works fine so far.
However, I also need to be able to rotate the item while it is being dragged (using the spacebar).
stage.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown);
function myKeyDown(e:KeyboardEvent):void{
if (e.keyCode == Keyboard.SPACE){
rotate++;
if (rotate == 5){
rotate = 1;
}
WHATGOESHERE?.gotoAndStop(rotate);
}
If I hardcode in an instance name of an object everything works fine - so the rotate function is working properly. The problem is, how can I reference event.currentTarget from the startDrag function while inside of the keyDown event?
My first thought was to set event.currentTarget to a variable and then calling the variable from within the keyDown event. However, targetHold = event.currentTarget; does not seem to record the instance name of the object being clicked...
public var targetHold:Object = new Object;
function ClickToDrag(event:MouseEvent):void {
event.currentTarget.startDrag();
targetHold = event.currentTarget;
trace ("targetHold " + targetHold);
stage.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown);
function myKeyDown(e:KeyboardEvent):void{
if (e.keyCode == Keyboard.SPACE){
rotate++;
if (rotate == 5){
rotate = 1;
}
targetHold.gotoAndStop(rotate); //does not work
}
}
function ReleaseToDrop(event:MouseEvent):void {
event.currentTarget.stopDrag();
}
As you click the object, it should have focus. If you register the listener for the KeyboardEvent on the object and not on the stage, it will be .currentTarget.
Here's an example of what I have in mind. Right after starting the drag, add the listener to the same object instead of the stage.
event.currentTarget.startDrag();
event.currentTarget.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown);
The proper way of doing this would be to define all the functionality in a class. Within a self contained class, you would not need any .currentTarget.
Here is how I would do this: (well, actually I'd follow #null's advice and encapsulate it in a sub class that all your dragable objects would extend, but that is a little broad so this will do)
public var targetHold:MovieClip; //don't make a new object, just create the empty var
public function YourConstructor(){
//your other constructor code
stage.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown); //don't add the listener in the click function
}
private function clickToDrag(event:MouseEvent):void {
if(targetHold) ReleaseToDrop(null); //safeguard in case flash lost the focus during the mouse up
targetHold = event.currentTarget as MovieClip; //assign the current target. Might as well cast it as MovieClip and get code completion benefits
targetHold.startDrag();
trace ("targetHold " + targetHold);
}
private function myKeyDown(e:KeyboardEvent):void{
//check if target hold exists
if (targetHold != null && e.keyCode == Keyboard.SPACE){
rotate++;
if (rotate == 5){
rotate = 1;
}
targetHold.gotoAndStop(rotate);
}
}
private function ReleaseToDrop(event:MouseEvent):void {
if(targetHold) targetHold.stopDrag();
targetHold = null;
}
I have made a content where in one frame I have 10 movieclips(5 color pair) equally divided into two columns.I have added three event listener to the stage mousedown, mouseup, mouse move. I have drawn lines from one movieclip to another to match one column movie clip to another column same movie clip.. I added code to timeline but when I go to next frame or previous frame (where there are another acitvities) using next/prev button a warning is showing up :
Cannot access a property or method of a null object reference.
at CL3_Sc_Pat12_SL05_fla::MainTimeline/mMove()
this waring is not showing for mousedown() mouseup().i have used same next and same previous button for 3 frames.and for frame jumping i numbered each frame as frame no 1,2,3.if frameno == 3 goto frame 2 if frameno== 2 goto frame 1 thus it works..frame jumping code is in 1st frame..
Here is my code :
stage.addEventListener(MouseEvent.MOUSE_DOWN, mDown);
stage.addEventListener(MouseEvent.MOUSE_UP, mUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mMove);
function mDown(event:MouseEvent):void
{
mouseHolding = true;
clickedX = mouseX;
clickedY = mouseY;
myDrawing.graphics.moveTo(mouseX, mouseY);
Line_draw.graphics.moveTo(mouseX, mouseY);
if (pencil.hitTestObject(box1)) //box of 1st column
{
trace("box1 value is: "+chk_val_1);
}
}
function mUp(MouseEvent):void
{
myDrawing.graphics.lineTo(mouseX, mouseY);
mouseHolding = false;
if (pencil.hitTestObject(hit_box1)) ////box of 2nd column
{
trace(boxes have same color);
Line_draw.graphics.lineTo(mouseX, mouseY);
}
}
function mMove(MouseEvent):void
{
if (mouseHolding && mouseY < 510 )
{
clearTemp();
Line_draw.graphics.lineTo(mouseX, mouseY);
}
}
function clearTemp():void
{
Line_draw.graphics.clear();
Line_draw.graphics.lineStyle(6,0x0066CC,1);
Line_draw.graphics.moveTo(clickedX, clickedY);
}
function nxt_click(event:MouseEvent)
{
gotoAndPlay(3);
}
function prev_click(event:MouseEvent)
{
gotoAndPlay(1);
}
My code is working perfect but I want to know why is this warning coming again and again ?
You need to draw arrows (lines) just in your "anim4" frame so outside this frame you have to disable this function and remove all stage listener created for that, so you can do like this :
function nxt_click(event:MouseEvent)
{
if(){
// your other instructions
}
// your other instructions
else if (my_frame == 4)
{
stage.removeEventListener(MouseEvent.MOUSE_DOWN, mDown);
stage.removeEventListener(MouseEvent.MOUSE_UP, mUp);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mMove);
gotoAndPlay("anim5");
}
}
And you should do the same thing when exiting the "anim4" frame by pressing the previous button.
Hope that can help.
Ok, so I have a page with 5 movieclips/buttons on it. When you mouse over each one they light up (OVER state) and when you click on them they expand (DOWN state). The problem is if you have multiple movieclips expanded (in the DOWN state) they overlap and it looks awful. I want to code them so only 1 can be expanded at a time. How can I do this? I imagine I need an IF statement on each button like "If any other movieclips are in the DOWN state, then disable DOWN for this movieclip, if no other buttons are in DOWN state then enable the DOWN state for this movieclip" or something like that but I don't know how to write it. Please help. Here is the code for one of the movieclips:
Step0btn.stop();
Step0btn.addEventListener(MouseEvent.MOUSE_DOWN, onStep0Press);
Step0btn.addEventListener(MouseEvent.MOUSE_OVER, onStep0Over);
Step0btn.addEventListener(MouseEvent.MOUSE_OUT, onStep0Out);
function onStep0Press(event:MouseEvent):void
{
// toggle between frame 1 and 3 on button press
Step0btn.gotoAndStop(Step0btn.currentFrame == 3 ? 1 : 3);
}
function onStep0Over(event:MouseEvent):void
{
if (Step0btn.currentFrame != 3)
{
Step0btn.gotoAndStop(2);
}
}
function onStep0Out(event:MouseEvent):void
{
// only switch back to UP state if the button is "pressed"
if (Step0btn.currentFrame != 3)
{
Step0btn.gotoAndStop(1);
}
}
Ok we have solved the issue with the overlapping movieclips, however on the movieclip's DOWN state there is another movie clip that has this code:
Step0img.stop();
Step0img.addEventListener(MouseEvent.MOUSE_DOWN, onStep0imgPress, false, 999);
function onStep0imgPress(event:MouseEvent):void
{
Step0img.gotoAndStop(2);
event.stopImmediatePropagation();
}
This allowed me to click on the nested movieclip without triggering the MOUSE DOWN even and closing the expanded movieclip. I think disabling the MOUSECHILDREN may have also disabled this functionality.
Here is one way this can be done: Replace the code above with this code on your button timelines (or better yet make a class file and have your buttons each have it as their base class like my answer to this question - then you only need to have the one code file that all your buttons share)
stage.addEventListener(MouseEvent.MOUSE_DOWN,globalMouseDown,false,0,true); //add a global mouse listener
function globalMouseDown(e:Event):void {
//find out if the target is a descendant of this, if not, then something else was clicked.
var tmpParent:DisplayObject = e.target as DisplayObject;
while(tmpParent && tmpParent != stage){
if(tmpParent == this) return;
tmpParent = tmpParent.parent;
}
//something else was clicked that wasn't this, so go to the up state
gotoAndStop(1);
}
stop();
addEventListener(MouseEvent.MOUSE_DOWN, onPress);
addEventListener(MouseEvent.MOUSE_OVER, onOver);
addEventListener(MouseEvent.MOUSE_OUT, onOut);
function onPress(event:MouseEvent):void
{
// toggle between frame 1 and 3 on button press
gotoAndStop(Step0btn.currentFrame == 3 ? 1 : 3);
}
function onOver(event:MouseEvent):void
{
if (currentFrame != 3)
{
gotoAndStop(2);
}
}
function onOut(event:MouseEvent):void
{
// only switch back to UP state if the button is "pressed"
if (currentFrame != 3)
{
gotoAndStop(1);
}
}
I'm new to AS3 and although I was looking for a solution to my problem truly long time, I was not successful. I have an animated presentation and I just want to make navigation through that by arrows. Everything is on the main timeline. In the first frame I made this code
var zpet: Number;
if (currentFrame == 1) {
zpet = 1;
}
stage.addEventListener(KeyboardEvent.KEY_DOWN, posun);
function posun(event: KeyboardEvent): void {
if (event.keyCode == 37) {
addEventListener(Event.ENTER_FRAME, playReverse);
function playReverse(event: Event): void {
if (currentFrame == zpet) {
stopPlayReverse();
} else {
prevFrame();
}
}
function stopPlayReverse(): void {
if (hasEventListener(Event.ENTER_FRAME)) {
removeEventListener(Event.ENTER_FRAME, playReverse);
}
}
} else if (event.keyCode == 39) {
if (currentFrame < totalFrames - 1) {
play();
} else {
stop();
}
}
}
stop();
Moving forward works perfect as I put stop(); in every keyframe of the presentation. The problem is how to go back just to the previous keyframe (and I also want to go back in reverse playing). I thought it would be quite easy if I made a variable (called "zpet") and set it the specific number of frame where to go back in each keyframe. But it doesn't work, all the time it's going back to frame 1. For example I put in the frame 26 the code zpet = 13; that should say when playing back from the frame 26 stop at the frame 13. Any ideas how to solve this? I would be really grateful for that..
You can label each keyframe of your animation anything you want directly from the timeline and then something like this :
function playReverse(event: Event): void
{
prevFrame();// You can also use gotoAndStop(currentFrame - 1)
if(currentFrameLabel != null)
stopPlayReverse();
}
Looks cleaner imo, plus you can use labels value later in case you make a scene selection menu.
Upon the click of a button, an animation starts. Then the program directs you to a certain frame when the animation is done.
Is this possible?
So this is what I've got so far: a Movie Clip movQuizIntro and a Button btnBond in Frame 1.
stop()
movQuizIntro.stop()
btnBond.addEventListener(MouseEvent.CLICK, BondQuiz)
btnReg.addEventListener(MouseEvent.CLICK, Registrering)
function BondQuiz (evt:MouseEvent)
{
if (currentFrame == 1)
{
movQuizIntro.alpha = 1
movQuizIntro.play()
}
}
What is the code and proper syntax you need to write in order to go to frame 2 after the animation is done?
`
stop();
movQuizIntro.stop();
int frameCounter=0;
btnBond.addEventListener(MouseEvent.CLICK, BondQuiz);
btnReg.addEventListener(MouseEvent.CLICK, Registrering);
function BondQuiz (evt:MouseEvent)
{
if (currentFrame == 1)
{
movQuizIntro.alpha = 1
movQuizIntro.play()
movQuizIntro.addEventListener(EventType.ENTER_FRAME, onEnterFrame);
}
}
// event handler function, runs every enter frame
private function onEnterFrame(event:Event):Void
{
frameCounter++;
if(frameCounter > movQuizIntro.totalFrames)
{
//Place code here because you know the MovieClip finished playings
//Go to desired frame
}
}
`
I wrote this code outside of an editor nor did I get to compile, so the gist is there and may have some minor errors.
NOTE:This is just a quick way of doing this. If you want something more reusable/cleaner then you would want to consider subclassing or alternate Object Oriented tricks.
In button event handler:
function onClick(e:MouseEvent):void{
ANIMATION_MC.addEventListener(Event.EXIT_FRAME, onFromeExit);
}
function onFrameExit(e:Event):void {
if (ANIMATION_MC.currentFrame == SOME_FRAME) {
ANIMATION_MC.removeEventListener(Event.EXIT_FRAME, onFromeExit);
TARGET.gotoAndPlay(NEW_FRAME);
}
}
And you can just use addFrameScript on ANIMATION_MC too.