I'd like to make a simple game where "discs" fall from the top of the screen and the user must catch them. I have a MovieClip which I want to resize to one of three randomly chosen sizes.
As I see it, there are four things that must be done.
Create and size the MovieClip
Position the MovieClip
Make the MovieClip fall
Determine when it is finished "falling" and see if the user has "caught" it.
My question is: How do I create, size and position the MovieClip? I've given it an identifier of "disc". Now what? Do I make an ENTER_FRAME event and do my creation there? How do I move the disc downwards? Do I use tweens, something else?
I'm primarily asking this as a sanity check.
I would use some kind of factory class that would be responsible for dropping random discs from the top of the stage.
Beside what you correctly mentioned, you will also need to:
define if the speed for falling is constant or not, you may need some acceleration tween. To move the objects downwards, you could use a native tween method, you will need to apply it to every disk that gets dropped.
define where the disk will start falling, it can be random or always from the same place.
you can find out if two objects are colliding using the AS3 hitTestObject method which belongs to the DisplayObject class.
you factory class could have a start() and stop() method. Once start() is fired, an infinite or ENTER_FRAME loop is started and disks start falling. If you want to create disks at a specific rate you could combine your loop with a timer to run code on a defined interval. For instance, every 3 seconds create 10 disks (using main loop) and drop them onto the stage.
Assuming that you have MovieClips named 'disc' & 'userHand' exported into actionscript, I'll summarize it in the foll way:
Generate the no of discs & Randomize their location. Start with something like:
var n:int = 30; //Total no of Discs
for(i:int=0;i<n;i++)
{
var mc:disc = new disc();
mc.x=Math.random()*stage.width(); //to scatter the discs across the stage
mc.y=-mc.height; //initially hide out a disc
addchild(mc);
}
Also add the Movie clip 'userhand' to stage.
Add enterframe handler function.
Fill in the enterframe handler to update (keep increasing) the y position of each disc.
Use hitTestObject() in the enterframe handler to determine hit among each 'disc' & 'userHand'.
Reset position of all the 'disc' clips which fall off the screen to random positions as initially.
You might want to look at programming particles.
http://r3dux.org/2010/01/actionscript-3-0-particle-systems-3-rain-effect/
At a very high level what you would do is.
You need to create a disc class.
You could give this class some variable properties like width, height,x etc.
In an enter frame in your main class you would add an enterframe function that creates new instances of disc passing it random values for each property.
Each instance of disc could also have its own entframe which increases its y position until it reaches the bottom of the screen. The disc would then remove its self from the stage. You could use an easing function passing it a random number to determine the rate at which its falls.
Say if its y position is greater than the stage height, remove the disc. If the user catches it (using a hit test maybe) also remove it.
It really recommend having a look at that link I posted.
Related
I'm aware that addChild (1) adds the object into a display container object, and (2) shows the object in the DisplayObjectContainer. What I want to know is what happens when an object is added into a DisplayObjectContainer?
To summarize my question is (are),
Is there any magic happens when addChild invoked? i.e. Something is happening in, for example, DisplayObjectContainer.
Let's say, I have MovieClip A and B. B has A as part of it. I called addChild (A) in B. In MainTimeline and Stage, I don't call addChild (B). Visually, since B hasn't been added, A won't be there too. However, does A is exist (e.g. the memory allocated), even though it's not on the Stage?
I have searched here and there in SO, but humongous amount of the questions asked related to mine are technical. I greatly appreciate any answer or pointer regarding my questions
Here is simplified explanation of what happens.
When you create MovieClip A (or any object) using the new keyword (or if using FlashPro an item that exists on the timeline where the playhead is), that object is in memory. So whether or not MovieClip A is on the display list, it is taking up memory in your application.
When you use addChild, here are some of those things that happen (not necessarily in order):
If the object being added already has parentage, it is removed from that parent (though scale and position are kept, and will now be relative to the new parent).
Events are dispatched on the new parent (and the old parent if applicable). Event.ADDED and Event.ADDED_TO_STAGE + Event.REMOVED / REMOVED_FROM_STAGE on the old parent.
The parent(s) of the newly added object, will now take into account the new child/grandchild. Things like hit tests, and bounds, and mouse overs etc.
On the next frame tick (the stage's refresh rate), that item will be drawn
All that said, once a movieClip is on the display list, there is performance drain VS just having that object in memory - so if an object doesn't need to be seen, it's more efficient to have it off the display list until it needs to be seen.
If using FlashPro/Animate, you should also be aware that if through code you do anything that manipulates the parentage of a timeline display object (addChild/removeChild/setChildIndex etc), that timeline object will no longer be managed by the timeline. That means that if you have an empty keyframe to remove an item from the timeline, that item will actually stay on the screen until you either explicitly remove it (removeChild(item)) or it's parent goes away.
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.
i am working with several nested movieclip objects in a project. but i get into trouble with the buttons i created and implemented in the nested movieclips:
to describe it in a simple way:
I have a main movieclip with five frames, including two buttons with listeners to browse between the frames. Then inside of one Frame I have another movieclip with its own buttons. i instanciated it by hand not through code and gave it a specific name like "nestedMc".
Now I dont want to build the Listeners for those buttons inside the class of the nested movieclip class but in its parent class, which works fine until i then goto another frame in the main movieclips timeline and come back.
obviously every time flash enters a frame its contents get created anew (and therefore get new instance names). I could now try solve this through filling the frames via code.
But maybe there is another way to make sure the frame contains the same instance everytime i enter?
Timeline scripting is a dirty business, and really, a carry-over compatibility layer for Actionscript 2 projects. Whenever possible, I highly recommend not doing it, and simply keeping all of your code in your document class. As you're experiencing, timeline code causes headaches.
Consider instead just creating both states of your Stage (it sounds like that's what your two buttons are jumping between) and simply hiding them offstage or setting their alpha to zero and their mouseEnabled state to false. Furthermore, if the purpose of your frames is to play animation (a tween), consider instead switching to a much more powerful suite such as TweenLite. Moving an object over a hundred pixels (smoothly) can be as easy as:
TweenLite.to(redBall, 3, {x:100});
Now, if you're manually adding these items to the stage, as long as the object is a dynamic one, you can assign an instance name to it which will be saved between frame loads. Be aware the object name is not the same as the instanced name. For example:
var redBall:Ball = new Ball();
redBall.name = "bubbles";
The object's name is Ball, but it's represented as a variable called redBall. Its actual DisplayList name will likely be ambiguous (such as "Instance71"), and I can manually define it as "bubbles". 3 different names for the same object, all very different and necessary.
Even if you give the object a displayList name, you may not be able to reference it through code unless you enable Automatically declare stage instances, which basically creates on each object a pointer to the displayList object.
That said, you can always fetch the object by other means. Obviously, your buttons are always appearing, but you're trying to find a very specific object on the stage. At this point, we can use getChildByName() or getChildAt().
Hope that helps.
-Cheers
So, I am wanting to clear my whole stage. I already searched through the internet, and unfortunately nothing has worked for my situation.
Basically, what I am doing is a somewhat complex maze generator and before I create a new one, I want to get rid of everything I created prior to that. So far, I hear that the best way to remove movieclips from the stage is buy using:
while(numChildren > 0)
removeChildAt(0);
However this only works for the current movieclip I call it in, which doesn't include the maze I generated. I just want to get rid of absolutely everything.
Any ideas on how to do this?
You're thinking along the right lines, you can use numChildren and removeChildAt however you need to call them in the scope of the stage:
while(stage.numChildren > 0)
{
stage.removeChildAt(0);
}
To just remove it from the stage:
stage.removeChildren();
Just removing clips from stage isn't always equal of removing them from memory
removeChildren, removeChild or removeChildAt does not actually remove an Sprite or any other DisplayObject from memory, it only removes it from the displaylist. That means if you create 1000 sprites and add them to the stage (displaylist), and then use removeChildren they could still exist in memory (forever). Then you have a memory leak.
To remove it from memory, all objects with a relation to the displayObject should be set to null. This includes event listeners and relations from / to non-displaylist related objects.
If you want to be sure all related stuff should be gone, just null it and check these things:
Remove it from the displaylist using removeChild or removeChildAt or removeChildren. (note this can be done from the stage)
Remove all eventListeners that are attached to the clip, or use weak event listeners.
If you used a reference in an Array, Vector, Dictionary or any other object, remove it from the object, set it to null or splice it using Array.splice()
setTimeout/setInterval should be cleared
Set the object = null
You can profile the memory with Mr Doob stats or performance stats from the Temple Library. You should see a drop (garbage collection) after a while when removing all clips. After removing multiple times the memory indicator should not be higher.
There was many discussions about this problem, but I want to pay attention on the situations that IMHO seems not so clear:
Yes the general rules are:
Remove chachedAsBitmap
Stop movieClip if playing
Remove events
Delete references
etc.
But let's look:
First Example:
I have nested sprite (ex: mainSprite), it contains other sprites with dynamic textFields in it (and are chached as bitmaps), just textFileds and MovieClips with event listeners on it (with weak reference).
When I need to remove this sprite I need first to remove all it's nested content via loops or just
removeChild(mainSprite);
mainSprite=null;
is just enough?
Second Example:
I have some sprite in which I'm loading bitmap and manipulating with bitmapData, later I'm just replacing content of this sprite with another bitmap, is allocated memory for older bitmap automatically erases and is overwritten or it still exists?
Third example:
I have some "graphics template" MovieClip (in library with Export for Actionscript property set on it) which I'm adding on the stage and filling with dynamic data (and adding event listeners), let's say that it's one scene of the app, on another scene I need same MovieClip with other dynamic data, but inbetween need to clear my stage (need something like transition animation which is also library MovieClip), what's the best way: to set this MovieClip visible property to false (while transition animation is plays) and then reuse it, or just remove it with removeChild and then add when add with addChild once more?
All I wrote is more about Air Mobile, cause in most cases for the desktop these situations aren't so problematic, but in case of mobile development they are.
You can visually monitor memory usage along with fps etc using this lib: http://code.google.com/p/flash-console/
hope that helps.
P.S. gc in flash is always a weird thing :)
First example: removing mainSprite from display list is enough if there are only weak listeners on its children.
Second example: I'd advice reusing the same object with visible = false. Recreating the same object is more resource expensive plus you get another instance of the same thing being in memory before it gets gc'ed.