Flash CS4, frame head position following the mouse - actionscript-3

I have a small script that moves the frame head backwards and forwards depending on where my mouseX coordinate is inside the main flash movie. Here's my code and it's working so far:
function onEnterFrame(event:Event):void
{
var frame:Number = Math.round(mouseX / (stage.stageWidth / animation.totalFrames));
animation.gotoAndStop(frame);
}
However, when the mouseX cursor leaves the Flash window at x=0, the left edge of the movie, and the mouse reenters the Flash window at stage.stageWidth, the right edge of the movie, the entire movie jumps/jerks to the last framehead.
Now this is sort of what is desired, but I want to soften the effect of moving from ex. frame 0 to frame 30.
So instead of popping to 30, there should be a smooth transition. Can anyone suggest how to manipulate the above function to enable that kind of behaviour!
Thanks in advance!

You could use an easing equation, for example:
var finalFrame:uint=0;
function onEnterFrame(event:Event):void {
var frame:Number = Math.round(mouseX / (stage.stageWidth / animation.totalFrames));
finalFrame+=(frame-finalFrame)*0.2; //simple easing
animation.gotoAndStop(finalFrame);
}
Or you could even use a tweening engine for a smoother transition...

The final solution:
function onEnterFrame(event:Event):void
{
var frame:Number = mouseX / (stage.stageWidth / animation.totalFrames);
var newFrame:Number = animation.currentFrame + ((frame - animation.currentFrame) / 3);
animation.gotoAndStop(Math.round(newFrame));
}
Whew!!!

Related

Flash AS3 | Removing or Stopping a Function

