AS3/CS4 removed TextField reappearing after tween finishes - actionscript-3

I load a swf via the Loader() class. As the swf is loaded I loop through all the children of root and remove any TextField with removeChild(). This works initially - the TextField is removed. But as a tween in the loaded swf finishes and loops, the removed TextField somehow reappears. The TextField is Dynamic text. If I remove some StaticText, this stays removed. What is going on here?
loopChildren(root);
function loopChildren(dispObj:*):void {
for (var i:int = 0; i< dispObj.numChildren; i++) {
var obj:DisplayObject = dispObj.getChildAt(i);
if (obj is DisplayObjectContainer) {
loopChildren(obj);
}
else {
if (obj is TextField) {
obj.parent.removeChild(obj);
i--;
}
}
}
}
If I call loopChildren with a timer (5 sec intervall) and trace(obj.name) for all children, I notice that the obj.name changes. The TextField is called instance11, instance32, instance54 and so on. It seems that a new instance is created and added continuously?
EDIT:
If I transfer the code directly to the swf and run it without using the wrapper it works as expected. I must be missing something that happens when its loaded through another movie?
EDIT2:
I should say that the TextField I'm trying to remove is in a separate layer on the same time line as the tween. If I put the tween in its own timeline, it seems to work as expected. But can't dynamic text and tween live together?

It sounds like your text field is defined on the stage (i.e. in the FLA, not instantiated by script), and the layer it's on probably has a keyframe that is played through at some point in your tween.
If that's correct, then what you're running into is a fairly low-level limitation of Flash regarding the competing natures of the timeline and the script environment. When you play through a tween, every timeline keyframe encodes some information for Flash about what sorts of object should be on the stage at that point, and where they should be, etc.
But when you also start referencing those same object with script, in general Flash has to guess whether you want the script or the information in the timeline to take precedence. In this case, probably what's happening is that after you remove the text field with script, one of the frames your tween plays through references the same field, and Flash doesn't know whether the removal was supposed to be permanent, or whether to honor the keyframe and recreate the field.
Thus, the short answer (too late!) to your question is, in general you should try to handle your stage elements with timeline tweens, or script, but not both. This is why your solution in edit #2 worked; because by moving the tween onto its own timeline, (I'm guessing) you no longer played across keyframes that encoded information about the text field in question. Another solution would probably be to remove the offending text field via the timeline (by playing to a keyframe where that text field no longer exists). Or, of course you could also control your textfield solely by script, creating it and destroying it, so it's never part of the timeline at all.

Why not just set the text field to empty?
loopChildren(root);
function loopChildren(dispObj:DisplayObjectContainer):void
{
for each(var i:int = 0; i < dispObj.numChildren; i++)
{
var obj:DisplayObject = dispObj.getChildAt(i);
if (obj is DisplayObjectContainer)
{
loopChildren(obj);
}
else if (obj is TextField)
{
TextField(obj).text = "";
}
}
}

Related

Flash AS3: Swapping Parts within Movieclips

