Recently I encountered one of those timed programming-tests they occasionally do as part of an interview-process. Even though my solution was deemed a success, I personally felt somewhat dissatisfied with my approach to the presented problem.
Sure, the time available was severely limited, but I couldn’t help but feel frustrated by the under-the-hood clunkiness of the end-result, so I decided to redo it the “proper” way for the sake of my inner tranquility, and for the benefit of all mankind. ![]()
Lo and behold this starfield-effect:
Unlike the original submitted for the above-mentioned test, this one I actually consider to be a pretty solid version.
Even though the framerate of this SWF is capped at 30fps and the number of stars limited to 1000 for the sake of usability, on my (not particularly cutting-edge) system it still runs at a glossy 60fps with 1500 stars.
I even added little performance-leeching extra features, like the cool “redshift” trail-effect, or the elliptical movement of the stars’ point of origin.
And now onto the code. One noteworthy detail is the heavy-duty use of Flash10′s new Vector class – essentially a fast, typed array – which contributes to the nice performance-results:
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 154 | // Hyperspace starfield (C) edvardtoth.com package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.display.MovieClip; import flash.display.StageScaleMode; import flash.display.StageAlign; import flash.display.StageQuality; import flash.display.PixelSnapping; import flash.filters.BlurFilter; import flash.filters.ColorMatrixFilter; import flash.geom.ColorTransform; import flash.geom.Matrix; import flash.geom.Point; import flash.geom.Rectangle; import flash.events.Event; public class Hyperspace extends MovieClip { private var starNum:int; private var starSpeed:Number; private var displayWidth:Number; private var displayHeight:Number; private var halfDisplayWidth:Number; private var halfDisplayHeight:Number; private var circleWidth:Number; private var circleHeight:Number; private var circleAngle:Number; private var circlePoint:Point; private var currentStar:Star; private var starField:Vector.<Star>; private var starHolder:Sprite; private var canvasBitmapData:BitmapData; private var canvasBitmap:Bitmap; private var canvasBlur:BlurFilter; private var canvasFade:ColorMatrixFilter; private var clipRect:Rectangle; private var point:Point; public function Hyperspace():void { if ( stage != null ) { stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; stage.quality = StageQuality.MEDIUM; displayWidth = stage.stageWidth; displayHeight = stage.stageHeight; } halfDisplayWidth = displayWidth >> 1; halfDisplayHeight = displayHeight >> 1; circleWidth = displayWidth >> 2; circleHeight = displayHeight >> 2; circleAngle = 0; circlePoint = new Point (0, 0); clipRect = new Rectangle (0, 0, displayWidth, displayHeight); point = new Point (0, 0); starHolder = new Sprite(); starField = new Vector.<Star>; // the stars are stored in this Vector (typed array) starNum = 1000; // the number of stars starSpeed = 1.2; var canvasFadeMatrix:Array = new Array(); canvasFadeMatrix = canvasFadeMatrix.concat([1, 0, 0, 0, 0]); // red canvasFadeMatrix = canvasFadeMatrix.concat([0, 0, 0, 0, 0]); // green canvasFadeMatrix = canvasFadeMatrix.concat([0, 0, 0, 0, 0]); // blue canvasFadeMatrix = canvasFadeMatrix.concat([0, 0, 0, 0.97, 0]); // alpha canvasFade = new ColorMatrixFilter (canvasFadeMatrix); canvasBlur = new BlurFilter (8, 8, 1); canvasBitmapData = new BitmapData (displayWidth, displayHeight, true, 0x00000000); canvasBitmap = new Bitmap (canvasBitmapData, PixelSnapping.AUTO, false); addChildAt (canvasBitmap, 0); // create the initial set of stars for (var i:int = 0; i < starNum; i++) { currentStar = new Star(); currentStar.xPos = Math.random() * 50.0 - 25.0; currentStar.yPos = Math.random() * 50.0 - 25.0; currentStar.zPos = Math.random() * 100.0; starHolder.addChild (currentStar); starField[i] = currentStar; } addEventListener(Event.ENTER_FRAME, updateFrame, false, 0, true); } private function updateFrame(event:Event):void { // the stars' point of origin is slowly moving around on a elliptical path // this is where the points of the path are calculated / updated circlePoint.x = halfDisplayWidth + Math.cos (circleAngle) * circleWidth; circlePoint.y = halfDisplayHeight + Math.sin (circleAngle) * circleHeight; circleAngle += 0.02; var i:int = -1; // to make sure the first element in the while-loop is handled properly while (++i < starNum) { currentStar = starField[i]; // if a star reaches or goes past the camera-plane, // it's assigned new random coordinates and pushed back if (currentStar.zPos <= 0.0) { currentStar.xPos = Math.random() * 50 - 25; currentStar.yPos = Math.random() * 50 - 25; currentStar.zPos = 100.0; } currentStar.zPos -= starSpeed; currentStar.x = currentStar.xPos / currentStar.zPos * displayWidth + circlePoint.x; currentStar.y = currentStar.yPos / currentStar.zPos * displayHeight + circlePoint.y; // the proper scale and transparency of each star is set here currentStar.scaleX = currentStar.scaleY = currentStar.alpha = 1.0 - currentStar.zPos * 0.01; } // the on-screen bitmap buffer is processed here, and the // starHolder container is drawn into it every frame as well. // besides creating the "redshift" trail-effect this also makes it // unnecessary to check for out-of-bounds stars in order to reduce off-screen draw. // (try "Show Redraw Regions" to verify) canvasBitmapData.applyFilter (canvasBitmapData, clipRect, point, canvasBlur); canvasBitmapData.applyFilter (canvasBitmapData, clipRect, point, canvasFade); canvasBitmapData.draw (starHolder, starHolder.transform.matrix, null, null, clipRect, false); } } } |
…and here’s the additional little class which is used for each individual star:
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 | // (C) edvardtoth.com package { import flash.display.Sprite; public class Star extends Sprite { // yes, the lack of getters and setters is bad manners, // but for this particular application it's also way faster public var xPos:Number; public var yPos:Number; public var zPos:Number; public function Star() { xPos = 0; yPos = 0; zPos = 0; graphics.beginFill (0xffffff); graphics.drawCircle (0.0, 0.0, 3.0); graphics.endFill(); } } } |

I’m just starting to learn AS after animating time line in Flash for years.Thanks for all the cool stuff you are posting
I like the red trails a lot! Thanks for posting.
Hi bro..Im sucks at AS…could email me the .fla
Your work is a total madman genius…
Please email to : efxtive@gmail.com
thanks a bunch bro…i love u