I need the answer to what seems like it should be a very obvious question, yet I can't find it anywhere:
How do you stop a function in Flash AS3? For basic example, when I push a button, the function starts working. When I press the button again, the function stops.
More specifically, how can I tailor this to an if/boolean (or similar) statement so that when/while the variable is true, the function starts working. Once the variable goes false, the function stops. When it goes true again, the process repeats.
The code in issue is this panning function that another user helped create for me.
if(Zoomed == true) {
MovieClip.y = stage.stageHeight / 2;
MovieClip.x = stage.stageWidth / 2;
addEventListener(MouseEvent.MOUSE_MOVE, panFunction);
function panFunction(me: MouseEvent): void {
MovieClip.x = stage.stageWidth / 2 - (stage.mouseX - stage.stageWidth / 2);
MovieClip.y = stage.stageHeight / 2 - (stage.mouseY - stage.stageHeight / 2);
}
}
As you can see, I want it so that when the boolean function 'Zoomed' is true, the function activates and the panning feature works. The problem is that when I go back to Zoomed == false, the function is still running. I am looking to find out how to stop this from happening.
I have tried a 'while' loop but it ultimately just freezes the animation (likely because its a moving image and it's trying to render every frame with this code).
Summarising: I need a way for a function to be able to be toggled on and off. Alternatively, being able to add it and remove it when it's needed/not needed should work the same. Any help on this would be a great help, thanks!
What you need to do is remove the event listener when you no longer want panning.
Something like this, which assumes you change the value of zoomed on a click:
var zoomed:Boolean = false; //a var to store whether we are currently zoomed
//change the zoom on mouse click
addEventListener(MouseEvent.CLICK, zoomClick);
function panFunction(me:MouseEvent): void {
mc.x = stage.stageWidth / 2 - (stage.mouseX - stage.stageWidth / 2);
mc.y = stage.stageHeight / 2 - (stage.mouseY - stage.stageHeight / 2);
}
function zoomClick(me:MouseEvent):void {
zoomed = !zoomed; //toggle the zoomed value
if(zoomed){
//we're zoomed, so add the panning mouse move listener
addEventListener(MouseEvent.MOUSE_MOVE, panFunction);
//do whatever else you need to when first zoomed.
}else{
//no longer zoomed, remove the mouse move listener
removeEventListener(MouseEvent.MOUSE_MOVE, panFunction);
}
}
Some notes, the word MovieClip is not a good instance name, as it may conflict the class name MovieClip, I'd recommend renaming it mc or something else to avoid potential problems later on.
Also, avoid inline functions (functions declared/contained within other functions), they can be especially problematical when attached to event listeners and are a good way to introduce memory leaks into your program.

How to stop an effect from one frame to continue in the next?

I have made a program in which small green rectangles (or Greeny here) are periodically generated at the bottom of the screen and inside the movie clip symbol, I have made a classic tween such that it moves to the top of the screen. I have also declared a variable (t) that increments itself periodically (I am running it at 24 fps). When the value variable, t reaches or exceeds 96, it moves to the next frame. The problem however is that even in the next frame, the generation of these small green rectangles do not stop. Please do excuse me if I have asked the question wrongly. By the way the code on frame 2 is just stop();. Here is the code for frame 1-
var c:int;
var t:int = 0;
var s:int = 8;
function eFrame(event:Event):void
{
t++;
if (t%s == 0)
{
var i:Greeny = new Greeny ;
i.x = Math.random() * 550;
i.y = 400;
stage.addChild(i);
}
if (t > 96) {
nextFrame();
}
}
this.addEventListener(Event.ENTER_FRAME, eFrame);
stop();
EDIT - Here is the link for the file - http://www.mediafire.com/download/crjh2fubcbnx3l5/Retro.fla
you have to remove your your event listener on frame 2. Try this (on frame2 or in frame 1 when your condition t>96 is reached):
this.removeEventListener(Event.ENTER_FRAME, eFrame);
If you want to stop the generation of green rectangles, you should remove the listener of Event.Enter_Frame, or do something to stop it in function eFrame.
If you want to make all rectangles not visible, you should set theirs "visible" attribute false or remove them from stage .

AS3 - How to use pixel/point detection with mouse event instead of object detection

This seems like it should be so easy that I'm embarrassed to ask, but I just can't get it.
I have a large round MovieClip (being used as a button). This MovieClip contains a PNG with a transparent background inserted into the MovieClip.
Due to its size there are large empty registration areas on the 4 corners (the bounding box).
How can I have the mouse register as being over only the circle pixels and not the blank space (of Alpha channel pixels) in the square boundary box?
Simple sample code:
public function simpleSample () : void
{
mc1.buttonMode = true;
mc1.addEventListener(MouseEvent.CLICK, doStuff);
}
public function doStuff (event:MouseEvent) : void
{
mc2.gotoAndStop(2);
}
Here are 3 different ways to accomplish this.
EDIT Since you've later explained that your button is an image, this first option won't work for you
If the shape flag on hitTestPoint works with your button (eg it's a shape), you can use hitTestPoint inside your mouse click handler to figure out if the click is actually over the object:
public function doStuff(event:MouseEvent){
//only continue if hit test point is true,
//the x and y values are global (not relative to the mc your testing as one might suppose)
//the third parameter should be true, so it takes into account the shape of object and not just it's bounds
if(mc1.hitTestPoint(stage.mouseX, stage.mouseY, true)){
mc2.gotoAndStop(2);
}
}
If the above doesn't work because you have bimtap data in your button, then an easy way to accomplish this is to just add a shape mask to the button.
So, either inside your button using FlasPro, mask everything with a circle shape, or, do it via code by doing the following when you first show the button:
var s:Shape = new Shape();
s.graphics.beginFill(0);
s.graphics.drawCircle(mc1.x + (mc1.width * .5), mc1.y + (mc1.height * .5), mc1.width / 2);
addChild(s);
mc1.mask = s;
If using an image as the button, or you want to set a threshold of how transparent to consider a click, then you can check the transparency of the pixel under the mouse:
function doStuff(event:MouseEvent){
//only continue if pixel under the mosue is NOT transparent
//first, you need a bitmap to work with
//if you know for sure the position of your bitmap, you can do something like this:
var bm:Bitmap = mc1.getChildAt(0) as Bitmap;
//annoyingly though, FlashPro makes timeline bitmaps shapes,
//so the above won't work UNLESS you take your bitmap in the FlashPro Library
//and export it for actionscript, giving it a class name, then it will be an actual bitmap on the timeline.
//As an alternative, you could (very CPU expensively) draw the whole button as a bitmap
var bmd:BitmapData = new BitmapData(mc1.width,mc1.height,true,0x00000000);
bmd.draw(mc1);
var bm:Bitmap = new Bitmap(bmd);
//we get the 32bit pixel under the mouse point
var pixel:uint = bm.bitmapData.getPixel32(bm.x + event.localX,bm.y + event.localY);
//then we grab just the Alpha part of that pixel ( >> 24 & 0xFF ).
//if the value is 0, it's totally transparent, if it's 255, it's totally opaque.
//for this example, let's say anything greater than 0 is considered good to be a click
if((pixel >> 24 & 0xFF) > 0){
mc2.gotoAndStop(2);
}
}

How to make Movie clip stretch and contract to follow another Movie clip on stage

Hey everyone so I am working on a fishing pole and I created a hook in AS3 that the user controls when they touch the screen the playerHook is allowed to move anywhere on the screen in any direction that the user directs it to.
So what i want is for the hookLine to be attached to the hook and follow it everywhere also the hookLine to be attached to the fishing pole as well, but i want the hook line to of course act like one, in the way that when the user moves the Hook to the end of the screen then the hook line stretches with it and when it is moved back, the hook line contracts. Hope you understand what I'm trying to convey. Just basically how a fishing pole acts.
Here is the code that I am using for the user to control the playerHook :
In my Main Function:
//Add hook to stage
playerHook = new mcHook;
stage.addChild(playerHook);
playerHook.x = (stage.stageWidth / 2);
playerHook.y = (stage.stageWidth / 2);
//Event listeners
playerHook.addEventListener(Event.ENTER_FRAME, playerHookMove);
In my playerHookMove function:
private function playerHookMove(e:Event):void
{
var xCoord = playerHook.x - mouseX;
var yCoord = playerHook.y - mouseY;
playerHook.x = playerHook.x - (xCoord / 3.5);
playerHook.y = playerHook.y - (yCoord / 3.5);
}
If anyone has any idea on how to have the hookLine object do what I stated above i would really appreciate it. I have ideas such as scaling and transforming. But not too sure. Please help!

Particle Animation as3 Layering

I have battled through several tutorials to come up with the perfect particle snow effect. The only thing I need to do now is duplicate the particle effect and have a second version of it play between my background and foreground. The original I still want to keep as the top most layer. I tried wrapping the code in a function and making two of them with different names, but I got a bunch of weird errors. So instead of ruining what I already have I came here to ask for any advice on the situation. Here is my code. I am using the Greensock animation library to handle my timeline and animation.
import com.greensock.*;
import com.greensock.easing.*;
addChildAt(MC_BG, 0)
addChildAt(MC_FG, 2)
var tl:TimelineMax=new TimelineMax({paused:false});
function createFlake(offset) {
//create a flake (attach symbol in library with Class flake) and position on stage
var flake:Flake = new Flake();
flake.y=-50;
flake.x=randomRange(-10,1090);
flake.alpha=0;
addChild(flake);
//create timeline for each flake
var nestedTl:TimelineMax = new TimelineMax();
//how much wiggling / zig zagging
var wiggle:Number=randomRange(15,35);
//zig or zag?
wiggle=Math.random() > .5?- wiggle:wiggle;
//how fast and big
var speed:Number=randomRange(5,15);
//fade and grow
nestedTl.insert(TweenMax.to(flake, .5, {alpha:randomRange(.5,1), scaleX:speed, scaleY:speed}));
//go down
nestedTl.insert(TweenMax.to(flake,speed, {y:800}));
//zig zag
nestedTl.insert(TweenMax.to(flake, speed*.15, {x:String(wiggle), repeat:Math.floor(randomRange(1,4)), yoyo:true, ease:Sine.easeInOut}));
tl.insert(nestedTl, offset);
}
//generate random num between a min and max value
function randomRange(min:Number, max:Number):Number {
return min + (Math.random() * (max - min));
}
function init() {
//create a bunch of flakes and add them to timeline
for (var count:Number = 0; count<10000; count++) {
var offset = count * 0.075;
createFlake(offset);
}
}
init();
Any help would be greatly appreciated.
The answer was so simple I completely overlooked it. I made 3 blank Movie Clips, and in each of them I put a slightly modified version of this code. Then I put each movie clip on a layer in between what I wanted, and Bob's your uncle, it worked.