I have a Movieclip (level 1, MC) with around 10 frames. There is a different movieclip (level 2, Move Jump etc animation) on each frame. Inside each of the level 2 movieclips, there are about 30 movieclip symbols (level 3, Head Arm etc) each spamming about 100 frames with around 30-50 keyframes. Each level 3 symbol has around 10 frames, on each frame I have a particular skin graphic.
I have all the level 2 and level 3 symbols instance named (same label across timeline for the same object), and I have the right frames stop(); and labelled. I also understand that everytime I enter a new frame in not just level 1 but also level 2, I have to reset all the level 3 symbols to the desired frame, because my previous settings will be destroyed upon leaving frame.
I got it working by doing level1.gotoAndStop(level2name) ---> level1.level2.level3.gotoAndStop(skintype) and then loop over a nasty nasty number of poses X bodyparts. AND this process needs to be performed in an ENTER_FRAME event since everything will be reset again. Needless to say, I really really don't want to do it this way.
One of the alternatives is breaking the graphics up and have many many level 2 poses movieclips inside my level 1 MC movieclip (mage hit by warrior 3rd attack, warrior hit by rogue 4th attack...). That's what I used to do before. But for this project, a simple calculation tells me I need to make 200+ animations that way, which is not feasible. I can also get rid of level 1 MC and have the poses saved into an array, but the bodyparts still need to be refreshed every frame.
I'm hoping that there's a relatively quick fix to this that I managed to miss, as it seems like such a basic feature, I'm sure many flash games will have to go through it (dress up, or anything with customization + animation really). Yet somehow I've been searching for days and can't find a cure. The author-time ability to simply swap out graphics within a symbol to replace every frame of every animation in the entire file also suggests that there's gotta be a more universal approach to these swapping. I hope you can prove me right!
I do have 2 things that I don't know if I should even bother trying: 1) Drag the MC onto frame1 (my only frame), where I currently have nothing but code. 2) Declare each bodypart individually AND declare MC, then have MC's parts link to these bodyparts. Basically, I just need a viable method to keep these bodyparts from resetting everytime the animation goes to a new frame, my flash knowledge is not enough to tell me whether if it's even possible to have these "global graphics bank independent of frames".
And yes I know I'm probably not doing it in the most clean way possible, but I simply animate better with visuals, so while I CAN start from shapes and animate everything using strictly code I REALLY want to move away from it. The art style is pretty important in this project.
UPDATE: For now, I went for the ugly route. Everytime the MC changes animation, I do:
MovieClip(DisplayObjectContainer(MC.getChildByName(MC.move))).Hand.gotoAndStop(MC.skinname);
And repeat that for all 35 body parts. Turns out that flash replaces all frames of hand in the MC.move, which makes life a lot easier. The alternative is to poll for every single frame, but the direct consequence is MUCH slower fps. Instead, right now I only need to switch graphics whenever there is a change to the moves.
This works, but I'm aware that it slows down performance quite a bit. In fact it can slow down performance in the same magnitude as the actual vector rendering. Limiting the swapping to only move changes is really not optional but mandatory.
Please look at this: http://zdg.ru/tmp/animation.swf
The source can be downloaded here: http://zdg.ru/tmp/animation.fla
If I got your description correct, I did the animation in the same way. The main timeline has a single frame with a character symbol. A character symbol has a timeline within it with two animation points "stand" and "jump". The character consists of symbols "head", "body", "left_hand", "right_hand", "left_leg", "right_leg". Each of these symbols is animated independently. Charater animation timeline contains both keyframes and tweens. All symbols are named consistently in all frames.
Each character part, in turn, has a timeline of 2 frames, corresponding to skin 1 and skin 2.
As you can see, the skin is not destroyed during the animation and there is no need to correct it in every frame.
The code on the main timeline is:
var char_body_parts:Array = new Array(
mv_char.body, mv_char.head, mv_char.left_hand, mv_char.right_hand,
mv_char.left_leg, mv_char.right_leg
);
var skin_num:int = 1;
mv_char.gotoAndStop("stand");
setSkin(char_body_parts, skin_num);
btn_jump.addEventListener(MouseEvent.CLICK, doJump);
btn_skin.addEventListener(MouseEvent.CLICK, doSkin);
function doJump(evt:MouseEvent):void {
mv_char.gotoAndPlay("jump");
}
function doSkin(evt:MouseEvent):void {
skin_num++;
if (skin_num > 2) skin_num = 1;
setSkin(char_body_parts, skin_num);
}
function setSkin(parts:Array, skin_num:int):void {
for (var i:int = 0; i < parts.length; i++) {
(parts[i] as MovieClip).gotoAndStop(skin_num);
}
}
================== UPDATE ====================
This is the updated animation: http://zdg.ru/tmp/animation3.swf
The source can be downloaded here: http://zdg.ru/tmp/animation3.fla
Now my setup is identical to yours.
I have a 2-frame char, one frame contains "stand" movieclip and the other frame contains "jump" movieclip.
Indeed, when you gotoAndStop for any of animations, skins get lost. But you don't have to update them every frame. You need to update them only in the first frame of animation, i.e. right after gotoAndStop("animation"). I still have a list of body parts to bulk assign the skin but now they are accessed by name. So the main code changes are:
var char_body_parts:Array = new Array(
"body", "head", "left_hand", "right_hand",
"left_leg", "right_leg"
);
function setSkin(char:MovieClip, parts:Array, skin_num:int):void {
for (var i:int = 0; i < parts.length; i++) {
char.mv_animation.getChildByName(parts[i]).gotoAndStop(skin_num);
}
}
function setAnimation(char:MovieClip, anim_name:String):void {
char.gotoAndStop(anim_name);
setSkin(char, char_body_parts, skin_num);
}
There are also two more solutions, I didn't code them but they are easily described.
In frame 1 of each skin movieclip, add gotoAndStop((root as MovieClip).skin_num). It works as follows: whenever a skin gets reset, it starts from frame 1. In frame 1 it will gotoAndStop to the current skin automatically. So you dont need to do anything else.
Put your animation movieclips not in the timeline, but in the same single frame. Name each animation lke "stand", "jump" etc. Switch animations not by gotoAndStop, but by making selected animation visible and others invisible. The skin would have to be set once for each skin change.

