forked from: フリーハンドベジェ
forked from フリーハンドベジェ (diff: 404)
mashed: forked (that is : http://wonderfl.net/c/srIi ) and http://wonderfl.net/c/ubO1
ActionScript3 source code
/**
* Copyright aobyrne ( http://wonderfl.net/user/aobyrne )
* GNU General Public License, v3 ( http://www.gnu.org/licenses/quick-guide-gplv3.html )
* Downloaded from: http://wonderfl.net/c/srIi
*/
/**
* フリーハンドベジェAS3移植版
* (ドラッグ操作で絵がかけます。)
*
* Released under the GPL
*
* refered from
* http://childtv.web.fc2.com/bezier/
*/
package
{
import flash.display.Sprite;
import flash.events.Event;
[SWF(frameRate="60", backgroundColor="0xffffff")]
public class BezierSoftDrawing extends Sprite
{
public function BezierSoftDrawing()
{
loaderInfo.addEventListener(Event.COMPLETE, completeHandler);
}
private function completeHandler(e:Event):void
{
loaderInfo.removeEventListener(Event.COMPLETE, completeHandler);
addChild(new BezierCanvas(loaderInfo.width, loaderInfo.height));
}
}
}
import flash.display.DisplayObjectContainer;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.utils.Timer;
class BezierCanvas extends Sprite
{
private var _drawingPath:Path;
private var _fixedPath:Path;
private var _generator:BezierGenerator;
private var _lastHeight:Number;
private var _lastPoint:BezierPoint;
private var _lastWidth:Number;
private var _offsetX:Number;
private var _offsetY:Number;
private var _paths:Array;
private var _points:Array;
private var _tangent:BezierPoint;
private var wanderingTarget:WanderingTarget;
private var wPoint:Point;
public function BezierCanvas(w:Number, h:Number)
{
_generator = new BezierGenerator({tolerance: 2.5, maxIterations: 1});
_paths = [];
mouseChildren = false;
//addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
var g:Graphics = graphics;
g.clear();
g.beginFill(0, 0);
g.drawRect(0, 0, w, h);
g.endFill();
wanderingTarget = new WanderingTarget;
var canvasHeight :Number = 465;
var canvasWidth:Number = 465;
wanderingTarget.position = new Vector3D(canvasHeight * 0.5,canvasHeight * 0.5);
wanderingTarget.boundsCentre = new Vector3D(canvasHeight*0.5, canvasWidth*0.5, 0);
wanderingTarget.boundsRadius = canvasHeight * 0.5;
var timer:Timer = new Timer(100);
timer.addEventListener(TimerEvent.TIMER, ot);
timer.start();
wPoint = new Point;
}
private function ot(e:TimerEvent):void
{
var timer:Timer = e.target as Timer;
var number:int = timer.currentCount % 50;
wanderingTarget.wander();
wanderingTarget.update();
wPoint.x = wanderingTarget.x;
wPoint.y = wanderingTarget.y;
trace( "wPoint : " + wPoint );
if (number==1) //mouse down
{
startLine(wPoint);
}
else if (number == 0)//mouse up
{
addPoint(toPointFromPoint(wPoint));
if (_drawingPath === null)
{
_fixedPath.erase();
return;
}
_drawingPath.erase();
_fixedPath.append(_drawingPath);
_paths.push(_fixedPath);
}
else
{
addPoint(toPointFromPoint(wPoint));
}
}
public function redraw(segment:Array):void
{
if (_drawingPath !== null)
{
_drawingPath.clear();
}
else
{
_drawingPath = new Path(this);
}
_drawingPath.moveTo(segment[0]);
_drawingPath.curveTo(segment[1], segment[2], segment[3]);
_drawingPath.draw();
}
private function addPoint(point:BezierPoint):void
{
if (point.equals(_lastPoint))
{
return;
}
_lastPoint = point;
_points.push(point);
var segment:Array = _generator.fromPoints(_points, _tangent);
if (segment.length === 0)
{
_drawingPath.erase();
_fixedPath.append(_drawingPath);
_tangent = _fixedPath.smoothTangent();
_points = _points.slice(_points.length - 2);
segment = _generator.fromPoints(_points, _tangent);
}
redraw(segment);
}
private function mouseDownHandler(e:MouseEvent):void
{
stage.addEventListener(MouseEvent.MOUSE_UP, mouseHandler);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseHandler);
var p:Point = new Point(e.stageX, e.stageY);
trace( "p : " + p );
p = globalToLocal(p);
trace( "p : " + p );
_offsetX = e.stageX - p.x;
trace( "_offsetX : " + _offsetX );
_offsetY = e.stageY - p.y;
trace( "_offsetY : " + _offsetY );
_lastPoint = null;
_tangent = null;
var point:BezierPoint = toPoint(e);
_points = [point];
_fixedPath = new Path(this);
_fixedPath.moveTo(point);
_fixedPath.draw();
_drawingPath = null;
}
private function startLine(pt:Point):void
{
var p:Point = new Point(pt.x, pt.y);
p = globalToLocal(p);
_offsetX = 0;// e.stageX - p.x;
_offsetY = 0;// e.stageY - p.y;
_lastPoint = null;
_tangent = null;
var point:BezierPoint = toPointFromPoint(pt);
_points = [point];
_fixedPath = new Path(this);
_fixedPath.moveTo(point);
_fixedPath.draw();
_drawingPath = null;
}
private function mouseHandler(e:MouseEvent):void
{
if (e.type === MouseEvent.MOUSE_UP)
{
stage.removeEventListener(MouseEvent.MOUSE_UP, mouseHandler);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseHandler);
addPoint(toPoint(e));
if (_drawingPath === null)
{
_fixedPath.erase();
return;
}
_drawingPath.erase();
_fixedPath.append(_drawingPath);
_paths.push(_fixedPath);
return;
}
addPoint(toPoint(e));
e.updateAfterEvent();
}
private function toPoint(e:MouseEvent):BezierPoint
{
var x:Number = e.stageX - _offsetX;
var y:Number = e.stageY - _offsetY;
return new BezierPoint(x, y);
}
private function toPointFromPoint(pt:Point):BezierPoint
{
var x:Number = pt.x - _offsetX;
var y:Number = pt.y - _offsetY;
return new BezierPoint(x, y);
}
}
class Path extends Shape
{
private var _lastPoint:BezierPoint;
private var _pointSet:Array;
private var _target:DisplayObjectContainer;
public function Path(target:DisplayObjectContainer)
{
setupLineStyle();
_pointSet = [];
_target = target;
}
public function append(path:Path):void
{
var pointSet:Array = path._pointSet;
for (var i:int = 1, len:int = pointSet.length; i < len; i++)
{
var points:Array = pointSet[i];
if (points.length === 3)
{
curveTo(points[0], points[1], points[2]);
}
}
}
public function clear():void
{
_pointSet = [];
graphics.clear();
setupLineStyle();
}
public function curveTo(control1:BezierPoint, control2:BezierPoint, point:BezierPoint):void
{
_pointSet.push([control1, control2, point]);
var g:Graphics = graphics;
var x0:Number = _lastPoint.x;
var y0:Number = _lastPoint.y;
var x1:Number = control1.x * 3;
var y1:Number = control1.y * 3;
var x2:Number = control2.x * 3;
var y2:Number = control2.y * 3;
var x3:Number = point.x;
var y3:Number = point.y;
var u:Number = 1.0 / 50;
var t1:Number, t0:Number;
var x:Number, y:Number;
_lastPoint = point;
for (t0 = 0, t1 = 1; t0 < 1; t0 += u, t1 = 1 - t0)
{
x = (x0 * t1 * t1 * t1) +
(x1 * t0 * t1 * t1) +
(x2 * t0 * t0 * t1) +
(x3 * t0 * t0 * t0);
y = (y0 * t1 * t1 * t1) +
(y1 * t0 * t1 * t1) +
(y2 * t0 * t0 * t1) +
(y3 * t0 * t0 * t0);
g.lineTo(x, y);
}
g.lineTo(x3, y3);
}
public function draw():void
{
if (parent === null)
{
_target.addChild(this);
}
}
public function erase():void
{
if (parent !== null)
{
_target.removeChild(this);
}
}
public function moveTo(point:BezierPoint):void
{
_lastPoint = point;
_pointSet.push([point]);
graphics.moveTo(point.x, point.y);
}
public function setupLineStyle():void
{
graphics.lineStyle(3, 0, 1, false)
}
public function smoothTangent():BezierPoint
{
var points:Array = _pointSet[_pointSet.length - 1];
if (points !== null && points.length !== 3)
{
return null;
}
return points[2].minus(points[1]).unit;
}
}
class BezierPoint
{
public static const ZERO_POINT:BezierPoint = new BezierPoint(0, 0);
public static function operate(operator:Function, ... points):BezierPoint
{
var x:Array = [], y:Array = [];
for (var i:int = 0, len:int = points.length; i < len; i++)
{
x[i] = points[i].x;
y[i] = points[i].y;
}
return new BezierPoint(operator.apply(null, x), operator.apply(null, y));
}
private var _x:Number;
private var _y:Number;
private var _zero:Boolean;
public function BezierPoint(x:Number, y:Number)
{
_x = x;
_y = y;
_zero = _x === 0 && _y === 0;
}
public function get abs():Number
{
return Math.sqrt(_x * _x + _y * _y);
}
public function distance(p:BezierPoint):Number
{
return new BezierPoint(_x - p._x, _y - p._y).abs;
}
public function dot(p:BezierPoint):Number
{
return _x * p._x + _y * p._y;
}
public function equals(p:BezierPoint):Boolean
{
if (p === null)
{
return false;
}
return _x === p._x && _y === p._y;
}
public function minus(p:BezierPoint):BezierPoint
{
return new BezierPoint(_x - p._x, _y - p._y);
}
public function plus(p:BezierPoint):BezierPoint
{
return new BezierPoint(_x + p._x, _y + p._y);
}
public function get square():Number
{
return _x * _x + _y * _y;
}
public function time(value:Number):BezierPoint
{
return new BezierPoint(_x * value, _y * value);
}
public function toString():String
{
return "(" + x + ", " + y + ")";
}
public function get unit():BezierPoint
{
var a:Number = abs;
return new BezierPoint(_x / a, _y / a);
}
public function get x():Number
{
return _x;
}
public function get y():Number
{
return _y;
}
public function get zero():Boolean
{
return _zero;
}
}
class BezierGenerator
{
private static const PASCAL:Array = [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1]];
private var _bezier:Array;
private var _data:Array;
private var _endTangent:BezierPoint;
private var _len:int;
private var _maxIterations:Number;
private var _params:Array;
private var _splitBezierPoint:int;
private var _startTangent:BezierPoint;
private var _tolerance:Number;
public function BezierGenerator(option:*)
{
option = option || {};
_maxIterations = option.maxIterations || 3,
_tolerance = option.tolerance || 1;
}
public function fromPoints(points:Array, start:BezierPoint, end:BezierPoint = null):Array
{
setup(points, start, end);
var result:Array = _fromPoints();
free();
return result;
}
private function _fromPoints():Array
{
if (_len === 2)
{
return fromTwoPoints();
}
return generateBezier();
}
private function bezier(u:Number):Array
{
var u1:Number = 1 - u;
var u2:Number = u1 * u1;
var u3:Number = u * u;
return [u2 * u1, 3 * u * u2, 3 * u3 * u1, u3 * u];
}
private function bezierPt(b:Array, t:Number):BezierPoint
{
var s:Number = 1 - t;
var degree:int = b.length - 1;
var spow:Array = [1];
var tpow:Array = [1];
for (var d:int = 0; d < degree; d++)
{
spow[d + 1] = spow[d] * s;
tpow[d + 1] = tpow[d] * t;
}
var result:BezierPoint = b[0].time(spow[degree]);
for (d = 1; d <= degree; d++)
{
result = result.plus(b[d].time(PASCAL[degree][d] * spow[degree - d] * tpow[d]));
}
return result;
}
private function computeHook(point1:BezierPoint, point2:BezierPoint, param:Number):Number
{
var toleranceMore:Number = _tolerance;
var operator:Function = function(p1:Number, p2:Number, t:Number):Number
{
return (p1 + p2) / 2 - t;
};
var distance:Number = BezierPoint.operate(operator, point1, point2, bezierPt(_bezier, param)).abs;
return (distance < toleranceMore) ? 0 : distance / (point1.distance(point2) + toleranceMore);
}
private function estimateEndTangent():BezierPoint
{
var tangent:BezierPoint;
for (var i:int = _len - 2; i >= 0; i--)
{
tangent = _data[i].minus(_data[_len - 1]);
if (tangent.square > _tolerance * _tolerance)
{
return tangent.unit;
}
}
return tangent.zero ? _data[_len - 2].minus(_data[_len - 1]).unit : tangent.unit;
}
private function estimateStartTangent():BezierPoint
{
var tangent:BezierPoint;
for (var i:int = 1; i < _len; i++)
{
tangent = _data[i].minus(_data[0]);
if (tangent.square > _tolerance * _tolerance)
{
return tangent.unit;
}
}
return tangent.zero ? _data[1].minus(_data[0]).unit : tangent.unit;
}
private function free():void
{
_bezier = null;
_data = null;
_params = null;
_startTangent = null;
_endTangent = null;
}
private function fromTwoPoints():Array
{
_bezier[0] = _data[0];
_bezier[3] = _data[1];
var distance:Number = _bezier[0].distance(_bezier[3]) / 3;
var op1:Function = function(a:Number, b:Number):Number
{
return (a * 2 + b) / 3;
};
var op2:Function = function(a:Number, b:Number):Number
{
return a + b * distance;
};
_bezier[1] = _startTangent.zero
? BezierPoint.operate(op1, _bezier[0], _bezier[3])
: BezierPoint.operate(op2, _bezier[0], _startTangent);
_bezier[2] = _endTangent.zero
? BezierPoint.operate(op1, _bezier[3], _bezier[0])
: BezierPoint.operate(op2, _bezier[3], _endTangent);
return _bezier;
}
private function generateBezier():Array
{
setParamsByLength();
setAssumptBezier();
var error:Number = maxError();
if (Math.abs(error) <= 1)
return _bezier;
if (error >= 0 && error <= 3)
{
for (var i:int = 0, len:int = _maxIterations; i < len; i++)
{
setAssumptBezier();
error = maxError();
if (Math.abs(error) <= 1)
return _bezier;
}
}
if (error < 0)
{
if (_splitBezierPoint == 0 && !_startTangent.zero)
return fromPoints(_data, BezierPoint.ZERO_POINT, _endTangent);
if (_splitBezierPoint == _len - 1 && !_endTangent.zero)
return fromPoints(_data, _startTangent, BezierPoint.ZERO_POINT);
}
return [];
}
private function maxError():Number
{
var toleranceMore:Number = _tolerance;
var maxDistanceSquare:Number = 0;
var maxHook:Number = 0;
var snapEnd:int = 0;
var prevBezierPoint:BezierPoint = _bezier[0];
for (var i:int = 1, len:int = _len; i < len; i++)
{
var currentBezierPoint:BezierPoint = bezierPt(_bezier, _params[i]);
var distanceSquare:Number = currentBezierPoint.minus(_data[i]).square;
if (distanceSquare > maxDistanceSquare)
{
maxDistanceSquare = distanceSquare;
_splitBezierPoint = i;
}
var hook:Number = computeHook(prevBezierPoint, currentBezierPoint, (_params[i] + _params[i - 1]) / 2);
if (hook > maxHook)
{
maxHook = hook;
snapEnd = i;
}
prevBezierPoint = currentBezierPoint;
}
var maxDistanceRatio:Number = Math.sqrt(maxDistanceSquare) / toleranceMore;
if (maxHook <= maxDistanceRatio)
{
return maxDistanceRatio;
}
else
{
_splitBezierPoint = snapEnd - 1;
return -maxHook;
}
}
private function newtonRaphsonRootFind(bezier:Array, point:BezierPoint, param:Number):Number
{
var dbezier:Array = pointDifference(bezier);
var ddbezier:Array = pointDifference(dbezier);
var p:BezierPoint = bezierPt(bezier, param);
var dp:BezierPoint = bezierPt(dbezier, param);
var ddp:BezierPoint = bezierPt(ddbezier, param);
var diff:BezierPoint = p.minus(point);
var numerator:Number = diff.dot(dp);
var denominator:Number = dp.square + diff.dot(ddp);
var improvedParam:Number;
if (denominator > 0)
{
improvedParam = param - (numerator / denominator);
}
else
{
if (numerator > 0)
{
improvedParam = param * 0.98 - 0.01;
}
else if (numerator < 0)
{
improvedParam = param * 0.98 + 0.031;
}
else
{
improvedParam = param;
}
}
if (improvedParam < 0)
{
improvedParam = 0;
}
else if (improvedParam > 1)
{
improvedParam = 1;
}
var diffSquare:Number = diff.square;
for (var proportion:Number = 0.125; ; proportion += 0.125)
{
if (bezierPt(bezier, improvedParam).minus(point).square > diffSquare)
{
if (proportion > 1)
{
improvedParam = param;
break;
}
improvedParam = (1 - proportion) * improvedParam + proportion * param;
}
else
{
break;
}
}
return improvedParam;
}
private function pointDifference(points:Array):Array
{
var diff:Array = [];
for (var i:int = 0, len:int = points.length; i < len - 1; i++)
{
diff[i] = points[i + 1].minus(points[i]).time(len - 1);
}
return diff;
}
private function reparameterize():void
{
for (var i:int = 0, len:int = _len; i < len - 1; i++)
{
_params[i] = newtonRaphsonRootFind(_bezier, _data[i], _params[i]);
}
}
private function setAssumptBezier():void
{
var start:BezierPoint = _startTangent.zero ? estimateStartTangent() : _startTangent;
var end:BezierPoint = _endTangent.zero ? estimateEndTangent() : _endTangent;
setAssumptBezierWithTangent(start, end);
if (_startTangent.zero)
{
setControllBezierPoint(1);
if (!_bezier[0].equals(_bezier[1]))
{
start = _bezier[1].minus(_bezier[0]).unit;
}
setAssumptBezierWithTangent(start, end);
}
reparameterize();
}
private function setAssumptBezierWithTangent(start:BezierPoint, end:BezierPoint):void
{
var C:Array = [[0, 0], [0, 0]];
var X:Array = [0, 0];
_bezier[0] = _data[0];
_bezier[3] = _data[_len - 1];
for (var i:int = 0; i < _len; i++)
{
var b:Array = bezier(_params[i]);
var a:Array = [start.time(b[1]), end.time(b[2])];
C[0][0] += a[0].dot(a[0]);
C[0][1] += a[0].dot(a[1]);
C[1][0] = C[0][1];
C[1][1] += a[1].dot(a[1]);
var offset:BezierPoint = BezierPoint.operate(function(p:Number, bezier0:Number, bezier3:Number):Number
{
return p - (b[0] + b[1]) * bezier0 - (b[2] + b[3]) * bezier3;
}, _data[i], _bezier[0], _bezier[3]);
X[0] += a[0].dot(offset);
X[1] += a[1].dot(offset);
}
var alphaL:Number;
var alphaR:Number;
var detC:Number = C[0][0] * C[1][1] - C[1][0] * C[0][1];
if (detC)
{
var detC0X:Number = C[0][0] * X[1] - C[0][1] * X[0];
var detXC1:Number = X[0] * C[1][1] - X[1] * C[0][1];
alphaL = detXC1 / detC;
alphaR = detC0X / detC;
}
else
{
var c0:Number = C[0][0] + C[0][1];
if (c0)
{
alphaL = X[0] / c0;
}
else
{
var c1:Number = C[1][0] + C[1][1];
alphaL = c1 ? X[1] / c1 : 0;
}
alphaR = alphaL;
}
if (alphaL < 1e-6 || alphaR < 1e-6)
alphaL = alphaR = _data[0].distance(_data[_len - 1]) / 3;
_bezier[1] = start.time(alphaL).plus(_bezier[0]);
_bezier[2] = end.time(alphaR).plus(_bezier[3]);
}
private function setControllBezierPoint(ei:int):void
{
var oi:int = 3 - ei;
var result:BezierPoint = BezierPoint.ZERO_POINT;
var den:Number = 0;
for (var i:int = 0; i < _len; i++)
{
var b:Array = bezier(_params[i]);
result = BezierPoint.operate(function(r:Number, b0:Number, b3:Number, bo:Number, p:Number):Number
{
return r + b[ei] * (b[0] * b0 + b[3] * b3 + b[oi] * bo - p);
}, result, _bezier[0], _bezier[3], _bezier[oi], _data[i]);
den -= b[ei] * b[ei];
}
if (den)
{
result = result.time(1 / den);
}
else
{
result = BezierPoint.operate(function(p0:Number, p3:Number):Number
{
return (oi * p0 + ei * p3) / 3;
}, _bezier[0], _bezier[3]);
}
_bezier[ei] = result;
}
private function setParamsByLength():void
{
var i:int;
_params = [0];
for (i = 1; i < _len; i++)
_params[i] = _params[i - 1] + _data[i].distance(_data[i - 1]);
var total:Number = _params[_len - 1];
for (i = 0; i < _len; i++)
_params[i] /= total;
}
private function setup(points:Array, start:BezierPoint, end:BezierPoint):void
{
_bezier = [];
_data = points;
_params = [];
_len = _data.length;
_startTangent = start || BezierPoint.ZERO_POINT;
_endTangent = end || BezierPoint.ZERO_POINT;
_splitBezierPoint = 0;
}
}
import flash.display.DisplayObject;
import flash.geom.Matrix3D;
import flash.geom.Point;
import flash.geom.Vector3D;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.objects.DisplayObject3D;
internal class WanderingTarget extends Point
{
/**
* SEE http://blog.soulwire.co.uk/laboratory/flash/as3-flocking-steering-behaviors
* SOUL WIRE
*/
private var _matrix : Matrix3D;
private var _maxForce : Number;
private var _maxSpeed : Number;
private var _distance : Number;
private var _drawScale : Number;
private var _maxForceSQ : Number;
private var _maxSpeedSQ : Number;
private var _velocity : Vector3D;
private var _position : Vector3D;
private var _oldPosition : Vector3D;
private var _acceleration : Vector3D;
private var _steeringForce : Vector3D;
private var _screenCoords : Point;
private var _renderData : DisplayObject;
private var _edgeBehavior : String;
private var _boundsRadius : Number;
private var _boundsCentre : Vector3D = new Vector3D();
private var _radius : Number = 10.0;
private var _wanderTheta : Number = 0.0;
private var _wanderRadius : Number = 16.0;
private var _wanderDistance : Number = 60.0;
private var _wanderStep : Number = 0.25;
private var _lookAtTarget : Boolean = true;
protected var _config : Object = {
minForce:3.0,
maxForce:6.0,
minSpeed:6.0,
maxSpeed:12.0,
minWanderDistance:10.0,
maxWanderDistance:100.0,
minWanderRadius:5.0,
maxWanderRadius:20.0,
minWanderStep:0.1,
maxWanderStep:0.9,
boundsRadius:250,
numBoids:120
};
public function WanderingTarget()
{
maxForce = 4;//random(_config.minForce, _config.maxForce);
maxSpeed = 10//;random(_config.minSpeed, _config.maxSpeed);
_wanderDistance = 25;//random(_config.minWanderDistance, _config.maxWanderDistance);
_wanderRadius = 15;//random(_config.minWanderRadius, _config.maxWanderRadius);
_wanderStep = 5;//random(_config.minWanderStep, _config.maxWanderStep);
super();
reset();
//super(fov, near, far, useCulling, useProjection);
}
/**
* Generates a random wandering force for the Boid.
* The results of this method can be controlled by the
* _wanderDistance, _wanderStep and _wanderRadius parameters
*
* @param multiplier
*
* By multiplying the force generated by this behavior,
* more or less weight can be given to this behavior in
* comparison to other behaviors being calculated by the
* Boid. To increase the weighting of this behavior, use
* a number above 1.0, or to decrease it use a number
* below 1.0
*/
public function wander( multiplier : Number = 1.0 ) : void
{
_wanderTheta += Math.random() * _wanderStep;
if ( Math.random() < 0.5 )
{
_wanderTheta = -_wanderTheta;
}
var pos : Vector3D = _velocity.clone();
//trace(pos)
pos.normalize();
pos.scaleBy(_wanderDistance);
pos.incrementBy(_position);
var offset : Vector3D = new Vector3D();
offset.x = _wanderRadius * Math.cos(_wanderTheta);
offset.y = _wanderRadius * Math.sin(_wanderTheta);
//offset.z = _wanderRadius * Math.tan(_wanderTheta);
// trace(offset)
//trace(_wanderRadius, _wanderTheta, pos, offset)
_steeringForce = steer(pos.add(offset));
if ( multiplier != 1.0 )
{
_steeringForce.scaleBy(multiplier);
}
// trace(_steeringForce)
_acceleration.incrementBy(_steeringForce);
}
private function steer( target : Vector3D, ease : Boolean = false, easeDistance : Number = 100 ) : Vector3D
{
//trace(_steeringForce,target.clone());
_steeringForce = target.clone();
_steeringForce.decrementBy(_position);
//trace(_steeringForce,target.clone());
_distance = _steeringForce.normalize();
//trace('ab', _distance)
if ( _distance > 0.00001 )
{
if ( _distance < easeDistance && ease )
{
_steeringForce.scaleBy(_maxSpeed * ( _distance / easeDistance ));
}
else
{
_steeringForce.scaleBy(_maxSpeed);
}
_steeringForce.decrementBy(_velocity);
if ( _steeringForce.lengthSquared > _maxForceSQ )
{
_steeringForce.normalize();
_steeringForce.scaleBy(_maxForce);
}
}
//trace(_steeringForce)
return _steeringForce;
}
public function update() : void
{
_oldPosition.x = _position.x;
_oldPosition.y = _position.y;
_oldPosition.z = _position.z;
_velocity.incrementBy(_acceleration);
if ( _velocity.lengthSquared > _maxSpeedSQ )
{
_velocity.normalize();
_velocity.scaleBy(_maxSpeed);
}
_position.incrementBy(_velocity);
x = _position.x;
y = _position.y;
//z = _position.z;
_acceleration.x = 0;
_acceleration.y = 0;
_acceleration.z = 0;
if ( isNaN(_boundsRadius) )
{
trace( "isNaN(_boundsRadius) : " + isNaN(_boundsRadius) );
return;
}
if( !_position.equals(_oldPosition) )
{
var distance : Number = Vector3D.distance(_position, _boundsCentre);
if( distance > _boundsRadius + _radius )
{
/**
* Move the boid to the edge of the boundary
* then invert it's velocity and step it
* forward back into the sphere
*/
_position.decrementBy(_boundsCentre);
_position.normalize();
_position.scaleBy(_boundsRadius + _radius);
_velocity.scaleBy(-1);
_position.incrementBy(_velocity);
_position.incrementBy(_boundsCentre);
}
}
}
/**
* Resets the Boid's position, velocity, acceleration and
* current steering force to zero
*/
public function reset() : void
{
_velocity = new Vector3D();
_position = new Vector3D();
_oldPosition = new Vector3D();
_acceleration = new Vector3D();
_steeringForce = new Vector3D();
_screenCoords = new Point();
}
/**
* The maximum force available to the Boid when
* calculating the steering force produced by
* the Boids steering bahaviors
*/
public function get maxForce() : Number
{
return _maxForce;
}
public function set maxForce( value : Number ) : void
{
if ( value < 0 )
{
value = 0;
}
_maxForce = value;
_maxForceSQ = value * value;
}
/**
* The maximum speed the Boid can reach
*/
public function get maxSpeed() : Number
{
return _maxSpeed;
}
public function set maxSpeed( value : Number ) : void
{
if ( value < 0 )
{
value = 0;
}
_maxSpeed = value;
_maxSpeedSQ = value * value;
}
protected function random( min : Number, max : Number = NaN ) : Number
{
if ( isNaN(max) )
{
max = min;
min = 0;
}
return Math.random() * ( max - min ) + min;
}
/**
* The centrepoint of the Boids bounding sphere.
* If the Boid travels futher than boundsRadius
* from this point the specified edge behavior
* will take affect.
*/
public function get boundsCentre() : Vector3D
{
return _boundsCentre;
}
public function set boundsCentre( value : Vector3D ) : void
{
_boundsCentre = value;
}
/**
* The maximum distance which this Boid can
* travel from it's boundsCentre before the
* specified edge behavior takes affect
*/
public function get boundsRadius() : Number
{
return _boundsRadius;
}
public function set boundsRadius( value : Number ) : void
{
_boundsRadius = value;
}
public function get position():Vector3D
{
return _position;
}
public function set position(value:Vector3D):void
{
_position = value;
}
}