In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Jelly Ball 2

package
{
	import flash.display.*;
	import flash.geom.*;
	import flash.events.*;

    [SWF(width="465", height="465", backgroundColor="0xffffff", frameRate="31")]
	public class JBall extends Sprite
	{
		private static const N:int = 61;
		private static const R:int = 60;

		public static const JGRAD_C:Array = [0x002255, 0x3377cc];
		public static const JGRAD_A:Array = [0.4, 0.7];
		public static const JGRAD_R:Array = [0, 255];
		private var mJGradTrans:Matrix = new Matrix();

		public static const HGRAD_C:Array = [0xaaeeff, 0xaaeeff, 0xaaeeff];
		public static const HGRAD_A:Array = [0.3, 0.02, 0];
		public static const HGRAD_R:Array = [0, 190, 191];

		private var mNodes:Array = [];
		private var mCenter:Point = new Point();
		private var mGVec:Point = new Point();
		private var mField:Sprite = new Sprite();
		private var mBallLayer:Sprite = new Sprite();

		private var mBoxHW:int = 152;
		private var mBoxHH:int = 168;

		private var mFAngle:Number = 0;

		function JBall()
		{
			generateNodes(N);
			addChild(mField);
			mField.addChild(mBallLayer);
			mField.x = 232;
			mField.y = 232;
			var g:Graphics = mField.graphics;
			g.beginFill(0);
			g.drawRect(-mBoxHW, -mBoxHH, 2*mBoxHW, 2*mBoxHH);

			mCenter.x = 0;
			mCenter.y = 0;

			var i:int, nd:JNode;

			var pt:Point = new Point();
			for (i = 0;i < N;i++)
			{
				nd = JNode(mNodes[i]);
				generateRoundPos(nd.theta, pt);

				nd.x = pt.x;
				nd.y = pt.y;
			}

			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}

		private function onEnterFrame(e:Event):void
		{
                        if (!(isNaN(mouseX) || mouseX < -100 || mouseX > 600)) { 
			var mx:Number = (mouseX - 232) * 0.0003;

			const DPI:Number = Math.PI*2;
			mFAngle += mx;
			if (mFAngle < 0) mFAngle += DPI;
			else if (mFAngle > DPI) mFAngle -= DPI;

			setGVec(mFAngle);
                        }
			tick();
			move();
			draw();
		}

		private function setGVec(a:Number):void
		{
			mGVec.y = Math.cos(a) * .7;
			mGVec.x = Math.sin(a) * .7;
			mField.rotation = a * 180 / Math.PI;
		}

		private function generateNodes(n:int):void
		{
			var i:int, a:Number, nd:JNode;

			for (i = 0;i < n;i++)
			{
				nd = new JNode();

				a = Math.PI * 2.0 * Number(i)/Number(n);
				nd.theta = a;
				mField.addChild(nd);
				mNodes.push(nd);
			}
		}

		private function generateRoundPos(a:Number, outpt:Point, r:Number = R):void
		{
			outpt.x = mCenter.x + Math.sin(a) * r;
			outpt.y = mCenter.y - Math.cos(a) * r;
		}

		private static const be:Number = 0.4;
		private function tick():void
		{
			var i:int, nd:JNode;
			var nxt:Number;

			calcCenter();

			for (i = 0;i < N;i++)
			{
				nd = mNodes[i];
				nd.v.x *= 0.98;
				nd.v.y *= 0.98;
			}

			var prs:Number = calcPressure();
			for (i = 0;i < N;i++)
			{
				nd = mNodes[i];

				nd.F.x *= -0.2;
				nd.F.y *= -0.2;
				addVec(nd.v, nd.F);

				nd.F.x = 0;
				nd.F.y = 0;

				addVec(nd.v, mGVec);
				applyInternalForce(nd, prs);
				addVec(nd.v, nd.F);

				if (nd.v.y > 0) {
					nxt = nd.y + nd.v.y;
					if (nxt > mBoxHH) {
						nd.nextV.y = -nd.v.y * be;
						nd.v.y = mBoxHH - nd.y;
					}
				} else {
					nxt = nd.y + nd.v.y;
					if (nxt < -mBoxHH) {
						nd.nextV.y = -nd.v.y * be;
						nd.v.y = -mBoxHH - nd.y;
					}
				}

				if (nd.v.x > 0) {
					nxt = nd.x + nd.v.x;
					if (nxt > mBoxHW) {
						nd.nextV.x = -nd.v.x * be;
						nd.v.x = mBoxHW - nd.x;
					}
				} else {
					nxt = nd.x + nd.v.x;
					if (nxt < -mBoxHW) {
						nd.nextV.x = -nd.v.x * be;
						nd.v.x = -mBoxHW - nd.x;
					}
				}
			}
		}

		private function move():void
		{
			var i:int, nd:JNode;

			for (i = 0;i < N;i++)
			{
				nd = mNodes[i];
				nd.x += nd.v.x;
				nd.y += nd.v.y;

				if (!isNaN(nd.nextV.x)) {
					nd.v.x = nd.nextV.x;
					nd.nextV.x = NaN;
				}

				if (!isNaN(nd.nextV.y)) {
					nd.v.y = nd.nextV.y;
					nd.nextV.y = NaN;
				}

		//		applyInternalForce(nd, 0);
			}
		}

		private function draw():void
		{
			var i:int, nd:JNode;
			var g:Graphics = mBallLayer.graphics;
			g.clear();

			var ar:Number = 0, rx:Number, ry:Number;
			for (i = 0;i < N;i++)
			{
				nd = mNodes[i];
				rx = mCenter.x - nd.x;
				ry = mCenter.y - nd.y;
				ar += Math.sqrt(rx*rx + ry*ry);
			}

			g.beginFill(0x0011aa, 0.4);
			drawBallShape(g, 0);
			g.endFill();

			ar /= Number(R);
			var sx:Number, sy:Number;
			var r:Number = 0.06;

			mJGradTrans.createGradientBox(ar*4, ar*4, 0, mCenter.x + Math.sin(mFAngle-2.4)*40 - ar*2, mCenter.y + Math.cos(mFAngle-2.4)*40 - ar*2);
			g.beginGradientFill(GradientType.RADIAL, JGRAD_C, JGRAD_A, JGRAD_R, mJGradTrans);
			drawBallShape(g, r);
			g.endFill();

			r = 0.13;
			mJGradTrans.createGradientBox(ar*2.2, ar*2.2, 0, mCenter.x + Math.sin(mFAngle-2.8)*40 - ar, mCenter.y + Math.cos(mFAngle-2.8)*40 - ar);
			g.beginGradientFill(GradientType.RADIAL, HGRAD_C, HGRAD_A, HGRAD_R, mJGradTrans);
			drawBallShape(g, r);
			g.endFill();
		}

		private function drawBallShape(g:Graphics, r:Number):void
		{
			var nd:JNode;
			var nd2:JNode;
			var sx:Number, sy:Number;
			var sx2:Number, sy2:Number;
			for (var i:int = 0;i < N;i+=2)
			{
				nd  = mNodes[i];
				nd2 = mNodes[i+1];

				sx = nd.x*(1-r*0.9) + mCenter.x*r*0.9;
				sy = nd.y*(1-r*0.9) + mCenter.y*r*0.9;

				sx2 = nd2.x*(1-r) + mCenter.x*r;
				sy2 = nd2.y*(1-r) + mCenter.y*r;

				if (i == 0) {
					g.moveTo(sx, sy);
					i--;
				}
				else {
					g.curveTo(sx, sy, sx2, sy2);
				}
			}

			nd  = mNodes[N-1];
			nd2 = mNodes[0];

			sx = nd.x*(1-r) + mCenter.x*r;
			sy = nd.y*(1-r) + mCenter.y*r;

			sx2 = nd2.x*(1-r) + mCenter.x*r;
			sy2 = nd2.y*(1-r) + mCenter.y*r;
			g.curveTo(sx2, sy2, sx, sy);
		}

		private static function addVec(v0:Point, v:Point):void
		{
			v0.x += v.x;
			v0.y += v.y;
		}

		private function calcPressure():Number
		{
			var p:Number = 0;
			var k:Number = N * R;
			var vx:Number, vy:Number;
			for (var i:int = 0;i < N;i++) {
				var nd:JNode = mNodes[i];
				vx = nd.x - mCenter.x;
				vy = nd.y - mCenter.y;
				p += Math.sqrt(vx*vx + vy*vy);
			}

			p = (k - p) * 0.3;
			if (p < 0) p = 0;
if (p > 20) p = 20;
			return p;
		}

		private function applyInternalForce(nd:JNode, prs:Number):void
		{
			var p:Point = new Point();
			generateRoundPos(nd.theta, p, R+prs);
			var vx:Number = (p.x-(nd.x+nd.v.x*0.1));
			var vy:Number = (p.y-(nd.y+nd.v.y*0.1));

//			var e:Number = 1.0 / (Math.sqrt(vx*vx + vy*vy)*0.01 + 1.0);
//			if (e > 1) e = 1;

			var e:Number = 0.13;

			vx *= e;
			vy *= e;

			var nrm:Number = Math.sqrt(vx*vx + vy*vy);
			if (nrm > 5) {
				vx *= 5 / nrm;
				vy *= 5 / nrm;
			}

			nd.F.x += vx;
			nd.F.y += vy;
		}

		private function calcCenter():void
		{
			var cx:Number = 0;
			var cy:Number = 0;

			var i:int, nd:JNode;

			for (i = 0;i < N;i++)
			{
				nd = mNodes[i];
				cx += nd.x;
				cy += nd.y;
			}

			mCenter.x = cx / Number(N);
			mCenter.y = cy / Number(N);
		}
	}
}

class JNode extends flash.display.Sprite
{
	import flash.display.*;
	import flash.geom.*;

	public var theta:Number;
	public var v:Point = new Point(0, 0);
	public var F:Point = new Point(0, 0);
	public var nextV:Point = new Point(NaN, NaN);

	function JNode()
	{
/*
		var g:Graphics = graphics;
		g.beginFill(0xff9933);
		g.drawCircle(0, 0, 3);
*/
	}
}