Use AS3 to turn on/off a graphic's visibility - actionscript-3

I found other threads/questions that were similar but didn't quite provide the answer I need.
This should be incredibly simple, but I'm not very versed in AS3 yet so I'm stuck.
I have a movie clip on the stage whose alpha is set at 0. I want to make it so that when I press a certain key on my keyboard the alpha for that movie clip is set to 1 (100%). I already have several other keys coded in AS3 to do other actions (jump to certain frames in the timeline, move certain objects up, down, left and right, etc). So I added this code:
if (e.keyCode == 77){
graphic_object.alpha == 1;
}
"graphic_object" is the instance name for the movie clip I want to show.
However, when I press the "M" key (77), nothing shows up. The movie clip apparently remains at 0.
So what's the incredibly simple resolution to this that I'm overlooking?
Thanks.

== => comparison
= => setter
graphics_object.alpha = 1;

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.

AS3 key presses cause animation error

I'm making a game and basically I'm having some errors with the animation state.
public function movementChar()
{
if (touchingGround)
{
if (rightKey)
{
gotoAndStop("run");
scaleX = 1;
}
if (leftKey)
{
gotoAndStop("run");
scaleX = -1;
}
if (upKey)
{
gotoAndStop("jump");
this.y -= 15;
//touchingGround = false;
}
if (attackKey)
{
gotoAndStop("attack");
}
if (!rightKey && !leftKey && !upKey && !attackKey)
{
gotoAndStop("stop");
}
}
}
I have some other coding which says if the player is touching the ground then touchingGround = true;
and if it is true then the player can move right, left, jump and attack.
The problem is that when I press the attack key, it keeps on looping the animation and attacking.
I want the attack key to play the animation once and make the boolean hasAttacked = true; once.
Another problem is that when the player is moving and the attack key has been pressed/ hold down the animation freezes. Flash gets confused on which animation to play so it stops at frame 1 and glitches.
I would appreciate it if someone can give me an idea on how to fix this.
Thank you.
Ok I have a few recommendations. First let's address the fact that your attack animation is looping. You will need to go into the SirTimmyAttack movieclip timeline and add
stop();
In to frame 4 to keep the animation from looping forever. After you do that the animation will play once. You have a timer that you are starting when you tell him to attack, after the timer execute he will attack again. So if you hold the "A" key he will ATTACK...Wait for timer...ATTACK...Wait for timer....ATT ect. if you want him only to attack once per press of the "A" key remove that timer and never start it.
On to address your second concern about the player being unable to attack and walk at the same time. That is a technical limitation of the way you are currently animating. Since the players entire animation is contained inside a set of frames you cant mix and match to combine them. I would suggest breaking your player graphics/animations into to halves. An Upper body, and a lower body. That way you can trigger walking/running/standing animations independently from the upperbody/attack animations.
Hope this helps, let me know if you have any other questions.
I don't have my flash dev stuffs on my current machine so I can't open the fla but:
I suspect that this is caused by not 'consuming' the key event. i.e. presumably you are setting rightKey, leftKey, attackKey etc on key up and key down events and checking the state during the update function?
The problem with this is that each update it will act as if pressing the key the first time, every time, you need some method of knowing that the key press has been handled.
As I say I can't check your fla so I can't comment on the best method but I suspect you may have to substantially change your input handling.

How to handle mouseEvent transparently in AS3?