Replacing movieclip

I m currently working on converting one of my as2 game project into as3 (flash pro cs4). But there is a problem on the background movieclip.
I have a function called disposemc:
function disposemc(mcname:MovieClip):void{
mcname.parent.removeChild(mcname);
mcname = null
}
Another function called changelayer:
function changelayer(mcname:MovieClip,layer:MovieClip):void{
layer.addChild(mcname)
}
So in main timeline frame 2 I have a movieclip on stage (placed in IDE) with instance name "bg_mc", then on main timeline frame 3 I have a DIFFERENT mc on stage with the SAME instance name "bg_mc". The purpose of this is to replace the old bg_mc by the new one.
The problem is,
In frame 2, I applied changelayer function to bg_mc and moved it into a child mc of root by addChild, and then applied a function of my CPU image post processing framework and added the bg_mc into an array.
After some stuffs happened, I went nextFrame to frame 3, and found that the new bg_mc didnot replace the old one, instead it overlaps.
So I tried disposemc function when leaving frame 2 to get rid of the old bg_mc, and at frame 3 I applied changelayer to bg_mc and added bg_mc to my render array.
And I found that the old bg_mc is off the stage but it is still rendering onto my bitmap data, means it is not nullified like it suppose to be in disposemc function. And it is also hard to access it because the name overlaps. When I call bg_mc in frame 3 it is the new one, but the old one still exists, and from the rendered bitmap data it can see it is still playing.
Will making the old mc stop in disposemc function help?
Can anyone give any help? If my structure of making bg is bad, is there any other way to override an instance with a different mc in library?
The purpose of this is to replace the old bg_mc by the new one
You work with MovieClip and frames. So use keyframes by design. If you need to place different background in third frame, don't program it, place it. If you want program, don't use MovieClip with keyframes as main navigation instrument.
Main timeline could be easily swapped with very simple logic and several movie clips with only one frame
//Some MovieClips from the library, with only one frame, still designed in Flash IDE
var currentScene:DisplayObject;
var home: MyHove = new MyHove()
var intro:MyIntro = new MyIntro();
navigate(home);
//after some interaction from the user, go to another page
navigate(intro);
//It will work like gotoAndStop... but better, and give you more control
function navigate(scene: DisplayObject):void{
if(currentScene != null){
removeChild(currentScene);
}
currentScene = scene;
if(currentScene != null){
addChild(currentScene);
//apply logic for swapping background
}
}

as3 Air - AddChild works but is slooooooooooow

