AS3 – Draw Circle Animation Based on Time


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();
			}
		}
	}
}
Spread the Good Word:
  • Digg
  • del.icio.us
  • Facebook
  • NewsVine
  • StumbleUpon

, , ,

  1. #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!

(will not be published)

Switch to our mobile site