Simulating a MovieClip in pure as3 - actionscript-3

I am looking for a way to make a Flash movie clip (animation, like the ones created with Flash Pro CS), but purely in as3 - so I can import them into Prezi.
I have done a lot of as3 programming in Flash Builder with Flex projects and I have no background in how MovieClips work.
What I have already tried is extending a MovieClip class and trying to base the animation on Timers, this failed so I tried with ENTER_FRAME event (because flash animations are based on frames - so I thought...). But all this fails, only graphics drawn in the constructor are displayed - no animation happens. (As I wrote in the first paragraph I am testing this importing the swf into Prezi, opening it in a browser works as expected)
Is there any way to do it? Like listening to specific events?

Give sprite sheet a try. It's the best solution for animation in AS3, and also pretty simple to implement. for changing drawing, there are Timer and ENTER_FRAME event to do this.

Funny thing happened. I wanted to show you a sample code I was trying out (I already tried Sprite with ENTER_FRAME), that was not working. By accident I found a solution. It looks like you need to draw something in the first frame, or else the other frames won't work (in Prezi at least).
So here is the working code:
public class PreziTest extends Sprite{
private var radius:uint = 10;
public function PreziTest(){
addEventListener(Event.ENTER_FRAME, onEnterFrame);
onEnterFrame(null); // WITHOUT THIS IT WON'T WORK - YOU NEED TO DRAW SOMTHING IN THE FIRST FRAME
}
private function onEnterFrame(event:Event):void{
radius += 10;
if(radius > 200)
radius = 10;
graphics.clear();
graphics.beginFill(0xff0000);
graphics.drawCircle(radius, radius, radius);
}
}
Thanks for all your help!

Related

Flash AS3 Scripted eyes do not tween with other layer animation

thanks for reading.
I have a small animation in Flash that is scripted to enable the eyes to follow the mouse. This further animates upwards on mouse click, but the eyes that are scripted do not follow the tween.
I have childed/ embedded the eyes objects inside the main animating layer but this also seems to NOT follow.
I'm a bit confused and expect I have missed some fundamental structural/ layering issue -but I'm at a bit of a loss and am concerned if it is not me, then is it a bug or something in Flash and scripted layers working together or something:(
Anyway, I enclose the actual .fla and the .swf in vain of any help that you wonderful dudes can pass down to me.
https://drive.google.com/open?id=0B4yGmvZlwZmWanJJX1IzTk5pYXM
I would really love to know why and what if there is something I have fundamentally missed here. (I haven't checked for AS3 in the Symbol conversion Advanced options dialogue for the eye instance, but this has not effected the interactive eye part and I suspect it shouldn't be the cause of the conflict as a result - happy to be wrong here though of course :))
Edit: Here is the code for the project {which started out as a youtube tut showing how to control a circular movement of some eye objects with the mouseMove event }
//this is an action script window
//we can code into here :)
this.stop();
this.loop = false;
stage.addEventListener(MouseEvent.MOUSE_MOVE, MoveEyes);
stage.addEventListener(MouseEvent.MOUSE_DOWN, PlayTimeline);
function MoveEyes(e:MouseEvent): void
{
var mouseYPosition = mouseY - EyeR.y;
var mouseXPosition = mouseX - EyeR.x;
var radiusR = Math.atan2(mouseYPosition, mouseXPosition);
var degreesR = radiusR / (Math.PI / 180);
EyeR.rotation = degreesR;
mouseYPosition = mouseY - EyeL.y;
mouseXPosition = mouseX - EyeL.x;
var radiusL = Math.atan2(mouseYPosition, mouseXPosition);
var degreesL = radiusL / (Math.PI / 180);
EyeL.rotation = degreesL;
}
//when clicked start the animation
function PlayTimeline(e: MouseEvent) : void
{
this.play();
}
...In fairness, and I am totally happy to be wrong of course but, I don't think the code is causing or has anything to do with the fault, it may be more my stage layer positions or something along those lines, hence the full .fla file for someone better than me to point out my mistake.
Cheers all and thanks again for reading and taking the time here.
:)
Gruffy
That's actually a very interesting bug. I believe what's happening is that by interacting with the Eyes' properties, you're removing it from the timeline tween.
Your best bet would be to simply remake the timeline tween in code like so:
function PlayTimeline(e: MouseEvent) : void
{
this.play();
new Tween(EyeL, "y", fl.transitions.easing.None.easeInOut, EyeL.y, 141.95, 100);
new Tween(EyeR, "y", fl.transitions.easing.None.easeInOut, EyeR.y, 141.95, 100);
}
This gives the affect you need. However if you start messing with the timeline animation you will need to change the tween, so perhaps it would be best to move all the tweening code side?
EDIT: I notice that the eyes don't animate whilst the bird is moving unless you continue to move the mouse. The solution for this would be to change the mouseEvent listener to an enterframe listener so that it will happen every frame regardless of whether the mouse is moving or not. That's not the best solution, as it's a bit overkill, but to do anything else would likely involve some timers or third part libraries, which I don't think are strictly necessary at this point