I am creating an app where when a button is pressed a very large picture is added to the stage (it is larger than the screen but can be dragged around by the user)
When the button is pressed the picture (well, movieClip) does come up and it able to be dragged fine, buttons inside it work.
The problem though is that there is a pause of about 6 seconds between the button press and the image appearing. I am using one .fla file for publishing and compiling (let's just call it Main.fla for now), and another one to hold all the graphics. The graphics are then added with this embed command:
[Embed (source = "assets/graphic.swf", symbol = "Content")]
private var Content:Class;
private var _content:*;
I have these lines where all the variables are declared (in between the class definition and the constructor function) I was under the impression that embedding it like this was equivalent to loading it at compile time. Is this true? What could be causing this lag when the button is pressed?
If I can't cut out the lag, another idea I had was to make some spinning circle or something to tell the user, "hey, don't worry. It's loading!"
If the slowness is at addChild you can add the asset to the stage much earlier and set it's visiblility to false, then when the button is clicked set it back to true. Obviously this is a small hack but might be sufficient for what you are doing.
var asset:MovieClip;
private function init():void
{
asset = new Content();
assset.visible = false;
addChild(asset);
button.addEventListener(MouseEvent.CLICK, onMouseClick);
}
private function onMouseClick(e:MouseEvent):void
{
asset.visible = true;
}
Embedding your SWF is probably not what is causing the delay.. or rather it would not likely be better if you imported the SWF into your FLA. Is this on a device? Chances are you would either have to devise a different way of loading your asset, or be satisfied with a loading animation.
If the main K size is coming from a large image, you could consider loading it in segments, starting with the part that is initially visible.

Unable to access children in movie clip

Inside flash cs6 I have drawn a flash movieclip in which I set export settings as abc.Gameboard. Inside gameboard I have a bunch of pieces (symbol:Piece) which I export as abc.Piece - both base class set to MovieClip and with class files. The piece has frame labels like hit, over etc.. My problem is accessing the pieces in code so I can eg. gotoAndPlay("mine") - at the moment the event only fires once which is the last piece on the board.
I can set the frame action on this last piece but would like to figure out how to do same for each piece.
I add a gameboard to the stage like so
var gb:Gameboard = new Gameboard();
gb.name = "gb001";
contextView.addChild(gb);
Then
contextView.addEventListener(Event.ADDED, thingAdded);
private function thingAdded(event:Event):void
{
var type:String = event.target.toString();
switch(type)
{
// this runs only once - i want it to run for each piece that is inside the symbol
case "[object Piece]":
var p:MovieClip = event.target as Piece;
p.gotoAndPlay("mine");
break;
}
}
or if there's a better way that would be great.. this looks pretty clunky
Edit: Bit more info about how I'm trying to build the gameboard
Draw a collection of shapes in illustrator - mask it (Gameboard region). Import into Flash as Graphic. Convert graphic to several movie clip symbols (So JSFL can drill down and access masked pieces) - run JSFL script & create 00's of pieces. Then I set export settings on Piece and Gameboard and add Gameboard to the contextView.
I actually wrote an entire article about this once. The ADDED event should fire once for every DisplayObject that gets added. Are you sure that you're not using ADDED_TO_STAGE, which does not bubble? If you're using ADDED_TO_STAGE, then you need to set the useCapture flag to true to get it to fire for all children.
If you want to involve RobotLegs in the process, probably the better way is to simply create a "marker" Class for each specific button that you want to have behave in a different way, then register a mediator for each Class that will manage the behvior. Robotlegs already has the hooks built in to listen for ADDED_TO_STAGE and do this.
However, you could also consider using the Flash IDE for what it's for, which is putting stuff on stage. In that case, your GameBoard instance will be ready in the constructor of your main document Class for you to do whatever you want with it.
MPO is that logic that is outside Gameboard shouldn't know or care how it works internally, and honestly it probably shouldn't even be GameBoard's responsibility to handle simple stuff like button over states and things. That should be up to the button itself. If the buttons don't need to toggle or anything beyond what SimpleButton handles, you can just declare the button instances as Button in the library instead of MovieClip and get all that stuff for free instead of coding it yourself.
Part of being a good coder is in being able to figure out ways not to code everything.
in their Gameboard inside Piece? I want know exactly your Gameboard Structure.
If you're right. try this:
function thingAdded(e:Event):void
{
if(!e.target is Gameboard) return;
var mc:Gameboard = Gameboard(e.target);
var i:int = 0;
while(i<mc.numChildren)
{
if( mc.getChildAt(i) is Piece)
{
var piece:Piece = Piece(mc.getChildAt(i));
piece.gotoAndStop(2);
}
i++;
}
}
Here is my Sample code: Gameboard

hitTestObject, stopDrag stops drag on two movieclips even though function states one movieclip to stop drag

I have a function that states when movieclip1 is dragged and hits a line then it stops the drag, however it seems to stop the entire drag function in the swf on the other movieclips even though they arent called in the function. Can somebody please help me with this.
Regards
T
Here is the code:
function hitTest(event:Event):void
{
if (movieclip1.hitTestObject(line))
{
movieclip1.stopDrag();
}
else
{
}
}
Are you absolutely positive you only have one instance of movieclip1 on your stage? Definitely double check. Are you creating them dynamically, or are they preloaded when your SWF loads?
If they're preloaded:
Perhaps during testing you made some quick copies of it, and now those copies have the same name and they're all responding the same. That's my first guess.
If they're loaded dynamically:
Check the function where they're being created. If you're naming them in a loop (with a number on the end like the above), be sure that you're properly increasing the numeric value used on the end.