I created an AS file and used it as a class, inside it I called buttons and slideshow images.
After that I decided to create an intro by moving the timeline. My problem is that all the objects are displayed from the very first frame, is there a way to make the entire class start after certain frame?
Code for reference:
package {
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.MovieClip;
public class play extends MovieClip {
private var loader:Loader = new Loader();
private var images:Array = ["img/Layer_1.jpg", "img/Layer_2.jpg", "img/Layer_3.jpg", "img/Layer_4.jpg", "img/Layer_5.jpg", "img/Layer_6.jpg", "img/Layer_7.jpg", "img/Layer_9.jpg", "img/Layer_10.jpg", "img/Layer_11.jpg", "img/Layer_12.jpg", "img/Layer_13.jpg", "img/Layer_14.jpg"];
private var triangleButton:triangle = new triangle;
private var squareButton:square = new square;
private var crossButton:cross = new cross;
private var circleButton:circle = new circle;
public function play() {
loadNextImage();
addChild(loader);
loader.x = 137;
loader.y = 65;
//Buttons
addChild(triangleButton);
triangleButton.width = 28;
triangleButton.scaleY = triangleButton.scaleX;
triangleButton.x = 804;
triangleButton.y = 107;
triangleButton.addEventListener(MouseEvent.CLICK, slideGames);
addChild(circleButton);
circleButton.width = 28;
circleButton.scaleY = circleButton.scaleX;
circleButton.x = 825;
circleButton.y = 130;
circleButton.addEventListener(MouseEvent.CLICK, slideGames);
addChild(crossButton);
crossButton.width = 28;
crossButton.scaleY = crossButton.scaleX;
crossButton.x = 804;
crossButton.y = 155;
crossButton.addEventListener(MouseEvent.CLICK, slideGames);
addChild(squareButton);
squareButton.width = 28;
squareButton.scaleY = squareButton.scaleX;
squareButton.x = 780;
squareButton.y = 130;
squareButton.addEventListener(MouseEvent.CLICK, slideGames);
}
public function slideGames(event:MouseEvent):void {
loadNextImage();
}
public function loadNextImage() : void {
// Increment the image
_imageIndex++;
// If we've reached the end of the array, start over
if (_imageIndex >= images.length) {
_imageIndex = 0;
}
// Now get the image source from the array and tell the loader to load it
var imageSource : String = images[_imageIndex] as String;
loader.load(new URLRequest(imageSource));
}
// Next image to display
protected var _imageIndex : int = -1;
}
}
Yes, instead of initializing everything in the constructor of your class (play()), you can move it to another function, and call that from the timeline. I am assuming you are using the play class as the document class.
So instead of
public function play() {
you would rename it to
public function play_start() {
Create an empty constructor named play() at this point if you want to.
In the flash IDE, select the frame where you want the items to appear, then create a keyframe there.
Select the keyframe and go to the Actions panel (F9) and enter the following code:
this.play_start();
once the playhead is at the keyframe, your code should be executed.
Related
I was analyzing an unexpected memory leak in our game project and found some strange results. I am profiling using Adobe Scout and eliminated all other factors like starling, texture or our loading library. I reduced the code to simply load a png and immediately allocate an empty inline function on its complete event.
Loading a png allocates image on default and if you do nothing after loading gc clears that image. But creating an inline function seems to prevent that image to be garbage collected somehow. My test code is;
public class Main extends Sprite
{
private var _callbacks:Array = new Array();
public function Main()
{
load("map.png", onPngLoaded);
}
private function onPngLoaded(bitmap:Bitmap):void
{
_callbacks.push(function():void { });
}
public function load(url:String, onLoaded:Function):void
{
var loader:Loader = new Loader;
var completeHandler:Function = function(e:Event):void {
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, completeHandler);
onLoaded(loader.content);
}
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
loader.load(new URLRequest(url));
}
}
If you remove the code which creates an inline function;
private function onPngLoaded(bitmap:Bitmap):void
{
// removed the code here!
}
gc works and clears the image from memory.
Since having no logical explanation for this, I suspect of a flash / as3 bug. I will be glad to hear any comments who tests my code and gets the same results.
Note: To test, replace the main class of an empty as3 project with my code and import packages. You can load any png. I am using flashdevelop, flex-sdk 4.6.0 and flash player 14.
When you create an inline function, all local variables get stored with it in the global scope. So in this case, that would include the bitmap parameter.
For more information, see this:
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7f54.html
Here is the relevant part:
Any time a function begins execution, a number of objects and properties are created. First, a special object called an activation object is created that stores the parameters and any local variables or functions declared in the function body....Second, a scope chain is created that contains an ordered list of objects that Flash Player or Adobe AIR checks for identifier declarations. Every function that executes has a scope chain that is stored in an internal property. For a nested function, the scope chain starts with its own activation object, followed by its parent function’s activation object. The chain continues in this manner until it reaches the global object.
This is another reason why inline/anonymous functions are best avoided in most situations.
So using asc2, Flash/Air 19 : Yes I get the same results that you are seeing, but due to the anonymous function holding global references I expected that (like my original comment stated).
I rewrote it in my style based upon Adobe's GC technical articles and bulletins and no leaks are seen as all the global references are removed.
A cut/paste AIR example:
package {
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.Loader;
import flash.events.Event;
import flash.net.URLRequest;
import flash.system.System;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Main extends Sprite {
var timer:Timer;
var button:CustomSimpleButton;
var currentMemory:TextField;
var highMemory:TextField;
var hi:Number;
var _callbacks:Array = new Array();
public function Main() {
button = new CustomSimpleButton();
button.addEventListener(MouseEvent.CLICK, onClickButton);
addChild(button);
currentMemory = new TextField();
hi = System.privateMemory;
currentMemory.text = "c: " + hi.toString();
currentMemory.x = 100;
addChild(currentMemory);
highMemory = new TextField();
highMemory.text = "h: " + hi.toString();
highMemory.x = 200;
addChild(highMemory);
timer = new Timer(100, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerHandler);
timer.start();
}
function timerHandler(e:TimerEvent):void{
System.pauseForGCIfCollectionImminent(.25);
currentMemory.text = "c: " + System.privateMemory.toString();
hi = System.privateMemory > hi ? System.privateMemory : hi;
highMemory.text = "h: " + hi.toString();
timer.start();
}
function onClickButton(event:MouseEvent):void {
for (var i:uint = 0; i<100; i++) {
//load("foobar.png", onPngLoaded);
load2("foobar.png");
}
}
private function onPngLoaded2(bitmap:Bitmap):void {
var foobarBitMap:Bitmap = bitmap; // assuming you are doing something
foobarBitMap.smoothing = false; // with the bitmap...
callBacks(); // not sure what you are actually doing with this
}
private function callBacks():void {
_callbacks.push(function ():void {
});
}
public function completeHandler2(e:Event):void {
var target:Loader = e.currentTarget.loader as Loader;
// create a new bitmap based what is in the loader so the loader has not refs after method exits
var localBitmap:Bitmap = new Bitmap((target.content as Bitmap).bitmapData);
onPngLoaded2(localBitmap);
}
public function load2(url:String):void {
var loader2:Loader = new Loader;
loader2.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler2, false, 0, true);
loader2.load(new URLRequest(url));
}
}
}
import flash.display.Shape;
import flash.display.SimpleButton;
class CustomSimpleButton extends SimpleButton {
private var upColor:uint = 0xFFCC00;
private var overColor:uint = 0xCCFF00;
private var downColor:uint = 0x00CCFF;
private var size:uint = 80;
public function CustomSimpleButton() {
downState = new ButtonDisplayState(downColor, size);
overState = new ButtonDisplayState(overColor, size);
upState = new ButtonDisplayState(upColor, size);
hitTestState = new ButtonDisplayState(upColor, size * 2);
hitTestState.x = -(size / 4);
hitTestState.y = hitTestState.x;
useHandCursor = true;
}
}
class ButtonDisplayState extends Shape {
private var bgColor:uint;
private var size:uint;
public function ButtonDisplayState(bgColor:uint, size:uint) {
this.bgColor = bgColor;
this.size = size;
draw();
}
private function draw():void {
graphics.beginFill(bgColor);
graphics.drawRect(0, 0, size, size);
graphics.endFill();
}
}
I am loading an external swf file into a parent swf file.
Previously, I was getting error 1009 and fixed that by using a listener event to add the swf to the stage before running any scripts.
The swf however fails to load completely when embedded into a parent swf as seen in this URL
http://viewer.zmags.com/publication/06b68a69?viewType=pubPreview#/06b68a69/1
Here is the code I am using.
Thank you for any input.
package
{
import com.greensock.TweenLite;
import flash.display.DisplayObject;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.utils.getDefinitionByName;
public class slider5 extends Sprite
{
public var thumbPath:String = "Trailchair_thumb";
public var featPath:String = "Trailchair";
public var sliderIndex:Number = 1;
public var currBg:Bitmap = new Bitmap();
public var thumbCount:Number = 8;
public var thumbHolder:Sprite = new Sprite();
public var thumbMask:Sprite = new Sprite();
public var thumbX:Number = 0;
public var thmPadding:Number = 10;
public var thmWidth:Number;
public var navLeft:Sprite = new Sprite();
public var navRight:Sprite = new Sprite();
public var timer:Timer = new Timer(5000,0);
public var sliderDir:String = "fwd";
public function slider5()
{
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
public function onAddedToStage(e:Event):void{
removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
//THE BACKGROUND IMAGE
currBg.alpha = 1;
stage.addChildAt(currBg, 0);
changeBg(sliderIndex);
//The thumbMask a sprite with graphic rectangle
thumbMask.x = 87;
thumbMask.y = 572;
thumbMask.graphics.beginFill(0xFFFFFF);
thumbMask.graphics.drawRect(0,0, 406, 181);
stage.addChildAt(thumbMask, 2);
//The thumbSlider
thumbHolder.x = 228;
thumbHolder.y = 573;
stage.addChildAt(thumbHolder, 1);
thumbHolder.mask = thumbMask;
buildThumbs();
//add the nav
navLeft.x = 100;
navLeft.y = 609;
navRight.x = 496;
navRight.y = 609;
stage.addChildAt(navLeft, 4);
stage.addChildAt(navRight, 4);
var navBmp:Bitmap = new Bitmap();
navBmp.bitmapData = new navarrow(109,109);
var navBmp_Rt:Bitmap = new Bitmap();
navBmp_Rt.bitmapData = new navarrow(109,109);
navLeft.addChild(navBmp);
navLeft.scaleX *= -1;
navRight.addChild(navBmp_Rt);
navLeft.useHandCursor = true;
navLeft.buttonMode = true;
navRight.useHandCursor = true;
navRight.buttonMode = true;
navLeft.name = "left";
navRight.name = "right";
navLeft.addEventListener(MouseEvent.CLICK, navClick);
navRight.addEventListener(MouseEvent.CLICK, navClick);
//add the active item frame
var frame:Sprite = new Sprite();
frame.x = 226;
frame.y = 570;
frame.graphics.lineStyle(10, 0x000000);
frame.graphics.drawRect(0,0,131, 181);
stage.addChildAt(frame, 6);
timer.addEventListener(TimerEvent.TIMER, timeEvt);
timer.start();
}
public function changeBg(index):void
{
//set the first slide from our library and add to the stage
var currBg_Class:Class = getDefinitionByName( featPath + index ) as Class;
currBg.bitmapData = new currBg_Class(597,842);
//fade it in
TweenLite.from(currBg, 0.5, {alpha:0});
}
public function buildThumbs():void
{
var currThm:Class;
for (var i:uint = 1; i<=thumbCount; i++)
{
currThm = getDefinitionByName( thumbPath + i ) as Class;
var thmBmp:Bitmap = new Bitmap();
thmBmp.bitmapData = new currThm(126,176);
thmBmp.x = thumbX;
thumbHolder.addChild(thmBmp);
thumbX += thmBmp.width + thmPadding;
}
thmWidth = thmBmp.width + thmPadding;
}
public function navClick(e):void
{
timer.reset();
timer.start();
var dir:String = e.currentTarget.name;
if (dir=="left" && thumbHolder.x < 228 )
{
sliderIndex--;
TweenLite.to(thumbHolder, 0.5, {x:thumbHolder.x + thmWidth});
//thumbHolder.x = thumbHolder.x + thmWidth;
}
else if (dir=="right" && thumbHolder.x > - 724 )
{
sliderIndex++;
TweenLite.to(thumbHolder, 0.5, {x:thumbHolder.x - thmWidth});
//thumbHolder.x = thumbHolder.x - thmWidth;
}
if (sliderIndex == thumbCount)
{
sliderDir = "bk";
}
if (sliderIndex == 1)
{
sliderDir = "fwd";
}
changeBg(sliderIndex);
}
public function timeEvt(e):void
{
if (sliderDir == "fwd")
{
navRight.dispatchEvent(new Event(MouseEvent.CLICK));
}
else if (sliderDir == "bk")
{
navLeft.dispatchEvent(new Event(MouseEvent.CLICK));
}
}
}
}
If you still need it you can try these two suggestions. Note I didnt know about Zmags and initially assumed that it was your own domain name. That's why I suggested you use the Loader class. It worked for me when I did a test version of a parent.swf' that loaded a test 'child.swf' containing your code. It actually loaded the child swf without problems.
Change from extending Sprite to extending MovieClip
Avoid checking for added to stage in this project
Explanations:
Extending MovieClip instead of Sprite
I Long story short Flash wont like your swf extending Sprite then being opened by a parent loader that extends Movieclip. The ZMag player will be extending MovieClip. It's logical and the docs do confirm this in a way. Whether it fixes your issue or not just keep it MovieClip when using ZMags.
Avoiding Stage referencing in your code..
Looking at this Zmags Q&A documentaion:
http://community.zmags.com/articles/Knowledgebase/Common-questions-on-flash-integration
Looking at Question 4.. In their answer these two stand out.
Reference of the stage parameter in the uploaded SWF conflicting with the publication
Badly or locally referenced resources in the SWF you uploaded which cannot be found
Is it really necessary to have an added_to_stage check in this? If it wont hurt then I suggest dropping the stage_added checking from function slider5() and instead cut/paste in there the code you have from the function onAddedToStage(e:Event).
Hope it helps.
I'm able to load graphics from an external library with no problems, but for some reason all of the audio will not load/play.
Here's the loader class I'm using...
package
{
import flash.display.LoaderInfo;
import flash.display.MovieClip;
import flash.events.Event;
import flash.net.URLRequest;
import flash.text.Font;
public class LoadLibrary extends MovieClip
{
private var gear:MovieClip = new mcGear();
private var txtLoading:BlankClip;
private var _gameLib:String = "";
private var _Impact:Font = new Impact();
public function LoadLibrary(gameLibrary:String)
{
_gameLib = gameLibrary;
addChild(gear);
gear.x = 512;
gear.y = 384;
gear.alpha = .2;
gear.scaleX = .33;
gear.scaleY = .33;
txtLoading = new BlankClip(_Impact, "LOADING...", -400, -60, 800, 120, 26, "center", 5);
addChild(txtLoading);
txtLoading.x = 512;
txtLoading.y = 525;
txtLoading.alpha = .2;
var request:URLRequest = new URLRequest(_gameLib);
LoadVars.LIBLOADER.contentLoaderInfo.addEventListener(Event.COMPLETE, gameLibraryLoaded);
LoadVars.LIBLOADER.load(request);
}
private function gameLibraryLoaded(e:Event):void
{
removeChild(gear);
removeChild(txtLoading);
LoadVars.LIBLOADER.contentLoaderInfo.removeEventListener(Event.COMPLETE, gameLibraryLoaded);
var loaderInfo:LoaderInfo = LoaderInfo(e.currentTarget);
LoadVars.APPDOMAIN = loaderInfo.applicationDomain;
dispatchEvent(new GameEvents(GameEvents.LIBRARY_LOADED));
}
}
}
and the functions in my main class...
private function loadLib():void
{
_loadGraphics = new LoadLibrary("Elemental_Library.swf");
addChild(_loadGraphics);
_loadGraphics.addEventListener(GameEvents.LIBRARY_LOADED, test);
}
private function test(e:GameEvents):void
{
trace("LOADED");
var music:Sound = new GameMusic();
music.play();
}
Everything works fine until I try music.play and I get "1180: Call to a possibly undefined method GameMusic." I've tried several other audio clips and I get the same message. I tried creating a new library and imported just one audio file, same message. I verified I'm using the correct linkage names and the crazy part is that all of the movie clips load just fine from the same library.
Changed test to...
private function test(e:GameEvents):void
{
trace("LOADED");
var musicClass:Class = Class(LoadVars.APPDOMAIN.getDefinition("GameMusic"));
var music:Sound = Sound(new musicClass()); music.play();
}
I knew it was something stupid :P
package com.fladev.background
{
//import all classes
import caurina.transitions.Tweener;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.DisplayObject;
import flash.display.StageAlign;
import flash.display.StageDisplayState;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.FullScreenEvent;
import flash.events.MouseEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
public class MainClass extends Sprite
{
//create variables
private var loaderMenu:Loader;
private var loaderNames:Array = new Array ();
private var loaderContents:Array = new Array ();
private var loaderSlide:Loader;
private var swfDisplayObject:DisplayObject;
private var swfComObject:Object;
private var xmlLoader:URLLoader = new URLLoader();
private var xmlSlideLoader:URLLoader = new URLLoader();
public function MainClass()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.addEventListener(Event.RESIZE, stageResize);
xmlLoader.addEventListener(Event.COMPLETE, showXML);
xmlLoader.load(new URLRequest("navigation.xml"));
//xmlSlideLoader.addEventListener(Event.COMPLETE, showSlideXML);
//xmlSlideLoader.load(new URLRequest("slides.xml"));
}
function showXML(e:Event):void
{
XML.ignoreWhitespace = true;
var menuBtns:XML = new XML(e.target.data);
var i:Number = 0;
for ( i = 0; i < menuBtns.navItem.length(); i++ )
{
loaderMenu = new Loader();
loaderMenu.name = menuBtns.navItem[i].name ;
loaderMenu.load(new URLRequest(menuBtns.navItem[i].swfURL));
loaderMenu.contentLoaderInfo.addEventListener(Event.COMPLETE, createSwfObjects);
}
}
private function createSwfObjects(event:Event):void
{
var swfContent = event.currentTarget.content as MovieClip ;
var swfName = event.currentTarget.loader ;
navigationContainer.addChild(event.target.loader);
showImage(swfContent);
if ( swfName.name == 'topNavigation' )
{
swfContent.addEventListener("clickHandle",topNavigationClickHandler);
}
}
private function topNavigationClickHandler():void
{
trace('Back to root');
}
private function showImage(navigationItem):void
{
try
{
navigationItem.alpha = 0;
Tweener.addTween(navigationItem, { alpha:1, time:1, transition:"easeOutSine" } );
navigationItem.smoothing = true;
} catch (e:Error) { trace('Error no tweening'); };
stageResize();
}
private function stageResize(e:Event=null):void
{
var centerImages:Array = new Array ( contentContainer, navigationContainer, backgroundImage ) ;
backgroundImage.x = 0;
backgroundImage.y = 0;
backgroundImage.scaleX = backgroundImage.scaleY = 1;
if ((stage.stageHeight / stage.stageWidth) < backgroundImage.height / backgroundImage.width) {
backgroundImage.width = stage.stageWidth;
backgroundImage.scaleY = backgroundImage.scaleX;
} else {
backgroundImage.height = stage.stageHeight;
backgroundImage.scaleX = backgroundImage.scaleY;
}
for each ( var centered:MovieClip in centerImages )
{
centered.x = stage.stageWidth / 2 - centered.width / 2;
centered.y = stage.stageHeight / 2 - centered.height / 2;
}
}
}
}
This is my code for the main.as.
And here my code for my loaded SWF on the maintimeline.
addEventListener(Event.ADDED_TO_STAGE, init);
function init(event:Event):void
{
trace('try dispatch');
dispatchEvent(new Event("clickHandle",true));
}
Try dispatch works, but it does not get back to the main to fire up "Back to root".
Any idea?
thx!
As long as all movieclips dispatching events are added to the display list, this should work. This makes me think that perhaps the event listener being added is not working. Try adding a trace statement to the block of code as shown below:
if ( swfName.name == 'topNavigation' )
{
trace("adding listener");
swfContent.addEventListener("clickHandle",topNavigationClickHandler);
}
I expect that this if condition is failing, and thus your listener is never being created. Also, you need to add a function parameter to the callback method "topNavigationClickHandler" to accept the event as the callback parameter. You have not done this, and this is an error that would be thrown at runtime when the event was received and dispatched to the callback method. You havn't seen this yet because your listener has never had to invoke the callback. So you're gonna have to fix this code like so:
private function topNavigationClickHandler(e:Event):void
{
trace('Back to root');
}
Also I just want to add that your if condition on setting this listener seems a bit redundant, since you already know you are expecting the navigation swf, because you're explicitly loading it. Also I don't believe the name property would be set like this. Typically the name is only set inside the IDE before compilation, and if it isn't, it gets dynamically generated at runtime. What might be more useful is to check the URL of the loaded SWF to see if it contains "topNavigation" or whatever the swf name is. You can do this like so:
var swfUrl:String = myLoader.contentLoaderInfo.url;
if (swfUrl.search("topNavigation") != -1){
//Match found, add listener for navigation
}
I'm a new mem of as3. Today i make a work but i was stacked. pls help me:
My example:
• I have a Symbol in Library with linkage name: box_mc
import flash.display.MovieClip;
import flash.events.Event;
import Src.smoothAnimate;
var box_is:MovieClip = new box_mc();
box_is.name = 'box_na';
addChild(box_is);
var box_is:smoothAnimate = new smoothAnimate(); // ERROR 1151 HERE
• i have a custom class :
package Src
{
import flash.display.*;
import flash.events.Event;
/**
* ...
* #author Trunglvt
*/
public class smoothAnimate extends MovieClip
{
private var currentW:Number;
private var currentH:Number;
private var endX:Number;
private var endY:Number;
private var sp:Number;
function smoothAnimate() {
trace('trace');
}
public function changeSize(speed:Number, newW:Number, newH:Number) {
trace('test');
this.endX = newW; // get new size
this.endY = newH;
this.sp = speed;
this.addEventListener(Event.ENTER_FRAME, onFrame);
}
private function onFrame(e:Event) {
e.target.currentW = e.target.width;
e.target.currentH = e.target.height;
e.target.width += (e.target.endX - e.target.currentW) * e.target.sp;
e.target.height += (e.target.endY - e.target.currentH) * e.target.sp;
if (Math.floor(e.target.width) == Math.floor(e.target.endX) ||
Math.floor(e.target.height) == Math.floor(e.target.endY)) {
//stop function enterFrame here;
removeEventListener(Event.ENTER_FRAME, onFrame);
}
}
}
}
but when run is make error:
1151: A conflict exists with definition box_is in namespace internal.
i want when flash run, the box_is will be add in stage, resize by function changesize.
Pls help me.
Thank you.
When you say:
var box_is:smoothAnimate = new smoothAnimate();
This declaration will error. You previously declared box_is when you said:
var box_is:MovieClip = new box_mc();
Two var cannot have the same name in the same scope.
If you want to reuse the box_is symbol, don't use var. Just reassign box_is:
box_is = new smoothAnimate();