i have got a problem and cannot figure out. Everything is fine when i test the scene, i have added stop(); to my movie clip timeline and everything is fine until no code is added to the main stage. As soon as i start adding code to the stage, it starts looping? Because of this i'm stuck with a problem and cannot even develop further, because even mouse click events wont work of that looping... The code i am trying to add is just a simple move layer off stage after click on play button:
import fl.transitions.Tween;
import fl.transitions.easing.*;
import fl.transitions.TweenEvent;
introScreen.play_btn.addEventListener(MouseEvent.CLICK, clickAway);
function clickAway(event:MouseEvent):void
{
moveScreenOff(introScreen);
}
function moveScreenOff(screen:MovieClip):void
{
//Move the screen off...
var introTween = new Tween(screen,"x",Strong.easeInOut,screen.x,(screen.width)*-1,1,true);
//When the motion has finished...
introTween.addEventListener(TweenEvent.MOTION_FINISH, tweenFinish);
function tweenFinish(e:TweenEvent):void
{
trace("tweenFinish");
//Establish the game state...
gameState = STATE_INIT_GAME;
trace(gameState);
//Fire off the gameLoop function at the frame rate of the movie...
addEventListener(Event.ENTER_FRAME, gameLoop);
}
}
The reason your animations are looping continuously is because you have errors in your code.
Access of undefined property gameState.
Access of undefined property STATE_INIT_GAME.
Access of undefined property gameState.
Access of undefined property gameLoop.
You are trying to reference members that haven't been created yet or don't exist. Your main timeline starts at frame 1 with the code you referenced trying to access those variables and the gameLoop method. You need to setup the variables in the first frame to allow them to be referenced. i.e. under your import statements:
import fl.transitions.Tween;
import fl.transitions.easing.*;
import fl.transitions.TweenEvent;
var gameState:String;
const STATE_INIT_GAME:String = "GAME_INIT";
then you need to add the gameLoop function:
function gameLoop(e:Event):void {
trace('game loop running');
}
If you don't want those variables and that function setup there then you need to go to the frame using gotoAndStop or gotoAndPlay where those functions and variables can be declared and/or initialized, and stored into memory. Then they will be accessible.
Related
I have an AS3 project that has all its assets embedded using the [Embed] metadata tag because I would like the resulting SWF to be completely self-contained for the sake of portability on the internet.
Problem:
The file size is rather large, and I would like a progress bar to be displayed as it loads itself instead of a blank screen until it's completely finished. I can already achieve this with Adobe Animate (Flash Professional) by having a timeline with a light frame 1 and a heavy frame 2 which has a MovieClip that embeds the bulk of the assets.
I'm trying to switch over to Adobe Flash Builder, which has no IDE timeline, but I'm at a loss on how to do the same thing as the Flash IDE. Does anyone have any ideas on how to accomplish this?
Option №1. The one I'd picked, because it's easier to comprehend: external loader. A lightweight SWF with the only purpose of displaying some preloading info like % or progress while loading the heavyweight main module.
Option №2. There's a certain metatag that allows you to emulate that frame 1 preloader behavior. Keep in mind that is is not supported by ASC2.0 compiler (AIR SDK, I assume) but only by ASC1.0 compiler (Flex SDK). Flash Builder is a descendant of Flex Builder, so it's fine, I guess, but if it does not work for you, the first thing you should check is the compiler version your Flash Builder is packed with.
So, your main (the one you set as the document class in the settings) class should have that one metatag:
package
{
import flash.events.Event;
import flash.display.Sprite;
// Brace for the magic impact.
[Frame(factoryClass="Preloader")]
public class Main extends Sprite
{
public function Main()
{
// This is important, because at the moment of creation
// the instance is not attached to the stage.
if (stage) onStage(null);
else addEventListener(flash.events.Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event):void
{
removeEventListener(flash.events.Event.ADDED_TO_STAGE, onStage);
// This is the entry point of your actual application.
// The rest of the class goes normally from this point on.
Then, the mentioned preloader class. Its name should qualify exactly as mentioned in the metatag above.
package
{
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.utils.getDefinitionByName;
// This class represents the multi-framed main timeline
// thus it should subclass the basic MovieClip.
public class Preloader extends MovieClip
{
public function Preloader()
{
// Subscribe to all necessary points to monitor the loading.
addEventListener(Event.ENTER_FRAME, onFrame);
loaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioError);
loaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
}
private function ioError(e:IOErrorEvent):void
{
// Handle loading errors here.
}
private function onProgress(e:ProgressEvent):void
{
// Display loading progress here.
// Use e.bytesLoaded and e.bytesTotal values
// to calculate the % loaded and the overall loading progress.
}
private function onFrame(e:Event):void
{
// When the loading is finished, the main timeline,
// represented by Preloader class moves to the frame 2.
if (currentFrame == totalFrames)
{
stop();
onComplete();
}
}
// This method concludes the loading,
// cleans up the preloader itself
// and instantiates the Main class.
private function onComplete():void
{
removeEventListener(Event.ENTER_FRAME, onFrame);
loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, ioError);
loaderInfo.removeEventListener(ProgressEvent.PROGRESS, onProgress);
// So, here's the thing. You don't import the Main class
// because if you import it, then it will be embedded into
// the Preloader, then it must be loaded before Preloader
// can be initialized, which kind of fails the whole idea.
// Thus, you don't import the Main class but obtain it
// via the other means, like the "getDefinitionByName" method.
// Again, the fully qualified class name is to be provided.
var aMain:Class = getDefinitionByName("Main") as Class;
stage.addChild(new aMain as DisplayObject);
// Remove this instance as it no longer needed for anything.
parent.removeChild(this);
}
}
I found a solution that works with ASC2 / AIR SDK. Although his example preloader extends Sprite, and I believe you need to extend MovieClip to make it work, since you need a frame 2. And you need a gotoAndStop(2) once it has finished loading itself. Additional information here. Man, it's not a good sign when all your reference links go through web.archive.org!
Ok so i have some variables called "stat" that is inside a movie clip that i need to access from the main timeline. I have tried multiple ways but none of them have worked.
Edited.
I put the stage instance Movieclip names "mc". and this is have a this script.
var stat:String ="Test";
and next following script, Main timeline. If you access mc.stat you not get value. console show to null. when you called In Main timeline script access to instance MovieClip inner variable. because maybe Initialization code inside the script does not work yet. so you should delay called.
I suggested Using the Timer. try this:
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
trace("check1:" + mc.stat);
var timer:Timer = new Timer(1, 1);
timer.addEventListener(TimerEvent.TIMER, onAdded);
timer.start();
function onAdded(e:TimerEvent):void
{
timer.removeEventListener(TimerEvent.TIMER, onAdded);
trace("check2:" + mc.stat);
}
Code is always helpfull!
The movieclip musst exist at the time the code is executed.
trace("stat value in mc = " + mcName.stat);
I'm starting to use Flash CS6 for the first time to try and make Scaleform UI's for UDK. I'm following this simple tutorial: http://goo.gl/yedMU. I've followed it to the letter but can't seem to get it to work. I even have tried it again in a new project but it ends up with the same error. I've triple checked each name and instance but it just refuses to work. Here is the really simple code of the two frames in the file:
import flash.events.MouseEvent;
import flash.system.fscommand;
import flash.display.MovieClip;
subMenu_btn.addEventListener(MouseEvent.CLICK, subMenu);
exit_btn.addEventListener(MouseEvent.CLICK, exitGame);
var cursor:cursor_mc = new cursor_mc();
addChild(cursor);
cursor.x = mouseX;
cursor.y = mouseY;
cursor.startDrag();
stop();
function subMenu(event:MouseEvent):void
{
gotoAndStop('Sub Menu');
}
function exitGame(event:MouseEvent):void
{
fscommand('ExitGame');
}
and
play_btn.addEventListener(MouseEvent.CLICK, playGame);
back_btn.addEventListener(MouseEvent.CLICK, backBtn);
function playGame(event:MouseEvent):void
{
fscommand('PlayMap');
}
function backBtn(event:MouseEvent):void
{
gotoAndStop('Main Menu');
}
I used the debugger and the code breaks at
exit_btn.addEventListener(MouseEvent.CLICK, exitGame);
Any ideas? The whole thing works until I used the 'Back' button to go back to the first frame, when the 'Exit' button is gone and I get that error. The 'Submenu' button remains however and the menu is still operable.
This is the error using the debugger:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Menu_fla::MainTimeline/frame1()[Menu_fla.MainTimeline::frame1:6]
at flash.display::MovieClip/gotoAndStop()
at Menu_fla::MainTimeline/backBtn()[Menu_fla.MainTimeline::frame2:10]
Okay, so I might have been wrong in what I said in the comments above, the solution is this:
For your first frame's AS3:
import flash.events.MouseEvent;
import flash.system.fscommand;
import flash.display.MovieClip;
var cursor:cursor_mc = new cursor_mc();
subMenu_btn.addEventListener(MouseEvent.CLICK, subMenu);
exit_btn.addEventListener(MouseEvent.CLICK, exitGame);
addChild(cursor);
cursor.x = mouseX;
cursor.y = mouseY;
cursor.startDrag();
Mouse.hide();
stop();
function subMenu(event:MouseEvent):void
{
subMenu_btn.removeEventListener(MouseEvent.CLICK, subMenu);
exit_btn.removeEventListener(MouseEvent.CLICK, exitGame);
removeChild(cursor);
gotoAndStop('Sub Menu');
}
function exitGame(event:MouseEvent):void
{
fscommand('ExitGame');
}
For your second frame's AS3:
play_btn.addEventListener(MouseEvent.CLICK, playGame);
back_btn.addEventListener(MouseEvent.CLICK, backBtn);
cursor = new cursor_mc();
addChild(cursor);
cursor.x = mouseX;
cursor.y = mouseY;
cursor.startDrag();
Mouse.hide();
function playGame(event:MouseEvent):void
{
fscommand('PlayMap');
}
function backBtn(event:MouseEvent):void
{
removeChild(cursor);
gotoAndStop('Main Menu');
}
You were instantiating the cursor each time you hit frame 1, which I believe would create a namespace problem. The solution was to remove the cursor from the stage, and add it back in for each frame. There may be a more elegant solution, but as I never use multiple frames with AS (for this very reason), this is the best I could do. I also hid the mouse cursor to give your cursor_mc more focus.
Let me know if you have any other questions.
Happy coding!
Another solution would be to create a new layer, and put the cursor code on that layer only. That layer would have one keyframe, and extend to cover the entire timeline, so it is always alive.
Or, create a menu movie clip that exists on frame 1. And inside that movie clip, have your different frames for each part of the menu (options, etc.). And the cursor would exist at the same level as the menu movie clip. So it always exists and is only initialized once.
this is a follow up question to this question
i have never actually got the flash-actionscript code execution order.
in flash pro i have an instance of a moveiclip on stage in frame one named tree1 and on frame 3 i have on the stage tree3.
in the document class i have this code:
stop();
var scaleFactor:Number = tree1.scaleX;
gotoAndStop(3);
tree3.scaleX = scaleFactor;
while this works when testing on the desktop, this app will go mobile at the end
is this the correct way to go or should i register for a frameComplete event before accessing instances on a certain frame
So, just dont use the Document Class cause you will need to declare all the scenes from the beginning and will be complicate to manage each scene.
I suggest you to instance a simple MovieClip linked with his own class like the example SceneTree, put it on each Keyframe. You will have more control when you are entering or exiting each frame.
package {
import flash.display.MovieClip;
import flash.events.Event;
public class SceneTree extends MovieClip {
public function SceneTree() {
super();
this.addEventListener(Event.ADDED_TO_STAGE, Init);
this.addEventListener(Event.REMOVED_FROM_STAGE, removed);
}
protected function Init (event:Event):void{
trace("added")
}
protected function removed (event:Event):void{
trace("removed")
}
}
}
waiting for Event.FRAME_CONSTRUCTED is the correct way whenever accessing assets on a timeline
it insures all assets have been created
I have a flash animation made on the main timeline of the SWF with a couple of layers, some functions and some keyframe labels. For example, i have a movieclip of a star that come across the screen and then triggers a dispatchEvent for the main timeline to go to frame label "next".
Here is a sample of the actionscript used on the main timeline :
Stars.addEventListener("fadeInTitle",_fadeInTitle);
function _fadeInTitle(e:Event):void {
Title.gotoAndPlay("fadeIn");
Stars.removeEventListener("fadeInTitle",_fadeInTitle);
}
stop();
That SWF alone works perfectly. Problem comes when I try to load this SWF into another one.
What happens is the loader keeps reloading the SWF over and over, overlapping them and the actionscript that's on the main timeline of the loaded SWF is ignored, the timeline plays continuously. Here is the code i use to load the SWF :
import flash.net.URLRequest;
import flash.display.Loader;
import flash.events.Event;
import flash.events.ProgressEvent;
function startLoad(){
var mLoader:Loader = new Loader();
var mRequest:URLRequest = new URLRequest("Fly.swf");
mLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteHandler);
mLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgressHandler);
mLoader.load(mRequest);
}
function onCompleteHandler(loadEvent:Event){
addChild(loadEvent.target.content);
}
function onProgressHandler(mProgress:ProgressEvent){
var percent:Number = mProgress.bytesLoaded/mProgress.bytesTotal;
}
startLoad();
There's nothing special there. Just a simple loader.
I have found a workaround by putting the entire animation inside one main movieclip and put that movieclip on the main timeline (one keyframe, one layer, no actionscript) and then load it. That way it works fine but it feel more like a patch than a solution. I would really like to know why it's bugging when you try to load an external SWF that use the main timeline with multiple layers, keyframes and actionscript.
Any help/hint will be greatly appreciated.
Thanks a lot for reading.
m
First take the loader instantiation out of a function, it is not necessary. Second, kill your listeners in the onComplete function. Third, if this loader code is on the timeline of your loader shell, make sure that there is not more than one frame, or if there is (not sure why there would be though) place a stop on the frame containing the loader code. Or even better, use a Document class to contain your loader code rather than putting it on the timeline. My best guess is you were calling startLoad() over again somehow. Also, make sure you have the flash debug player installed so you are getting proper error reporting when viewing this in a browser.
var mLoader:Loader = new Loader();
var mRequest:URLRequest = new URLRequest("Fly.swf");
mLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteHandler);
mLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgressHandler);
mLoader.load(mRequest);
function onCompleteHandler(loadEvent:Event)
{
mLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompleteHandler);
mLoader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, onProgressHandler);
addChild(loadEvent.target.content);
}
function onProgressHandler(mProgress:ProgressEvent)
{
var percent:Number = mProgress.bytesLoaded/mProgress.bytesTotal;
}