How drag a Sprite smoothly on-screen in actionscript

First of all, my question is basically the same as this one:
How to drag an image to move it smoothly on screen, with ActionScript?
I want my dragged Sprites to keep up with the mouse on-screen, smoothly, without lagging behind.
And I notice that in the old ActionScript 3 Cookbook from way-back-when that they used a similar solution for their DraggableSprite as was used in the above link. Namely, use the stage instance to listen for the MouseMove event and then read from the event.stageX and stageY properties.
I've done that.
But my Sprite still doesn't stay locked with the mouse cursor. It lags behind. I feel like I must be missing something. However, if the solution posted above (ie listen for stage's MouseMove and use event.stageX/Y) is still current and the problem I'm describing should not be occurring, please also let me know. Even though it's not supposed to work, I've tried event.updateAfterEvent() and it also doesn't seem to have any positive effect.
Any help or advice would be greatly appreciated.
Here's a simple example of how I've written the handlers. It should work as-is if pasted into a new project.
I should also add that I'm compiling this as a desktop application using Adobe AIR. Would the run time be a factor???
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
[SWF(width="1280", height="720", frameRate="30")]
public class test_drag extends Sprite {
private var testDragSprite:TestDragSprite;
public function test_drag() {
super();
graphics.clear();
graphics.beginFill(0x0000FF);
graphics.drawRect(0, 0, 1280, 720);
graphics.endFill();
testDragSprite = new TestDragSprite();
addChild(testDragSprite);
testDragSprite.addEventListener(MouseEvent.MOUSE_DOWN, testDragSprite_mouseHandler);
testDragSprite.addEventListener(MouseEvent.MOUSE_UP, testDragSprite_mouseHandler);
}
private function testDragSprite_mouseHandler(e:MouseEvent):void {
switch (e.type) {
case MouseEvent.MOUSE_DOWN: {
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
break;
}
case MouseEvent.MOUSE_UP: {
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
break;
}
}
}
private function mouseMoveHandler(e:MouseEvent):void {
//-20 to keep the sprite centered on the mouse
testDragSprite.x = e.stageX - 20;
testDragSprite.y = e.stageY - 20;
//e.updateAfterEvent(); //strange effect, but doesn't solve the problem.
}
}
}
import flash.display.Sprite;
internal class TestDragSprite extends Sprite {
public function TestDragSprite() {
super();
graphics.lineStyle(1, 0xDDDDDD);
graphics.beginFill(0xFF0000);
graphics.drawRoundRect(0, 0, 40, 40, 12);
graphics.endFill();
}
}
There is always going to be a little lag, but:
The first two suggestions will make the most noticeable change to your code/performance.
Enable hardware graphics acceleration; edit your AIR application
descriptor file (xml) and set renderMode to Direct (or GPU). Consult
the Adobe Air help for details.
<!-- The render mode for the app (either auto, cpu, gpu, or direct). Optional. Default auto -->
<renderMode>direct</renderMode>
Use startDrag and endDrag to bypass your manual assignments in your mouseMoveHandler.
Replace :
testDragSprite.addEventListener(MouseEvent.MOUSE_DOWN, testDragSprite_mouseHandler);
testDragSprite.addEventListener(MouseEvent.MOUSE_UP, testDragSprite_mouseHandler);
With :
testDragSprite.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
testDragSprite.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
Add the new handlers:
private function mouseDown(e:MouseEvent):void {
testDragSprite.startDrag();
}
private function mouseUp(e:MouseEvent):void {
testDragSprite.stopDrag();
}
Increase your frame rate, but watch your CPU usage as your application/game becomes more complicated as you may need to lower it to allow your game logic enough time to complete between frames (otherwise you end up with what is called long frames, you can use the free Adobe Scout profiling tool to watch for these and lots of other things).
Add a frame rate HUD to your display so you can monitor when your actual framerate is lower than the requested framerate (this is for debugging)
If your game is 2d based, consider using the open-source Starling framework as all content is rendered directly by the GPU vs Flash's standard display list objects.
Just try the member function startDrag.
The Feathers UI library includes a drag-and-drop module. The answers above all use the 'old' display list which is not mobile-ready. If you want your code to work cross-platform you need a GPU framework (most popular is Starling on which Feathers is based, as well as most Adobe AIR games and Apps).

