If you need to perform an animation and have it be standard when viewed across different machines, it is best to use an onEnterFrame event. I had a need in a project recently to draw a circle in a specified amount of time. I had been using the Timer class but found major time discrepancies between running the code locally and running the code in a browser. With some code that Jackson Dunstan provided, I was able to modify the animation so that you can start/stop drawing the circle based on user input. (In the sample provided it is by clicking the stage) I hope this helps someone in a similar situation. Code after the jump…
Draw a circle with as3 that will finish in a specific time. (9.6 KiB, 34 hits)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | package { import flash.display.*; import flash.events.*; import flash.utils.*; [SWF(backgroundColor=0xEEEADB,frameRate=30)] /** * Draws a circle using AS3 and you can start/stop the animation by clicking the stage * @author Jackson Dunstan w/ mods by jguthrie */ public class CircleDrawTest extends Sprite { /** Current angle on the circle we're drawing from */ private var __angle:Number; /** Center of the circle in the X */ private var __centerX:Number; /** Center of the circle in the Y */ private var __centerY:Number; /** Radius of the circle */ private var __radius:Number; /** Number of radians of the circle to draw per second */ private var __radiansPerSecond:Number; /** Time circle drawing will finish */ private var __endTime:int; /** Last time we entered a frame */ private var __lastFrameTime:uint; /** Our circle*/ private var __circle:Shape = new Shape(); /** Parameter used in stageClick to know if we are paused or not */ private var __paused:Boolean = false; /** Double this time is how long it will take for the circle to be drawn */ private var __rotationTime:int = 4; /** Parameter that is used to know when to reset the __timeSpentPaused variable after a pause */ private var __iWasPaused:Boolean = false; /** Variable that is used to add onto __endTime when you pause the animation */ private var __timeSpentPaused:int; /** */ private var __beforeTime = int; /** * Application entry point */ public function CircleDrawTest() { stage.addEventListener(MouseEvent.CLICK, stageClick); stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; stage.quality = StageQuality.BEST; addChild(__circle); var mask_sh:Shape = new Shape(); mask_sh.graphics.beginFill(0xCCCCCC); mask_sh.graphics.drawCircle(0, 0, 31); //make the mask just a bit larger than the circle mask_sh.graphics.endFill(); mask_sh.x = stage.stageWidth/2; mask_sh.y = stage.stageHeight/2; addChild(mask_sh); __circle.mask = mask_sh; __angle = 270*(Math.PI/180); __centerX = stage.stageWidth/2; __centerY = stage.stageHeight/2; __radius = 29; __radiansPerSecond = Math.PI / __rotationTime; initCircle(); } private function stageClick(e:Event):void { if (__paused == true) { __timeSpentPaused = getTimer() - __timeSpentPaused; __endTime = __endTime + __timeSpentPaused; __lastFrameTime = getTimer(); __iWasPaused = false; __paused = false; addEventListener(Event.ENTER_FRAME, onEnterFrameDraw); } else { removeEventListener(Event.ENTER_FRAME, onEnterFrameDraw); __timeSpentPaused = getTimer(); __iWasPaused = true; __paused = true; }; } private function initCircle():void { __beforeTime = getTimer(); __angle = 270*(Math.PI/180); __endTime = getTimer() + (2000*Math.PI) / __radiansPerSecond; __circle.graphics.clear(); __circle.graphics.lineStyle(6, 0xFF6600,1,false,LineScaleMode.NORMAL,CapsStyle.NONE); __circle.graphics.moveTo( __centerX + Math.cos(__angle)*__radius, __centerY + Math.sin(__angle)*__radius ); addEventListener(Event.ENTER_FRAME, onEnterFrameDraw); __lastFrameTime = getTimer(); } /** * Callback for when a frame is entered * @param ev ENTER_FRAME event */ private function onEnterFrameDraw(ev:Event): void { var now:int = getTimer(); var dTime:int = now - __lastFrameTime; if (!__iWasPaused) { __lastFrameTime = now; } var radiansMoved:Number = dTime * 0.001 * __radiansPerSecond; var endAngle:Number = __angle + radiansMoved; var halfAngle:Number = __angle + radiansMoved*0.5; __angle = endAngle; __circle.graphics.curveTo( __centerX + Math.cos(endAngle)*__radius, __centerY + Math.sin(endAngle)*__radius, __centerX + Math.cos(halfAngle)*__radius, __centerY + Math.sin(halfAngle)*__radius ); if (now > __endTime) { removeEventListener(Event.ENTER_FRAME, onEnterFrameDraw); //trace('Total time elapsed : ' + (getTimer() - (__beforeTime + __timeSpentPaused))); //Not accurate if paused initCircle(); } } } } |
#1 by Jackson Dunstan on November 4, 2009 - 10:51 pm
Thanks for giving me credit. It’s good to see where you’ve taken it and even better to see it posted for everyone’s benefit. Congrats on getting it to work!