I have a DisplayObject docked at the top of my interface that displays debug information (frames per second, etc.) and is translucent with an alpha of 60%.
I would like to interact with items under this surface, such that when the mouse rolls over it, it dims to 10% alpha, and mouse events pass through it to the underlying objects.
Normally, I have this debug info panel's mouseEnabled and mouseChildren properties set to false, so objects under it receive mouse events.
The problem is that in order to hide it when the mouse rolls over it, it needs to have mouseEnabled set to true. However, if mouseEnabled is true, the mouse events are not picked up by objects underneath it.
As far as I know, I can't selectively enable mouseEvents, so it's either going to receive them all or none of them. That means that I'd have to handle and forward ALL events, if I took that approach.
I really wish the mouseEnabled property had a "peek" mode or something, so that it could receive the events if it is on top, but also allow them to pass through to objects underneath.
If a DisplayObject has mouseEnabled=true it means that its events will be sent to its container not to whateve is underneath the object. So this solution will not work. The best solution would be to reroute events from it manually using getObjectsUnderPoint as described here.
I've been using this approach for years in multi-touch apps. With multiple touch points I don't see any processor overhead. And you got only one cursor.
I feel your pain. Unfortunately, I don't know of a way to enable/disable specific mouse events. You could get creative with the solution though. For instance, maybe try adding a MOUSE_MOVE listener to your stage and track the coordinates of the mouse. Then, if the stageX,stageY of the mouse is in the area of your panel, set the visibility. You might also be able to use getObjectsUnderPoint() to determine which objects are under the mouse. But, my guess is that it would get a little intense on the processor to run that on each frame iteration.
I believe you are looking for mouseEnabled = false
But another last ditch attempt you can do is on mouse over move it to the other side of the screen.
One approach you can take, although not ideal, is to add an enter frame listener and check the mouse position every frame. something along the lines of:
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
private function onEnterFrame(e:Event):void {
if(mouseX > width || mouseY > height){
//hide stats
}
}
I'm assuming you have this display hierarchy:
Debug Window
Debug Control 1
Debug Control 2
...
Overlay
Why not make the overlay a mask on DebugWindow and have your mouseEvents attached to DebugWindow itself? See this page for some inspiration: http://blog.shaperstudio.com/2010/11/as3-inverse-mask/
I had this same problem.. i made function to check is mouse over certain object:
public function isMouseOverObject(mPos: Point, pObject:DisplayObject, pContainer:DisplayObjectContainer) {
var under_objects:Array = pContainer.getObjectsUnderPoint(mPos);
var is_under:Boolean = false;
for (var i:int = 0; i < under_objects.length; i++) {
if (under_objects[i] == pObject) {
is_under = true;
break;
}
}
return is_under;
}

EventDispatcher between an as and an fla?

I am making a fighting game in Flash and while I have everything running, I am missing something: a victory/loss screen. Logically, I know how to do it:
if character.hp < 0
{
character.dead = true;
dispatchevent("death", event)
}
My problem is that I have no idea as to how to code it. I know I will use two classes and my two .fla files (unless I am wrong).
I have two .fla files that are in play here: the Menu.fla file and the Arena.fla file. Menu.fla contains the entire navigation of the game, options, character selection screens, etc. and when it is time for the player to engage in battle, it loads the Arena.fla file, which contains only the backgrounds (depending on the selected stage) and for now is set to a length of one frame only. For Arena.fla, the real action happens in my classes, but logically, I would only need HP.as and Character.as.
In Character.as, I have declared the following variable:
var isDead:Boolean = false; //is character dead?
In HP.as, believe I should have the following:
if(currentHp<0)
{
currentHp = 0;
character.isDead = true; //declared as var `character:Object;`
EventDispatcher.dispatchEventListener("playerDead", playerDead);
}
And finally, in Arena.fla, I want to be able to detect the above-mentioned eventlistener and simply move on to a second frame which will display a message in the style of "PLAYER ONE HAS WON" or "PLAYER ONE HAS LOST" with a button that will allow me to go back to the character selection screen. This is the first part in which I am stuck: how do I detect the dispatched event listener in my main .fla file?
Secondly, if the player clicks on the "CONTINUE" button, which displays regardless if the player has won or lost, how can my Menu.fla (which loads the Arena.swf) detect this click event, unload the game, and go back to the character selection screen?
Thank you in advance for helping me out. I realize this is a lot of text but it's the most descriptive I can be. If you have any questions or need any clarification concerning my question, feel free to speak up.
-Christopher
I'm not sure about the code you have to read the HP but do you know that character.dead is actually becoming true?
You could always have the Arena.swf call a function in the HP.as that will end the game and declare a winner.You could add a second Frame to Arena.swf that contains a dimmed background and a WINNER or LOSER text.'
In general, the easiest way for a user-defined class to gain event dispatching capabilities is to extend EventDispatcher. If this is impossible (that is, if the class is already extending another class), you can instead implement the IEventDispatcher interface, create an EventDispatcher member, and write simple hooks to route calls into the aggregated EventDispatcher.
activate
Dispatched when Flash Player or an AIR application gains operating system focus and becomes active.
deactivate
Dispatched when Flash Player or an AIR application loses operating system focus and is becoming inactive.
Event dispatcher
Thank you all for your help, but I have figured it out. Turns out my method was far too complicated for what I wanted to do, and for the time I had left. I will explain how I did it.
Instead of using an EventDispatcher like I thought I would, I used a SharedObject, which simply made everything work like magic.
A SharedObject can be accessed from anywhere in the application/game, as long as it is referred to it correctly. So I simply created a SharedObject called "winLossData" set to "NO WINNERS" in my character selection screen. This cookie is never saved nor written to the disk, so there's no chance for the user to find it (generally speaking).
I have decided to use the Movement.as class which contains all of my controls and wrote an event listener of type Event.ENTER_FRAME that checks constantly my characters' health status. If one of them is below 100, my SharedObject immediately takes for value either "PLAYER ONE" or "PLAYER TWO", depending on who won (i.e. whose health points are not under 100). Afterward, just for precaution, I reset the losing character's health points to 100. Here's the code:
function whoWon(event:Event):void
{
if(playerSpriteBar.getPower() <= 0)
{
winner.data.winner = "Player Two";
playerSpriteBar.update(100);
}
if(playerAIBar.getPower() <= 0)
{
winner.data.winner = "Player One";
playerAIBar.update(100);
}
}
In my Menu.fla, I have another event listener of type Event.ENTER_FRAME that waits for the cookie to change value. As soon as the cookie changes values, Menu.fla automatically unloads the external swf (in our case, Arena.swf) and displays the results, accordingly to the received SharedObject. The rest of the actions happen inside the Menu.fla file, so no need for any extra coding.
Once again, thank you all for your help.

