remove this child and add new child AS3 - actionscript-3

i've been stuck on this for quite a while,
i'm working with a Main.as and LivrmScreen.as
and basically LivrmScreen.as is a game screen with other movieclip actions going on...
then i have a button on LivrmScreen that i wish to remove LivrmScreen itself and show homeScreen (all the homeScreen functions are in Main.as)
var homeScreen: HomeScreen;
public function LivrmScreen() {
backhomeBtn.addEventListener(MouseEvent.CLICK, onBackhomeBtnClicked);
}
function onBackhomeBtnClicked(evt:MouseEvent) {
homeScreen = new HomeScreen();
stage.addChild(homeScreen);
parent.removeChild(this);
}
this is what i have right now,
i added parent.removeChild because it won't remove when it is just removeChild ...
and because of that i added stage.addChild so that home screen will show up properly.
but then when homeScreen shows up the button's don't actually work ... so its just showing a dead movieclip. why is that???
i also tried to put the onBackhomeBtnClicked function in main.as thinking so that all the homeScreen functions are there and maybe the buttons will work... but in that case i cant even get the screens to remove and add properly

There's a flaw in your code logics. I don't want to go too deep into the OOP principles or tell you to use frameworks that takes care of these kind of things.
Here's a cheap and fast way out:
in Main.as
private function goToLivrScreen(e:Event = null):void
{
var livrScreen:LivrScreen = new LivrScreen();
livrScreen.addEventListener("onClose", onLivrScreenClose);
addChild(livrScreen);
}
private function onLivrScreenClose(e:Event = null):void
{
removeChild(e.currentTarget as DisplayObject);
// add code to show main menu or whatever you wanted
}
in LivrScreen.as
backhomeBtn.addEventListener(MouseEvent.CLICK, onBackhomeBtnClicked);
and handler
private function onBackhomeBtnClicked(evt:MouseEvent):void
{
// remove all listeners from all object that you have so your LivrScreen could be garbage collected
// when done just dispatch the Event that Main.as is waiting for
dispatchEvent(new Event("onClose"));
}
This is a pretty crude way to do it and there can be many improvements, but it will make your code a little cleaner and hopefully, more scalable in case you want to add new screen or change some implementation.

Related

method (function) in subClass not being called on mouse event

My goal is:
define a subClass of Sprite called Ship
use an event at runtime to call a function within this new class
It seems that I've figured out how to create my Ship class using a package in a linked .as file. But I can't seem to access the function within that class. Can anyone see what I'm doing wrong?
var ShipMc:Ship = new Ship();
addChild(ShipMc);// This successfully adds an instance, so I know the class is working.
addEventListener(MouseEvent.CLICK, ShipMc.addShip);//But this doesn't seem to run the function
This code works fine for instantiating a Sprite, but the code in the Ship.as file, specifically the function, is not working. No runtime errors, but nothing traced to the output window, either.
package
{
import flash.display.Sprite
public class Ship extends Sprite
{
public function addShip():void
{
trace("running addShip function")
}
}
}
The last time a coded anything in flash it was AS2!
I'll just mention that I've tried using addShip():void and just addShip(). Same response with both. It should be with :void, right? Anyway, the fact that neither one throws, tells me that this section of code isn't even getting read, I think.
Any help is much appreciated! Pulling my hair out.
Your code is not working because it contains some problems, so let's see that.
You should know that you are attaching the MouseEvent.CLICK event listener to the main timeline which didn't contain any clickable object yet now (it's empty), so let's start by adding something to your Ship class to avoid that :
public class Ship extends Sprite
{
// the constructor of your class, called when you instantiate this class
public function Ship()
{
// this code will draw an orange square 100*100px at (0, 0)
graphics.beginFill(0xff9900);
graphics.drawRect(0, 0, 100, 100);
graphics.endFill();
}
public function addShip():void
{
trace("addShip function run");
}
}
N.B: You can attach the MouseEvent.CLICK event listener to the stage, which will work even if you have nothing in the stage.
Now, if you test your app, you'll get an clickable orange square at the top left corner of your stage, but the compiler will fire an error (ArgumentError) because it's waiting for a listener function (the Ship.addShip() function here) which accept an MouseEvent object.
So to avoid that error, your Ship.addShip() function can be like this for example :
public function addShip(e:MouseEvent):void
{
trace("addShip function run");
}
Then your code should work.
You can also simplify things by using another listener function in your main code which can call the Ship.addShip() function, like this for example :
var ShipMc:Ship = new Ship();
addChild(ShipMc);
addEventListener(MouseEvent.CLICK, onMouseClick);
function onMouseClick(e:MouseEvent): void
{
ShipMc.addShip();
}
For more about all that, you can take a look on AS3 fundamentals where you can find all what you need to know about AS3.
Hope that can help.

