[study] - VERLET
詳解ActionScript3.0アニメーション
ベレ法
/**
* Copyright gaina ( http://wonderfl.net/user/gaina )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/N1Ea
*/
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
/**
* 詳解ActionScript3.0アニメーション
* ベレ法
* @author gaina
*/
public class Square extends Sprite
{
private var _points:Array = [];
private var _sticks:Array = [];
private var _rect:Rectangle;
private var SIDE:int = 24;
private var VERTICAL:int = 12;
private var offsetX:Number;
public function Square()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
_rect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight - 15);
offsetX = stage.stageWidth / SIDE / 2;
//点
for (var i:int = 0; i < SIDE * VERTICAL; i++)
{
var p:VerletPoint = makePoint( (i % SIDE) * stage.stageWidth / SIDE + offsetX, Math.floor(i / SIDE) * stage.stageHeight / VERTICAL);
}
var stick_side:int = (SIDE - 1) * VERTICAL;
var stick_vertical:int = (VERTICAL - 1) * SIDE;
var stick_num:int = stick_side + stick_vertical;
//構造物
for (var j:int = 0; j < stick_num; j++)
{
if (j < stick_side) {
//横の棒
var sw:VerletStick = makeStick(_points[j + (Math.floor(j / (SIDE - 1)))], _points[j + 1 + (Math.floor(j / (SIDE - 1)))]);
}else {
//縦の棒
var sv:VerletStick = makeStick(_points[j - stick_side], _points[j - stick_side + SIDE]);
}
}
addEventListener(Event.ENTER_FRAME, loop);
stage.addEventListener(MouseEvent.CLICK, 崩壊);
}
private function 崩壊(e:MouseEvent):void
{
_points[SIDE * VERTICAL / 2].vy = 10;
}
private function loop(e:Event):void
{
updatePoint();
updateContrain();
updateStick();
graphics.clear();
renderPoint();
renderStick()
}
private function makePoint(posx:Number, posy:Number):VerletPoint
{
var p:VerletPoint = new VerletPoint(posx, posy);
_points.push(p);
return p;
}
private function makeStick(pointA:VerletPoint, pointB:VerletPoint, length:int = -1):VerletStick
{
var s:VerletStick = new VerletStick(pointA, pointB, length);
_sticks.push(s);
return s;
}
private function updatePoint():void
{
for (var i:int = 0; i < _points.length; i++)
{
var p:VerletPoint = _points[i] as VerletPoint;
p.y += 0.5;
p.update();
}
}
private function updateContrain():void
{
for (var i:int = 0; i < _points.length; i++)
{
var p:VerletPoint = _points[i] as VerletPoint;
p.constrain(_rect);
}
}
private function updateStick():void
{
for (var i:int = 0; i < _sticks.length; i++)
{
var s:VerletStick = _sticks[i] as VerletStick;
s.update();
}
}
private function renderPoint():void
{
for (var i:int = 0; i < _points.length; i++)
{
var p:VerletPoint = _points[i] as VerletPoint;
p.render(graphics);
}
}
private function renderStick():void
{
for (var i:int = 0; i < _sticks.length; i++)
{
var s:VerletStick = _sticks[i] as VerletStick;
s.render(graphics);
}
}
}
}
import flash.display.Graphics;
import flash.geom.Rectangle;
/**
* ...
* @author gaina
*/
class VerletPoint
{
public var x:Number;
public var y:Number;
private var _oldx:Number;
private var _oldy:Number;
public function VerletPoint(x:Number,y:Number)
{
setPosition(x, y);
}
public function update():void
{
var _tempX:Number = x;
var _tempY:Number = y;
x += vx;
y += vy;
_oldx = _tempX;
_oldy = _tempY;
}
public function constrain(rect:Rectangle):void
{
x = Math.max(rect.left, Math.min(rect.right, x));
y = Math.max(rect.top, Math.min(rect.bottom, y));
}
private function setPosition(x:Number, y:Number):void
{
this.x = _oldx = x;
this.y = _oldy = y;
}
public function get vx():Number { return x - _oldx; }
public function set vx(value:Number):void
{
_oldx = x - value;
}
public function get vy():Number { return y - _oldy; }
public function set vy(value:Number):void
{
_oldy = y - value;
}
public function render(g:Graphics):void
{
g.beginFill(0);
g.drawCircle(x, y, 5);
g.endFill();
}
}
import flash.display.Graphics;
/**
* ...
* @author gaina
*/
class VerletStick
{
private var _pointA:VerletPoint;
private var _pointB:VerletPoint;
private var _length:Number;
public function VerletStick(pointA:VerletPoint, pointB:VerletPoint, length:Number = -1)
{
_pointA = pointA;
_pointB = pointB;
if (length == -1) {
var dx:Number = _pointB.x - _pointA.x;
var dy:Number = _pointB.y - _pointA.y;
_length = Math.sqrt(dx * dx + dy * dy);
}else {
_length = length;
}
}
public function update():void
{
var dx:Number = _pointB.x - _pointA.x;
var dy:Number = _pointB.y - _pointA.y;
var dist:Number = Math.sqrt(dx * dx + dy * dy);
var diff:Number = _length - dist;
var offsetX:Number = (diff * dx / dist) / 2;
var offsetY:Number = (diff * dy / dist) / 2;
_pointA.x -= offsetX;
_pointA.y -= offsetY;
_pointB.x += offsetX;
_pointB.y += offsetY;
}
public function render(g:Graphics):void
{
g.lineStyle(1);
g.moveTo(_pointA.x, _pointA.y);
g.lineTo(_pointB.x, _pointB.y);
}
}