neonRings
/**
* Copyright poiasd ( http://wonderfl.net/user/poiasd )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/uUYx
*/
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.Shape;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BlurFilter;
import flash.geom.Point;
import frocessing.color.ColorHSV;
[SWF (width = "465", height = "465", frameRate = "30")]
public class NeonRings extends Sprite {
private const STAGE_WIDTH:uint = 465;
private const STAGE_HEIGHT:uint = 465;
private const BG_COLOR:uint = 0x111111;
private const RING_COUNT:uint = 400;
private const COLOR_VARIATION:uint = RING_COUNT >> 2;
private const RING_SIZE:uint = 10;
private const RADIUS:uint = RING_SIZE >> 1;
private const IMG_HALF_SIZE:uint = RADIUS + 8;
private const RING_RESTITUTION:Number = 1.0;
private const WALL_RESTITUTION:Number = 1.0;
private var _canvas:BitmapData;
private var _ringImgList:Vector.<BitmapData> = new Vector.<BitmapData> ();
private var _ringList:Vector.<Ring> = new Vector.<Ring> ();
public function NeonRings ():void {
_canvas = new BitmapData (STAGE_WIDTH, STAGE_HEIGHT, false, BG_COLOR);
addChild (new Bitmap (_canvas));
addChild (new Bitmap (createScreen ()));
var hsv:ColorHSV;
var blur:Shape = new Shape ();
var ring:Shape = new Shape ();
for (var i:int = 0; i < COLOR_VARIATION; i++) {
_ringImgList [i] = new BitmapData (IMG_HALF_SIZE << 1, IMG_HALF_SIZE << 1, true, 0xFFFFFF);
hsv = new ColorHSV (i * 360 / COLOR_VARIATION, 1, 1);
blur.graphics.clear ();
blur.graphics.lineStyle (2, hsv.value);
blur.graphics.drawCircle (IMG_HALF_SIZE, IMG_HALF_SIZE, RADIUS);
blur.filters = [new BlurFilter (6, 6, 4)];
_ringImgList [i].draw (blur);
ring.graphics.clear ();
ring.graphics.beginFill (hsv.value);
ring.graphics.drawCircle (IMG_HALF_SIZE, IMG_HALF_SIZE, RADIUS);
ring.graphics.drawCircle (IMG_HALF_SIZE, IMG_HALF_SIZE, RADIUS - 1);
ring.graphics.endFill ();
_ringImgList [i].draw (ring);
}
stage.addEventListener (MouseEvent.MOUSE_DOWN, onMouseDown);
}
private function onMouseDown (event:MouseEvent):void {
stage.addEventListener (Event.ENTER_FRAME, onEnterFrame);
stage.removeEventListener (MouseEvent.MOUSE_DOWN, onMouseDown);
}
private var _count:int = 0;
private var _angle:Number = 0;
private function onEnterFrame (event:Event):void {
_canvas.lock ();
_canvas.fillRect (_canvas.rect, BG_COLOR);
var ring:Ring;
if (_count < RING_COUNT) {
var vx0:Number = 3 * Math.cos (_angle);
var vy0:Number = 3 * Math.sin (_angle);
ring = new Ring ((STAGE_WIDTH >> 1) + vx0 * 6, (STAGE_HEIGHT >> 1) + vy0 * 6, vx0, vy0);
ring.color = _count % COLOR_VARIATION;
_angle += Math.PI * 35 / 180;
_ringList.push (ring);
_count++;
}
for each (ring in _ringList) {
ring.x += ring.vx;
ring.y += ring.vy;
}
_ringList.sort (compare);
function compare(a:Ring, b:Ring):int {
return (a.x == b.x) ? 0 : (a.x > b.x) ? 1 : - 1;
}
var length:int = _ringList.length;
for (var i:int = 0; i < length - 1; i++) {
for (var j:int = i + 1; j < length; j++) {
var dx:Number = _ringList [j].x - _ringList [i].x;
if (dx <= RING_SIZE) {
collideRing (_ringList [i], _ringList [j]);
}else {
break;
}
}
}
var ringPos:Point = new Point ();
for each (ring in _ringList) {
collideWall (ring);
ringPos.x = ring.x - IMG_HALF_SIZE;
ringPos.y = ring.y - IMG_HALF_SIZE;
_canvas.copyPixels (_ringImgList [ring.color], _ringImgList [ring.color].rect, ringPos);
}
_canvas.unlock();
}
private function collideRing (ring1:Ring, ring2:Ring):void {
var dx:Number = ring2.x - ring1.x;
var dy:Number = ring2.y - ring1.y;
var distance:Number = Math.sqrt (dx * dx + dy * dy);
if (distance > RING_SIZE) return;
var cos:Number = dx / distance;
var sin:Number = dy / distance;
var offset:Number = (RING_SIZE - distance + 1) * 0.5;
var offsetX:Number = offset * cos;
var offsetY:Number = offset * sin;
var v1:Point = coordinateRotation (ring1.vx, ring1.vy, cos, -sin);
var v2:Point = coordinateRotation (ring2.vx, ring2.vy, cos, -sin);
var temp:Number = v1.x;
v1.x = ((1 - RING_RESTITUTION) * v1.x + (1 + RING_RESTITUTION) * v2.x) * 0.5;
v2.x = ((1 + RING_RESTITUTION) * temp + (1 - RING_RESTITUTION) * v2.x) * 0.5;
v1 = coordinateRotation (v1.x, v1.y, cos, sin);
v2 = coordinateRotation (v2.x, v2.y, cos, sin);
ring1.setValue (ring1.x - offsetX, ring1.y - offsetY, v1.x, v1.y);
ring2.setValue (ring2.x + offsetX, ring2.y + offsetY, v2.x, v2.y);
}
private function collideWall (ring:Ring):void {
if (ring.x <= RADIUS) {
ring.x = RADIUS;
ring.vx *= - WALL_RESTITUTION;
}else if (ring.x >= STAGE_WIDTH - RADIUS) {
ring.x = STAGE_WIDTH - RADIUS;
ring.vx *= - WALL_RESTITUTION;
}
if (ring.y <= RADIUS) {
ring.y = RADIUS;
ring.vy *= - WALL_RESTITUTION;
}else if (ring.y >= STAGE_HEIGHT - RADIUS) {
ring.y = STAGE_HEIGHT - RADIUS;
ring.vy *= - WALL_RESTITUTION;
}
}
private function coordinateRotation (x:Number, y:Number, cos:Number, sin:Number):Point {
return new Point (x * cos - y * sin, x * sin + y * cos);
}
private function createScreen ():BitmapData {
var tile:BitmapData = new BitmapData (2, 2, true, 0x000000);
tile.setPixel32 (1, 0, 0x20000000);
tile.setPixel32 (0, 1, 0x20000000);
tile.setPixel32 (1, 1, 0x40000000);
var shape:Shape = new Shape ();
shape.graphics.beginBitmapFill (tile);
shape.graphics.drawRect (0, 0, STAGE_WIDTH, STAGE_HEIGHT);
var screen:BitmapData = new BitmapData (STAGE_WIDTH, STAGE_HEIGHT, true, 0x000000);
screen.draw (shape);
return screen;
}
}
}
class Ring{
public var x:Number;
public var y:Number;
public var vx:Number;
public var vy:Number;
public var color:uint = 0;
public function Ring (x:Number, y:Number, vx:Number, vy:Number):void {
setValue (x, y, vx, vy);
}
public function setValue (x:Number, y:Number, vx:Number, vy:Number):void {
this.x = x;
this.y = y;
this.vx = vx;
this.vy = vy;
}
}