// Click to apply attraction force. // Please view all steps, to see how i got to this point. // I did not / do not, know when I'll stop these iterations but they are fun. // Please See proximity step 6, for Attractive/Repellent forces // Sort of forked 5. Tween controlling BetweenAS3 // forked from onedayitwillmake's Proximity step 6 // forked from onedayitwillmake's Proximity step 5 // forked from onedayitwillmake's Proximity step 4 // forked from onedayitwillmake's forked from: Proximity step 3 // forked from onedayitwillmake's forked from: Proximity step 2 // forked from onedayitwillmake's forked from: Proximity step 1 /** * Proximity field - Step 7 * @Revision * -First time using BetweenAS3! -the parameter, "stopOnComplete" = false, brings this spiderweb to life * @author Mario Gonzalez * @see http://onedayitwillmake.com/ */ package { import flash.display.GradientType; import flash.display.Graphics import flash.display.Shape; import flash.display.SpreadMethod; import flash.display.Sprite; import flash.display.StageQuality; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Matrix; import flash.geom.Point; import org.libspark.betweenas3.BetweenAS3; import org.libspark.betweenas3.easing.Back; import org.libspark.betweenas3.easing.Sine; import org.libspark.betweenas3.tweens.ITween; [SWF(width="465", height="465", fps="1", background="#000000")] public class Proximity extends Sprite { //Parameters private var _cCount :int = 0; private var _cMax :int = 80; //Rendering private var _canvas :Sprite; public var _canvasGraphics :Graphics //Reference public var _lastCircle :Circle; //Movement public static var FORCE_DEFAULT :int = 500; public static var FORCE :int = FORCE_DEFAULT; public var _mousePressed :Boolean = false; public var _mousePoint :Point = new Point(0, 0); public function Proximity() { stage.quality = StageQuality.LOW; stage.frameRate = 60; addChildAt(createBG(), 0); addChild(_canvas = new Sprite()); _canvasGraphics = _canvas.graphics; create(); addEventListener(Event.ENTER_FRAME, loop); stage.addEventListener(MouseEvent.MOUSE_DOWN, toggleMouseDown); stage.addEventListener(MouseEvent.MOUSE_UP, toggleMouseDown); } private function createBG():Sprite { var matr:Matrix = new Matrix(); matr.createGradientBox(465, 465, Math.PI / 2, 0, 0); var bg:Sprite = new Sprite(); bg.graphics.beginGradientFill ( GradientType.LINEAR, [0x000021, 0x000000], //colors [1, 1], //alphas [0, 255], //ratios matr, //matrix SpreadMethod.PAD ); bg.graphics.drawRect(0, 0, 465, 465); bg.graphics.endFill(); return bg; } /** * Main program loop */ private function loop(e:Event):void { if(stage.mouseX == 00 && stage.mouseY == 00) Proximity.FORCE = 0; else Proximity.FORCE = Proximity.FORCE_DEFAULT _mousePoint.x = stage.mouseX; _mousePoint.y = stage.mouseY; draw(); } /** * Creates more circles if we have not reached the maximum count # // Time setting: 2.5sec # BetweenAS3.tween(box1, {x: 220}, null, 2.5).play(); # # // Easing setting: EaseOutBounce # BetweenAS3.tween(box2, {x: 220}, null, 0.5, Bounce.easeOut).play(); # # // Easing with parameter # BetweenAS3.tween(box3, {x: 220}, null, 0.5, Back.easeOutWith(1.9)).play(); # # // Delay setting: 1.0sec # BetweenAS3.tween(box4, {x: 220}, null, 1.5, null, 1.0).play(); */ public function create():void { //if(_cCount >= _cMax) return; var c:Circle; var columns :int = 8; var rows :int = 10; for(var ax:int = 0; ax < columns; ax++) { for (var ay:int = 0; ay < rows; ay++) { c = new Circle(this); var startX:int = Math.random() * 465; var startY:int = Math.random() * 10 - 5 + 15; var homeX:int = ax * (475 / columns); var homeY:int = 470 addChild(c); var t:ITween = BetweenAS3.tween(c, {_ix: homeX, x: homeX, y: homeY, _iy: homeY}, /* End values */ {x: startX, _ix: startX, y: startY, _iy: startY}, /* Start at */ Math.random() * 6 + 1, /* Tween duration in seconds */ Sine.easeOutIn, /* Easing equation */ Math.random() * 3 /* Delay duration in seconds */ ); t.stopOnComplete = false; // Loop the tween forever; t.onPlay = c.reset; t.play(); // Only null on the first Circle created if(_lastCircle) c._prev = _lastCircle; // Store here, for next loop iteration // Once we're done, this variable is at the top of the LinkedList _lastCircle = c; } } } /** * Draws the proximity field between the circles */ public function draw():void { _canvas.graphics.clear(); _canvas.graphics.lineStyle(1, 0xffffff, 0.3); if(_lastCircle == null) return; //Only null, if draw() happens to be fired before circles created _lastCircle.checkForProximity(_lastCircle._prev); //The top circle, check against all back ones, then call the one under _lastCircle.move(); //Move then call the one udner } public function toggleMouseDown(e:MouseEvent):void { if(_mousePressed) _mousePressed = false; else _mousePressed = true; } } } import flash.display.Shape; import flash.display.Sprite; /** * Circles that live in the feild */ class Circle extends Sprite { private var _curveModifier :Number = Math.random() * 50 - 25; //How much to curve up or down on curveTo public var _p :Proximity; //reference public var _prev :Circle; //Linked list style behavior //MOVEMENT public static var ACC_PARAM:Number = 0.05; public static var VELOCITY_PARAM:Number = 0.85 public var _ix:Number; public var _iy:Number; public var _vx:Number = 0; public var _vy:Number = 0; public var _ax:Number = 0; public var _ay:Number = 0; /** * Individual Circles know only the Circle created previously to their own */ public function Circle(p:Proximity):void { _p = p; //blendMode = "add"; // graphics.beginFill(Math.random() * 255 * 255 * 255, 0.5) // graphics.drawCircle(0, 0, _radius); // graphics.endFill(); graphics.beginFill(0xffffff, 1) graphics.drawCircle(0, 0, 1); graphics.endFill(); } public function reset():void { _vx = 0; _vy = 0; _ax = 0; _ay = 0; } /** * Check all previous circles for proximity, and do [something] * There is no need for each circle to check the ones ahead, * because they've already checked against this one. * * Called recursively for this circle, until the linked list reaches the first circle. * Once it does, it calls checkForProximity on its '_prev' * The sequence repeats until there are no more previous ones * * @param tc:Circle The 'test circle' we will check against. */ public function checkForProximity(tc:Circle):void { if(tc == null) return; // This is the first circle created (unless error of course!) //if(tc._isEnabled == false) { checkForProximity(tc._prev); return;}; var d:Number = Math.sqrt((x - tc.x) * (x - tc.x) + (y - tc.y) * (y - tc.y)); if(d < 100) { _p._canvasGraphics.moveTo(x, y); //_p._canvasGraphics.lineTo(tc.x, tc.y); //_p._canvasGraphics.curveTo(tc.x, tc.y); _p._canvasGraphics.curveTo((x + tc.x) * 0.5, (y + tc.y) * 0.5 + _curveModifier, tc.x, tc.y); } //Keep checking backwards for proximity, until you reach the first circle if(tc._prev) checkForProximity(tc._prev); //Reached first circle. We are the last created circle Main.init(), //so call our _prev and continue the loop backwards //until we reach the first particle created else if(_prev) _prev.checkForProximity(_prev._prev); } /** * Moves the circle, initial position relative to mouse attraction/repelling force */ public function move():void { return;//Not used, since we're just tweening in this fork, see proximity step 6 //Don't let the force become too strong, by saying the distance will always be X at min var dist:Number = Math.max(Math.sqrt((x - stage.mouseX) * (x - stage.mouseX) + (y - stage.mouseY) * (y - stage.mouseY)), 40); var dy:Number = stage.mouseY - y; var dx:Number = stage.mouseX - x var angle:Number = Math.atan2(dy, dx); var f:Number = 1 / dist * Proximity.FORCE * ((_p._mousePressed == true) ? 1 : -1); _ax += Math.cos(angle) * f; _ay += Math.sin(angle) * f; _ax += (_ix - x) * ACC_PARAM; _ay += (_iy - y) * ACC_PARAM; _vx = (_vx + _ax) * VELOCITY_PARAM; _vy = (_vy + _ay) * VELOCITY_PARAM; x += _vx; y += _vy; _ax = _ay = 0; if(_prev) //Call move on all circles _prev.move(); } public function destroy():void { // _p._firstCircle = this; } public function enable():void { x = _ix = Math.random() * 10 - 5 + 15; } } Proximity step 7