/**
* Copyright h_kamizono ( http://wonderfl.net/user/h_kamizono )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/89E6
*/
package {
import flash.display.Sprite;
import flash.utils.Timer;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.events.*;
public class Main extends Sprite {
private var voronoi:Voronoi = new Voronoi();
private var fx:VolumetricPointLight;
public function Main() {
addEventListener(Event.ADDED_TO_STAGE, init);
if(null != stage) init();
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
stage.quality = "medium";
stage.align = "TL";
stage.scaleMode = "noScale";
// Create a VolumetricPointLight object, use the grid as the occlusion object.
fx = new VolumetricPointLight(800, 600, voronoi, [0xc08040, 0x4080c0, 0], [1, 1, 1], [0, 20, 30]);
// You can also specify a single color instead of gradient params, for example:
// fx = new VolumetricPointLight(800, 600, grid, 0xc08040);
// is equivalent to:
// fx = new VolumetricPointLight(800, 600, voronoi, [0xc08040, 0], [1, 1], [0, 255]);
addChild(fx);
// Render on every frame.
fx.startRendering();
}
}
}
class Voronoi extends Sprite {
private var pt:Array = new Array();
private var dotNum:Number = 30;
private var count:Number = 0;
public function Voronoi() {
stage ?
init() :
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
if (e) removeEventListener(Event.ADDED_TO_STAGE, init);
for (var i:Number = 0; i < dotNum; ++i) {
pt.push(new PhysicalPoint(Math.random()*stage.stageWidth, Math.random()*stage.stageHeight));
}
addEventListener(Event.ENTER_FRAME, onEnter);
}
private function onEnter(event:Event):void {
pt[0].setKasokudo((mouseX - pt[0].x)*10, (mouseY - pt[0].y)*10);
for (var i:Number = 0; i < pt.length; ++i) {
for (var j:Number = 0; j < pt.length; ++j) {
if (i != j) {
var dist:Number = Point.distance(pt[j], pt[i]);
dist = Math.max(100 - dist, 0)/100;
var dire:Number = Math.atan2(pt[i].y - pt[j].y, pt[i].x - pt[j].x);
pt[i].setKasokudoByPolar(dist*200, dire);
}
}
if (pt[i].x < 50) pt[i].setKasokudo(500, 0);
if (pt[i].y < 50) pt[i].setKasokudo(0, 500);
if (pt[i].x > stage.stageWidth - 50) pt[i].setKasokudo(-500, 0);
if (pt[i].y > stage.stageHeight - 50) pt[i].setKasokudo(0, -500);
}
// Rectangleは画面の大きさ
var areas:Array = Functions.getVoronoiAreas(pt, new Rectangle(0, 0,
stage.stageWidth, stage.stageHeight));
if (areas != null) {
for (var m:Number = 0; m < areas.length; ++m) {
var cen:Point = Functions.getCentroid(areas[m]);
if (cen != null) {
for (var n:Number = 0; n < areas[m].length; ++n) {
areas[m][n].x += (cen.x - areas[m][n].x)*0.05;
areas[m][n].y += (cen.y - areas[m][n].y)*0.05;
}
}
}
}
this.graphics.clear();
if (areas != null) {
for (var k:Number = 0; k < dotNum>>1; ++k) {
//if (k == 0) {
this.graphics.lineStyle(2, 0x888888);
Functions.fillRing(areas[k], this);
}
}
}
}
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
/**
* The EffectContainer class creates a volumetric light effect (also known as crepuscular or "god" rays).
* This is done in 2D with some bitmap processing of an emission object, and optionally an occlusion object.
*/
class EffectContainer extends Sprite {
/**
* When true a blur filter is applied to the final effect bitmap (can help when colorIntegrity == true).
*/
public var blur:Boolean = false;
/**
* Selects rendering method; when set to true colors won't be distorted and performance will be
* a little worse. Also, this might make the final output appear grainier.
*/
public var colorIntegrity:Boolean = false;
/**
* Light intensity.
*/
public var intensity:Number = 4;
/**
* Number of passes applied to buffer. Lower numbers mean lower quality but better performance,
* anything above 8 is probably overkill.
*/
public var passes:uint = 6;
/**
* Set this to one of the StageQuality constants to use this quality level when drawing bitmaps, or to
* null to use the current stage quality. Mileage may vary on different platforms and player versions.
* I think it should only be used when stage.quality is LOW (set this to BEST to get reasonable results).
*/
public var rasterQuality:String = null;
/**
* Final scale of emission. Should always be more than 1.
*/
public var scale:Number = 2;
/**
* Smooth scaling of the effect's final output bitmap.
*/
public var smoothing:Boolean = true;
/**
* Light source x.
* @default viewport center (set in constructor).
*/
public var srcX:Number;
/**
* Light source y.
* @default viewport center (set in constructor).
*/
public var srcY:Number;
protected var _blurFilter:BlurFilter = new BlurFilter(2, 2);
protected var _emission:DisplayObject;
protected var _occlusion:DisplayObject;
protected var _ct:ColorTransform = new ColorTransform;
protected var _halve:ColorTransform = new ColorTransform(0.5, 0.5, 0.5);
protected var _occlusionLoResBmd:BitmapData;
protected var _occlusionLoResBmp:Bitmap;
protected var _baseBmd:BitmapData;
protected var _bufferBmd:BitmapData;
protected var _lightBmp:Bitmap = new Bitmap;
protected var _bufferSize:uint = 0x8000;
protected var _bufferWidth:uint;
protected var _bufferHeight:uint;
protected var _viewportWidth:uint;
protected var _viewportHeight:uint;
protected var _mtx:Matrix = new Matrix;
/**
* Creates a new effect container.
*
* @param width Viewport width in pixels.
* @param height Viewport height in pixels.
* @param emission A DisplayObject to which the effect will be applied. This object will be
* added as a child of the container. When applying the effect the object's filters and color
* matrix is ignored, if you want to use filters or a color matrix put your content in another
* object and addChild it to this one instead.
* @param occlusion An optional occlusion object, handled the same way as the emission object.
*/
public function EffectContainer(width:uint, height:uint, emission:DisplayObject, occlusion:DisplayObject = null) {
if(!emission) throw(new Error("emission DisplayObject must not be null."));
addChild(_emission = emission);
if(occlusion) addChild(_occlusion = occlusion);
setViewportSize(width, height);
_lightBmp.blendMode = BlendMode.ADD;
addChild(_lightBmp);
srcX = width / 2;
srcY = height / 2;
}
/**
* Sets the container's size. This method recreates internal buffers (slow), do not call this on
* every frame.
*
* @param width Viewport width in pixels
* @param height Viewport height in pixels
*/
public function setViewportSize(width:uint, height:uint):void {
_viewportWidth = width;
_viewportHeight = height;
scrollRect = new Rectangle(0, 0, width, height);
_updateBuffers();
}
/**
* Sets the approximate size (in pixels) of the effect's internal buffers. Smaller number means lower
* quality and better performance. This method recreates internal buffers (slow), do not call this on
* every frame.
*
* @param size Buffer size in pixels
*/
public function setBufferSize(size:uint):void {
_bufferSize = size;
_updateBuffers();
}
protected function _updateBuffers():void {
var aspect:Number = _viewportWidth / _viewportHeight;
_bufferHeight = Math.max(1, Math.sqrt(_bufferSize / aspect));
_bufferWidth = Math.max(1, _bufferHeight * aspect);
dispose();
_baseBmd = new BitmapData(_bufferWidth, _bufferHeight, false, 0);
_bufferBmd = new BitmapData(_bufferWidth, _bufferHeight, false, 0);
_occlusionLoResBmd = new BitmapData(_bufferWidth, _bufferHeight, true, 0);
_occlusionLoResBmp = new Bitmap(_occlusionLoResBmd);
}
/**
* Render a single frame.
*
* @param e In case you want to make this an event listener.
*/
public function render(e:Event = null):void {
var savedQuality:String = stage.quality;
if(rasterQuality) stage.quality = rasterQuality;
var mul:Number = colorIntegrity ? intensity : intensity/(1<<passes);
_ct.redMultiplier = _ct.greenMultiplier = _ct.blueMultiplier = mul;
_drawLoResEmission();
if(_occlusion) _eraseLoResOcclusion();
if(rasterQuality) stage.quality = savedQuality;
var s:Number = 1 + (scale-1) / (1 << passes);
var tx:Number = srcX/_viewportWidth*_bufferWidth;
var ty:Number = srcY/_viewportHeight*_bufferHeight;
_mtx.identity();
_mtx.translate(-tx, -ty);
_mtx.scale(s, s);
_mtx.translate(tx, ty);
_lightBmp.bitmapData = _applyEffect(_baseBmd, _bufferBmd, _mtx, passes);
_lightBmp.width = _viewportWidth;
_lightBmp.height = _viewportHeight;
_lightBmp.smoothing = smoothing;
}
/**
* Draws a scaled-down emission on _baseBmd.
*/
protected function _drawLoResEmission():void {
_copyMatrix(_emission.transform.matrix, _mtx);
_mtx.scale(_bufferWidth / _viewportWidth, _bufferHeight / _viewportHeight);
_baseBmd.fillRect(_baseBmd.rect, 0);
_baseBmd.draw(_emission, _mtx, colorIntegrity ? null : _ct);
}
/**
* Draws a scaled-down occlusion on _occlusionLoResBmd and erases it from _baseBmd.
*/
protected function _eraseLoResOcclusion():void {
_occlusionLoResBmd.fillRect(_occlusionLoResBmd.rect, 0);
_copyMatrix(_occlusion.transform.matrix, _mtx);
_mtx.scale(_bufferWidth / _viewportWidth, _bufferHeight / _viewportHeight);
_occlusionLoResBmd.draw(_occlusion, _mtx);
_baseBmd.draw(_occlusionLoResBmp, null, null, BlendMode.ERASE);
}
/**
* Render the effect on every frame until stopRendering is called.
*/
public function startRendering():void {
addEventListener(Event.ENTER_FRAME, render);
}
/**
* Stop rendering on every frame.
*/
public function stopRendering():void {
removeEventListener(Event.ENTER_FRAME, render);
}
/**
* Low-level workhorse, applies the lighting effect to a bitmap. This function modifies the src and buffer
* bitmaps and it's mtx argument.
*
* @param src The BitmapData to apply the effect on.
* @param buffer Another BitmapData object for temporary storage. Must be the same size as src.
* @param mtx Effect matrix.
* @param passes Number of passes to make.
* @return A processed BitmapData object (supllied in either src or buffer) with final effect output.
*/
protected function _applyEffect(src:BitmapData, buffer:BitmapData, mtx:Matrix, passes:uint):BitmapData {
var tmp:BitmapData;
while(passes--) {
if(colorIntegrity) src.colorTransform(src.rect, _halve);
buffer.copyPixels(src, src.rect, src.rect.topLeft);
buffer.draw(src, mtx, null, BlendMode.ADD, null, true);
mtx.concat(mtx);
tmp = src; src = buffer; buffer = tmp;
}
if(colorIntegrity) src.colorTransform(src.rect, _ct);
if(blur) src.applyFilter(src, src.rect, src.rect.topLeft, _blurFilter);
return src;
}
/**
* Dispose of all intermediate buffers. After calling this the EffectContainer object will be unusable.
*/
public function dispose():void {
if(_baseBmd) _baseBmd.dispose();
if(_occlusionLoResBmd) _occlusionLoResBmd.dispose();
if(_bufferBmd) _bufferBmd.dispose();
_baseBmd = _occlusionLoResBmd = _bufferBmd = _lightBmp.bitmapData = null;
}
protected function _copyMatrix(src:Matrix, dst:Matrix):void {
dst.a = src.a;
dst.b = src.b;
dst.c = src.c;
dst.d = src.d;
dst.tx = src.tx;
dst.ty = src.ty;
}
}
import flash.display.*;
import flash.events.*;
import flash.geom.*;
/**
* VolumetricPointLight creates a simple effect container with a gradient emission pattern.
* The gradient's center is automatically moved to the (srcX, srcY) coordinates
* and it's radius is adjusted to the length of the viewport's diagonal, so if you
* set srcX and srcY to the viewport's center then only half of the gradient colors
* will be used.
*
* <p>This should also perform a little better than EffectContainer.</p>
*/
class VolumetricPointLight extends EffectContainer {
protected var _colors:Array;
protected var _alphas:Array;
protected var _ratios:Array;
protected var _gradient:Shape = new Shape;
protected var _gradientMtx:Matrix = new Matrix;
protected var _gradientBmp:Bitmap = new Bitmap;
protected var _lastSrcX:Number;
protected var _lastSrcY:Number;
protected var _lastIntensity:Number;
protected var _lastColorIntegrity:Boolean = false;
protected var _gradientLoResBmd:BitmapData;
protected var _gradientLoResDirty:Boolean = true;
/**
* Creates a new effect container, with an emission created from the supplied color or gradient.
* The constructor lets you use a shortcut syntax for creating simple single-color gradients.
* @example The shortcut syntax:
* <listing>new VolumetricPointLight(800, 600, occlusion, 0xc08040);</listing>
* @example is equivalent to:
* <listing>new VolumetricPointLight(800, 600, occlusion, [0xc08040, 0], [1, 1], [0, 255]);</listing>
*
* @param width Viewport width in pixels.
* @param height Viewport height in pixels.
* @param occlusion An occlusion object, will be overlayed above the lighting gradient and under the light effect bitmap.
* @param colorOrGradient Either a gradient colors array, or a uint color value.
* @param alphas Will only be used if colorOrGradient is an array. This will be passed to beginGradientFill.
* If not provided alphas will all be 1.
* @param ratios Will only be used if colorOrGradient is an array. This will be passed to
* beginGradientFill. If colorOrGradient is an Array and ratios aren't provided default
* ones will be created automatically.
*/
public function VolumetricPointLight(width:uint, height:uint, occlusion:DisplayObject, colorOrGradient:*, alphas:Array = null, ratios:Array = null) {
if(colorOrGradient is Array) {
_colors = colorOrGradient.concat();
if(!ratios) _ratios = colorOrGradient.map(function(item:*, i:int, arr:Array):int { return 0x100*i/(colorOrGradient.length+i-1) });
if(!alphas) _alphas = _colors.map(function(..._):Number { return 1 });
} else {
_colors = [colorOrGradient, 0];
_ratios = [0, 255];
}
super(width, height, _gradientBmp, occlusion);
if(!occlusion) throw(new Error("An occlusion DisplayObject must be provided."));
if(!(colorOrGradient is Array || colorOrGradient is uint)) throw(new Error("colorOrGradient must be either an Array or a uint."));
}
protected function _drawGradient():void {
var size:Number = 2 * Math.sqrt(_viewportWidth*_viewportWidth + _viewportHeight*_viewportHeight);
_gradientMtx.createGradientBox(size, size, 0, -size/2 + srcX, -size/2 + srcY);
_gradient.graphics.clear();
_gradient.graphics.beginGradientFill(GradientType.RADIAL, _colors, _alphas, _ratios, _gradientMtx);
_gradient.graphics.drawRect(0, 0, _viewportWidth, _viewportHeight);
_gradient.graphics.endFill();
if(_gradientBmp.bitmapData) _gradientBmp.bitmapData.dispose();
_gradientBmp.bitmapData = new BitmapData(_viewportWidth, _viewportHeight, true, 0);
_gradientBmp.bitmapData.draw(_gradient);
}
/**
* Updates the lo-res gradient bitmap if neccesary and copies it to _baseBmd.
*/
override protected function _drawLoResEmission():void {
if(_gradientLoResDirty) {
super._drawLoResEmission();
_gradientLoResBmd.copyPixels(_baseBmd, _baseBmd.rect, _baseBmd.rect.topLeft);
_gradientLoResDirty = false;
} else {
_baseBmd.copyPixels(_gradientLoResBmd, _baseBmd.rect, _baseBmd.rect.topLeft);
}
}
/** @inheritDoc */
override protected function _updateBuffers():void {
super._updateBuffers();
_gradientLoResBmd = new BitmapData(_bufferWidth, _bufferHeight, false, 0);
_gradientLoResDirty = true;
}
/** @inheritDoc */
override public function setViewportSize(width:uint, height:uint):void {
super.setViewportSize(width, height);
_drawGradient();
_gradientLoResDirty = true;
}
/** @inheritDoc */
override public function render(e:Event = null):void {
var srcChanged:Boolean = _lastSrcX != srcX || _lastSrcY != srcY;
if(srcChanged) _drawGradient();
_gradientLoResDirty ||= srcChanged;
_gradientLoResDirty ||= (!colorIntegrity && (_lastIntensity != intensity));
_gradientLoResDirty ||= (_lastColorIntegrity != colorIntegrity);
_lastSrcX = srcX;
_lastSrcY = srcY;
_lastIntensity = intensity;
_lastColorIntegrity = colorIntegrity;
super.render(e);
}
}
import flash.geom.Rectangle;
import flash.display.Sprite;
class Functions {
public static function getCentroid(pt:Array) :Point {
if (pt != null) {
if (pt.length == 0) {
return new Point(0, 0);
} else if (pt.length == 1) {
return new Point(pt[0].x, pt[0].y);
} else if (pt.length == 2) {
return new Point((pt[0].x + pt[1].x)/2, (pt[0].y + pt[1].y)/2);
} else {
var ptSize:Number = pt.length;
// area
var s:Number = pt[0].x * (pt[1].y - pt[ptSize-1].y);
// centroid
var gx:Number = pt[0].y * (pt[ptSize-1].x - pt[1].x) * (pt[ptSize-1].x + pt[0].x + pt[1].x);
var gy:Number = -pt[0].x * (pt[ptSize-1].y - pt[1].y) * (pt[ptSize-1].y + pt[0].y + pt[1].y);
for (var i:Number = 1; i < ptSize - 1; ++i) {
s += pt[i].x * (pt[i+1].y - pt[i-1].y);
gx += pt[i].y * (pt[i-1].x - pt[i+1].x) * (pt[i-1].x + pt[i].x + pt[i+1].x);
gy += -pt[i].x * (pt[i-1].y - pt[i+1].y) * (pt[i-1].y + pt[i].y + pt[i+1].y);
}
s += pt[ptSize - 1].x * (pt[0].y - pt[ptSize - 2].y);
s /= 2;
gx += pt[ptSize-1].y * (pt[ptSize-2].x - pt[0].x) * (pt[ptSize-2].x + pt[ptSize-1].x + pt[0].x);
gy += -pt[ptSize-1].x * (pt[ptSize-2].y - pt[0].y) * (pt[ptSize-2].y + pt[ptSize-1].y + pt[0].y);
gx /= s*6; gy /= s*6;
return new Point(gx, gy);
}
} else {
return null;
}
}
public static function fillRing(pt:Array, sp:Sprite,
col:uint = 0x000000, al:Number = 1) :void {
if (pt.length >= 3) {
sp.graphics.moveTo((pt[pt.length-1].x + pt[0].x)/2,
(pt[pt.length-1].y + pt[0].y)/2);
sp.graphics.beginFill(col, al);
for (var i:Number = 0; i < pt.length; ++i) {
sp.graphics.curveTo(pt[i].x, pt[i].y,
(pt[i].x + pt[(i+1)%pt.length].x)/2, (pt[i].y + pt[(i+1)%pt.length].y)/2);
}
sp.graphics.endFill();
}
}
public static function outerProduct(p0:Point, p1:Point, pt:Point) :Number {
var ret:Number;
var ax:Number = pt.x - p0.x;
var ay:Number = pt.y - p0.y;
var bx:Number = p1.x - p0.x;
var by:Number = p1.y - p0.y;
// Z値だけ返す、p0-p1よりp0-ptが左ならminus,右ならplus
ret = ax*by - bx*ay;
return ret;
}
public static function perpendicularBisector(p0:Point, p1:Point) :Array {
var ret:Array = new Array();
if (p0 != null && p1 != null) {
if (p0.y == p1.y) {
ret.push((p0.x + p1.x)/2);
return ret;
} else {
var slant:Number = -(p1.x - p0.x) / (p1.y - p0.y);
//var cp:Point = new Point((p0.x + p1.x)/2 , (p0.y + p1.y)/2);
//var y:Number = cp.y - slant*cp.x;
var y:Number = (p0.y + p1.y) - slant*(p0.x + p1.x);
y >>= 1;
ret.push(slant); ret.push(y);
return ret;
}
}
return null;
}
public static function calcIntersectionPoint(p0:Point, p1:Point, line:Array) :Point {
if (line != null) {
if (line.length == 1) {
if (p0.x == p1.x) {
if (p0.y == p1.y && line[0] == p0.x) {
return new Point(p0.x, p0.y);
} else {
return null;
}
} else {
var slant:Number = (p1.y - p0.y) / (p1.x - p0.x);
var y:Number = p0.y - slant*p0.x;
var ix:Number = line[0];
var iy:Number = slant*ix + y;
if (iy <= Math.max(p0.y, p1.y) && iy >= Math.min(p0.y, p1.y)) {
return new Point(ix, iy);
} else {
return null;
}
}
} else {
if (p0.x == p1.x) {
var jx:Number = p0.x; var jy:Number = line[0]*jx + line[1];
if (jy <= Math.max(p0.y, p1.y) && jy >= Math.min(p0.y, p1.y)) {
return new Point(jx, jy);
} else {
return null;
}
} else {
var slant2:Number = (p1.y - p0.y) / (p1.x - p0.x);
var y2:Number = p0.y - slant2*p0.x;
//
if (slant2 == line[0]) {
return null;
} else {
var kx:Number = (line[1] - y2) / (slant2 - line[0]);
var ky:Number = slant2*kx + y2;
if (kx <= Math.max(p0.x, p1.x) && kx >= Math.min(p0.x, p1.x)) {
return new Point(kx, ky);
} else {
return null;
}
}
}
}
}
return null;
}
public static function getVoronoiAreas(pt:Array, rect:Rectangle) :Array{
for (var i:Number = 0; i < pt.length; ++i) {
if (pt[i] is Point) {
} else {
return null;
}
}
var ret:Array = new Array();
for (var j:Number = 0; j < pt.length; ++j) {
ret.push(new Array());
ret[ret.length - 1].push(new Point(rect.left, rect.top));
ret[ret.length - 1].push(new Point(rect.right, rect.top));
ret[ret.length - 1].push(new Point(rect.right, rect.bottom));
ret[ret.length - 1].push(new Point(rect.left, rect.bottom));
}
for (var m:Number = 0; m < pt.length; ++m) {
for (var n:Number = 0; n < pt.length; ++n) {
if (m != n) {
var p:Array = perpendicularBisector(pt[m], pt[n]);
var counter:Number = 0;
var isPt:Array = new Array();
var startPtNum:Array = new Array();
for (var k:Number = 0; k < ret[m].length; ++k) {
var pp:Point = calcIntersectionPoint(ret[m][k], ret[m][(k+1)%(ret[m].length)], p);
if (pp != null) {
++counter;
isPt.push(pp);
startPtNum.push(k);
}
}
if (counter == 2) {
var temp0:Array = ret[m].slice(0, startPtNum[0] + 1);
var temp1:Array = ret[m].slice(startPtNum[0] + 1, startPtNum[1] + 1);
var temp2:Array = ret[m].slice(startPtNum[1] + 1);
var temp:Array;
var g1:Number; var g2:Number;
if (temp0 != null) {
if (temp0.length > 0) {
g1 = outerProduct(isPt[0], isPt[1], temp0[0]);
g2 = outerProduct(isPt[0], isPt[1], pt[m]);
if (g1*g2 >= 0) {
temp = temp0.concat([isPt[0]]);
} else {
temp = [isPt[0]];
}
}
}
if (temp1 != null) {
if (temp1.length > 0) {
g1 = outerProduct(isPt[0], isPt[1], temp1[0]);
g2 = outerProduct(isPt[0], isPt[1], pt[m]);
if (g1*g2 >= 0) {
temp = temp.concat(temp1, [isPt[1]]);
} else {
temp = temp.concat([isPt[1]]);
}
}
}
if (temp2 != null) {
if (temp2.length > 0) {
g1 = outerProduct(isPt[0], isPt[1], temp2[0]);
g2 = outerProduct(isPt[0], isPt[1], pt[m]);
if (g1*g2 >= 0) {
temp = temp.concat(temp2);
}
}
}
ret[m] = temp;
}
}
}
}
return ret;
}
}
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.utils.Timer;
class PhysicalPoint extends Point {
private var vx:Number, vy:Number;
private var ax:Number, ay:Number;
private var b:Number;
private var preTime:Number;
private var timer:Timer;
private var preX:Number, preY:Number;
public var kb:Number;
public var angle:Number;
public var preAngle:Number;
public var kakusokudo:Number;
public var kakukasokudo:Number;
private var limitter:Number = 0.3;
function PhysicalPoint(xx: Number = 0, yy:Number = 0, an:Number = 0) {
x = xx; y = yy;
preX = xx; preY = yy;
b = 0.9;
vx = 0; vy = 0;
ax = 0; ay = 0;
angle = an;
preAngle = an;
kb = 0.9;
kakusokudo = 0;
kakukasokudo = 0;
preTime = new Date().getTime();
timer = new Timer(33);
timer.addEventListener(TimerEvent.TIMER, loop);
timer.start();
}
public function loop(event:TimerEvent) :void {
var nowTime:Number = new Date().getTime();
var t:Number = (nowTime - preTime)/1000;
if (t > limitter) t = limitter;
preX = x;
preY = y;
x += (vx + 0.5*ax*t)*t;
y += (vy + 0.5*ay*t)*t;
vx += ax*t; vy += ay*t;
vx *= b; vy *= b;
ax = 0; ay = 0;
preAngle = angle;
angle += (kakusokudo + 0.5*kakukasokudo*t) *t;
kakusokudo += kakukasokudo*t;
kakusokudo *= kb;
kakukasokudo = 0;
preTime = nowTime;
}
public function setKasokudo(aax:Number = 0, aay:Number = 0) :void {
ax += aax;
ay += aay;
}
public function setKasokudoByPolar(r:Number=0, dire:Number = 0) :void {
ax += r*Math.cos(dire);
ay += r*Math.sin(dire);
}
public function setKakuKasokudo(aan:Number = 0) :void {
kakukasokudo += aan;
}
public function setKakuKasokudo2(dire:Number, val:Number) :void {
var aan:Number = val * Math.sin(dire - angle);
setKakuKasokudo(aan);
}
}