Bitmapdata.draw(MovieClip) Gives Blank BitmapData

I'm predrawing all vector element in my game to bitmaps to improve performance - the vector elements are exported as swf files from Illustrator (I suspect that is part of the problem).
When embedding the swf file in as3 like so:
[Embed(source = 'file.swf')] private static const image:Class;
And then adding it to the stage, like so
stage.addChild(new image);
Everything is fine, but if instead I draw it to a bitmap data like so...
genericBitmapData.draw(new image);
It's a blank bitmapdata. I've tried using gotoAndStop on frames 0 and 1 before drawing with no avail. Does anyone have experience with the swf files that Illustrator exports and any insight as to how I can get these drawing as expected?
Here is a link to a really simple .swf that produces the same results
Here's my revised solution:
//create movieclip
var mc:MovieClip = new image();
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
//this gets called on next frame
function enterFrameHandler(event:Event):void
{
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
genericBitmapData.draw(mc);
}
So it turns out that the object needs to be instantiated before I can use it to draw, and the easiest way to detect when that is is to listen for the ENTER_FRAME event:
(new image).addEventListener(Event.ENTER_FRAME, functionToDrawImage);
And when that function is called, it will be ready to draw to a bitmapdata, and then all is right with the world.

Smooth scrolling on Flash AS3

Is it possible to do completely smooth scrolling in Flash (ActionScript 3)? In the following test I am creating a bitmap consisting of random noise, then moving it to the left periodically. I have no heavy tasks running in the background. What I am looking for is smoothness that would be on par with my Amiga 500 from 1987 :-)
package {
import flash.display.*;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Game extends Sprite {
var noiseBitmap;
public function Game() {
var noiseBitmapData = new BitmapData(stage.stageWidth * 3, stage.stageHeight);
noiseBitmapData.noise(0, 0, 255, 7, true);
noiseBitmap = new Bitmap(noiseBitmapData);
addChild(noiseBitmap);
var t = new Timer(1000/30, 999999);
t.addEventListener("timer", function (e:TimerEvent) {
noiseBitmap.x--;
});
t.start();
}
}
}
The "rendering code" takes <1 millisecond to run on my computer (2.4 GHz Mac), but still the movement will occasionally get stuck for a frame or two, making the movement appear jerky.
FPS is set to 30 in Flash. I have tried running it both using "test movie" and in the browser (Chrome). Target is Flash Player 11.2. I have also tried calling e.updateAfterEvent() to force a redraw. I have Also played around setting the delay and FPS to slightly different values, but no improvement.
This is different from not smooth scrolling in AS3 because I am already using a BitmapData. Also I have tried using the ENTER_FRAME event instead of a timer as suggested in a reply to that question, but it did not help.
When using a timer, you will not be exactly synced with the frame rate. As you mention, the frame rate fluctuates a little making your timer sometimes fire twice during one frame or skipping a frame. To be sure to be more in sync with the frame rate, you should listen to the Event.ENTER_FRAME event.
An example:
this.addEventListener(Event.ENTER_FRAME, updateFrame);
⋮
function updateFrame(e:Event):void {
noiseBitmap.x--;
}
I suggest you try out Greensock's TweenLite. It is a highly optimized engine to do all sorts of tweening through code and is available for AS2 and AS3. You can find it here.
Walkietokyo's solution is still frame based and would not eliminate the issues you run into. Instead use time-based animation (which TweenLite actually implements). For more info refer to this article.

AS3...instantiating movieclips from library and also creating them dynamically...is stop() needed?

In the past, we've put a stop() action in the timeline of movieclip symbols so that the timeline would not play and we would control all animations via code.
We've also done that to the main timeline as well.
Is this still needed for performance reasons? Is this needed for dynamically created movieclips?
I know that the Sprite class should be used if there is no timeline associated with it.
You don't need to do this. When you create your instance, if your movieClip has more than one frame simply call stop on that instance:
var ball:MovieClip = new Ball();
ball.stop();
addChild(ball);