Jelly Ball
package
{
import flash.display.*;
import flash.geom.*;
import flash.events.*;
[SWF(width="465", height="465", backgroundColor="0xffe0ce", frameRate="31")]
public class JBall extends Sprite
{
private static const N:int = 29;
private static const R:int = 50;
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 = 180;
private var mBoxHH:int = 180;
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(0xffffff);
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
{
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) * .4;
mGVec.x = Math.sin(a) * .4;
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):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;
}
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);
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);
}
}
private function draw():void
{
var g:Graphics = mBallLayer.graphics;
g.clear();
g.beginFill(0xff7766);
for (var i:int = 0;i < N;i++)
{
var nd:JNode = mNodes[i];
if (i == 0)
g.moveTo(nd.x, nd.y);
else
g.lineTo(nd.x, nd.y);
}
g.endFill();
}
private static function addVec(v0:Point, v:Point):void
{
v0.x += v.x;
v0.y += v.y;
}
private function applyInternalForce(nd:JNode):void
{
var p:Point = new Point();
generateRoundPos(nd.theta, p);
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.19;
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(0xff7766);
g.drawCircle(0, 0, 3);
}
}