How to click through a display object in Flash with AS3?

I am creating a photo editor app where, at some point, the photo you edit is supposed to be dropped between two layers of DisplayObjects (a background image and an image mask.)
There is a problem, though. When the image you are editing is dropped between the background and the image mask layers, it becomes unclickable, and therefore gets stuck there, with no chance of dragging it again. (The photo editor uses TransformManager library.)
I am looking for a way to allow you to select the image you are editing no matter if there is another DisplayObject on top of it. And that probably means finding some way to click through the image mask.
Is there a way to do that?
I tried setting mouseChildren = false on imageMask, but that didn't have the desired effect.
Many thanks.
I had similar problems and I managed to solve it by using both
displayobject.mouseChildren = false;
and
displayobject.mouseEnabled = false;
on the object that you want to click through.
How about this?
mask.mouseEnabled = false;
You can always attach a Mouse Click listener to the container, and then either use GetObjectsUnderPoint and check for your object or do a hit test and see if the mouse position is over your intended object.
The hit test would look something like this !this.YourPhoto.hitTestPoint(stage.mouseX, stage.mouseY, false)
b
If I understand your problem, this handy class should solve it:
http://www.mosessupposes.com/utilities/InteractivePNG.html
Take a look at what senocular does here, specifically in the handleUpdate method. Basically: getting a list of everything under the mousePoint to find your object.
I think I stumbled upon similar problem, although in as2.
In flash when you position movie clip over movie clip, and the movie clip on the top has any mouse events implemented, it captures all mouse events so they never reach occluded movie clip.
The solution is not to have any mouse events for the top movie clip and have the movie clip positioned at the bottom capture mouse event and redirect some of them to the top movie clip (you can check mouse position with hitTest to determine if they should be redirected).
i had a strange bug i used;
movieClip.mouseEnabled = false;
but wasn't working for some reason.. was driving me crazy!! as i have used it so many times before. tried lots of different things nothing worked then i deleted the MovieClip and the created a new one and worked.. so the MovieClip's contents must have been corrupt or something as it had a old dynamic Text Area box embedded within the MovieClip.
hope this helps someone out there..