Custom Event Listener not working

I am new to as3 and I recently saw creation of custom events in as3 in a tutorial and I wanted to incorporate in my game. When i did the tutorial, it all seemed well for that project. But it doesnt seem to work with the new project.
Here is my code :
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class FashionFrenzy extends MovieClip
{
public var Buyer_mc:Buyer;
public var Buyers:Array;
public var gameTimer:Timer;
public function FashionFrenzy()
{
GameTimeController();
GenerateBuyers();
addEventListener(ReachMallDoorEvent.CHECK, OnReachMallDoor);
}
public function GameTimeController()
{
gameTimer = new Timer( 25 );
gameTimer.start();
}
public function GenerateBuyers()
{
Buyers = new Array ;
Buyer_mc = new Buyer(533.2,0) ;
addChild(Buyer_mc);
gameTimer.addEventListener( TimerEvent.TIMER, BuyerEnter );
if(Buyer_mc.y==377.25)
{
dispatchEvent( new ReachMallDoorEvent( ReachMallDoorEvent.CHECK ) );
}
}
public function BuyerEnter(event:TimerEvent)
{
Buyer_mc.Enter();
}
public function OnReachMallDoor(event:ReachMallDoorEvent)
{
trace("my timer starts now");
}
}
}
Here, OnReachMallDoor never seems to run because there is something wrong. I cant see the output saying "My timer starts now". But there is no error in the code and output doesnt show any runtime errors either. Where have I gone wrong? I want OnReachMallDoor function to run when my y coordinate is in desirable position and the event is dispatched.
The order of commands is wrong.
GenerateBuyers();
addEventListener(Rea...
The first line of these two is the one that could potentially cause the Event to be dispatched. But only after that will you start listening for it. That's simply too late. You have to start listening before the Event is dispatched.
The probability of the Event to be dispatched is very low.
Buyer_mc.y==377.25
Checking floating point values for equality is often not a good idea. It could easily be just slightly off due to rounding errors etc. If this .y property was controlled by the mouse for example, you'd have to position the mouse at exactly that position, which is very unlikely.
You only dispatch the Event at the beginning.
GenerateBuyers();
That function is only called once. The .y position is evaluated.
This only happens once and never again.
But the .y position is subject to change and the condition should be evaluated again, which doesn'T happen
The structure is not helpful.
It doesn't make much sense for an object to listen for its own Events. Simply call the function and be done with it.
Events are for communication between objects.
How this is supposed to be:
The point of the custom Event is to be notified about something.
You want to be notified when this condition
Buyer_mc.y==377.25
is true.
If you are evaluating that condition the way you do it now, then there's no point in receiving a notification about the result thereof. You have it already.
Instead, Buyer_mc should dispatch the Event. The condition should be checked in Buyer class.
What the code looks like
some snippets pointing out what the above means, code untested:
class Buyer
override public function set y(value:Number):void
{
if (value == 377.25)
dispatchEvent(new ReachMallDoorEvent(ReachMallDoorEvent.CHECK)); // I'm at the position, I send out the notification
super.y = value;
}
class FashionFrenzy
buyer = new Buyer(533.2, 0); // variables should start with small letter
buyer.addEventListener(ReachMallDoorEvent.CHECK, OnReachMallDoor);
If you now set the .y position to the value, the object will dispatch the Event. It will figure that out on its own.
Letting the object figure something out on its own and just receive a notification about it is the main reason to use custom events.

How do you handle stage Event.RESIZE in an Actionscript3 application?

This has long bothered me.
When using stage resize, you could say something like this:
public class Preload extends MovieClip
{
protected var main:Main;
public function preloader()
{
this.main = new Main();
this.addChild(this.main);
stage.addEventListener(Event.RESIZE, this.onResize);
}
protected function onResize(e:Event): void
{
this.main.x = stage.stageWidth>>1;
this.main.y = stage.stageHeight>>1;
}
}
What about if Main needs to also resize? I have many systems which respond to a resize event and I do not know if I should simply add a stage Event.RESIZE listener to every screen or if this should be controlled from a single location.
For example, add this.main.resize() to the onResize listener above then implement an IResizable interface on my screens for example?
What is best practice?
EDIT: Or should resize be part of something more generic, like invalidate()
For performance it's better to have only 1 Event.RESIZE listener in your document class. Then propagate the event to all your sub classes and children with functions, or even better with the wonderful Signals framework by Robert Penner.
If you need to scale your document class the easiest way is to put all your content inside a Sprite and scale that instead.

Removing a child of a video class called from a private function

I'm making a quiz type animation for work where on clicking an answer it plays a short animation FLV file relating to what you picked. As everything I read points towards AS3 being OOP I decided to make a MovieClip containing an FLV player and linked it to an AS3 file called FLV_Player.as. That way I can create a new instance of the FLV_Player everytime I need to play a video. Here is the code in that file which seems to work fine:
package
{
import fl.video.VideoEvent;
import flash.events.VideoEvent;
import flash.display.MovieClip;
public class FLV_Player extends MovieClip
{
public function FLV_Player(NextVideo:String)
{
animation_player.source=(NextVideo);
animation_player.addEventListener(VideoEvent.COMPLETE, vcompleted);
}
private function vcompleted(e:VideoEvent):void
{
nextFrame();
}
}
}
Now in the DocumentClass.as file I have this code:
private function NewVideo(videoname:String)
{
var nextvideo:FLV_Player = new FLV_Player(videoname);
addChild(nextvideo);
nextvideo.x = 0;
nextvideo.y = 0;
}
So when you click a button, go to the next frame or whatever the prompt is, it calls the NewVideo function and passes the name of whatever video is to be played next.
NewVideo("Introduction.flv");
Now I'm sure I'm going to run in to other issues later down the line as I really have no idea whether anything I've done is how it should be done, but the only issue I seem to be having at this point in time is removing the video and going to the next (or previous) frame to answer another question. I tried:
nextFrame();
removeChild(newVideo);
But it didn't work. Well, it may have gone to the next frame but with the video taking up the whole window it's hard to see if it did or not.
So how do I remove the video I've created? The main issue seems to be that because I had to create a new instance of the FLV_Player class in a private function the child is defined locally "var", rather than "public" or "private" var so I can't reference it again. It tells me that you can only create a "private var" from within the document class but if I make it there it will create the class on load rather than from the function when I'm ready to pass the video name parameter to it. At load I don't know what video I need it to play?
removeChild() must be called from the same object in which it was added. In this case, your DocumentClass. What you're trying to do now is telling an FLV_Player to remove itself, which won't work due to several reasons and bugs in your code.
The correct way to do things would be to have the FLV_Player object dispatch a custom event that your DocumentClass listens for. You need to create a new class which inherits from Event to create your custom event. I'd call it "PlayerEvent". In DisplayClass function you'd do this:
nextVideo.addEventListener(PlayerEvent.PLAYBACK_FINISHED, onPlaybackFinished);
addChild(nextVideo);
Then you need to create the onPlaybackFinished method:
private function onPlaybackFinished(event:PlayerEvent):void {
nextVideo.removeEventListener(PlayerEvent.PLAYBACK_FINISHED, onPlaybackFinished);
removeChild(nextVideo);
}
Inside the FLV_Player class, the vcomplete function should change to:
dispatchEvent(new Event(PlayerEvent.PLAYBACK_FINISHED));
Alternately, you could pass a pointer of the DocumentClass to the FLV_Player object, but this is very messy, can cause serious problems and not at all in the spirit of OOP. But it's a quick fix if you want to be lazy.
Events are an extremely important part of Actionscript 3 and I recommend you read up on them. Here's some good references:
http://www.adobe.com/devnet/actionscript/articles/event_handling_as3.html
http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7fca.html
http://www.blog.mpcreation.pl/actionscript-3-0-basics-custom-events-part-1/
I think you're right that your first problem is simply how to reference the new video, so to expand on my comment a bit: You can declare a variable without also assigning a value, so you don't need to have var nextvideo within your NewVideo function. With a class level variable instead, you can then reference whatever you set nextvideo to when you want to remove the video:
public class DocumentClass {
private var nextvideo:FLV_Player;
private function NewVideo(videoname:String)
{
nextvideo = new FLV_Player(videoname);
addChild(nextvideo);
}
private function removeVideo():void
{
removeChild(nextvideo);
nextvideo = null;
}
}

calling function in a runtime loaded swf

Using AS3 / Flash CS4
Alright thanks to everyone who is reading this. My problem specifically I am designing a user interface with controls on it. 5 buttons rotate left, rotate right, zoom in, zoom out, and auto rotate. The interface in itself works fine, I can trace out button clicks, toggle the auto rotate button etc...
My program reads an xml file. Loads some images, fills an array with links for each image, and when the image is clicked a loader loads a swf from a URL and displays it on screen. No problem.
Now I originally had the zoom controls user interface in the runtime_loaded.fla library, and the mouse listeners in the same linked document class. The interface works with the movieClip in runtime_loaded.swf when it is in the same code.
Now to practice good coding, I decided to remove the UI from the runtime_loaded.fla and add it to the Main.fla. This is essential because the main is going to handle possible 100's of images/objects that each have their own unique swf to link too. If I decide to change out the look of the interface but leave the function calls the same, I could essentially put in as many as I want into the main.fla instead of the runtime_loaded.fla which I would have to do for every single object.
THE FILE STRUCTURE
Main.fla <- interface in the library. 5 mouse event functions. Inside each function calls
a property of loaded_swf (loaded_swf.rotateLeft, loaded_swf.rotateRight) etc...
Runtime_loaded.fla <- links specificObject.as in properties (AS3/CS4)
specificObject.as <- has 5 public static functions{ rotateRight, rotateLeft, zoomIn, zoomOut, toggleAutoRotate }
THE CODE
//showFlashBox
function showFlashBox(temp_string:String):void {
if(!flash_box_on){
var temp_top:uint = numChildren;
addChildAt(FlashBoxContainer,temp_top);
newXButton.addEventListener(MouseEvent.CLICK, flashBoxXClick);
1. addChild(new_loader);
2. var url:URLRequest = new URLRequest(temp_string);
new_loader.x = 0;
new_loader.y = 0;
new_loader.load(url);
3. new_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, gotSwf);
flash_box_on = true;
}
}
function gotSwf(e:Event){
4. //loaded_swf = e.target.content;
trace(e.target.content);
5. new_zoom_controls.button_minus.addEventListener(MouseEvent.CLICK, zoomOutFunction);
new_zoom_controls.button_plus.addEventListener(MouseEvent.CLICK, zoomInFunction);
new_zoom_controls.button_left.addEventListener(MouseEvent.CLICK, rotateLeftFunction);
new_zoom_controls.button_right.addEventListener(MouseEvent.CLICK, rotateRightFunction);
new_zoom_controls.button_rotate.addEventListener(MouseEvent.CLICK, toggleRotateFunction);
function rotateRightFunction(e:MouseEvent){
6. //loaded_swf.rotateRight();
}
function rotateLeftFunction(e:MouseEvent){
//loaded_swf.rotateLeft();
}
function zoomInFunction(e:MouseEvent){
//loaded_swf.zoomIn();
}
function zoomOutFunction(e:MouseEvent){
//loaded_swf.zoomOut();
}
function toggleRotateFunction(e:MouseEvent){
//loaded_swf.toggleAutoRotate();
if(new_zoom_controls.button_rotate.currentFrame == 1){
new_zoom_controls.button_rotate.gotoAndStop(2);
}
else new_zoom_controls.button_rotate.gotoAndStop(1);
}
new_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, gotSwf);
}
If you follow steps 1-6 you see my steps of loading the .swf, mouse event listeners and click handlers, then the object call of the var loaded_swf:Object;
public static function rotateLeft():void
{
object.yaw(animation_turning_speed);
}
public static function rotateRight():void
{
object.yaw(-animation_turning_speed);
}
if I run the main.fla and try to click the buttons. This happens.
ReferenceError: Error #1069: Property rotateRight not found on
ThreedsKU39web and there is no default value. at MethodInfo-82()
ReferenceError: Error #1069: Property rotateLeft not found on
ThreedsKU39web and there is no default value. at MethodInfo-83()
I actually stumbled upon the answer before I finished submitting this as I went through the code to copy it. But after spending a few hours of frustrating moments on this last night, I will post it to ensure the next guy doesn't meet the same demise.
The answer was in the function of the runtime-loaded swf class.
public static function rotateRight():void
{
object.yaw(-animation_turning_speed);
}
It turns out it only needs to be public function instead of public static.
Mainly human error as after the file was working, I attempted to copy the code over to all my other object files, and somehow static got back in there and messed it up. So for future reference when loading in the external swf, public function should do the trick. *Note that many of my variables were returning errors until being declared as public static though.