/**
* Copyright monpu ( http://wonderfl.net/user/monpu )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/97G8
*/
// forked from makc3d's forked from: Dynamic verlet collision with mc?
// forked from bahngoura's Dynamic verlet collision with mc?
// forked from fakestar0826's Verlet Triangle
// forked from fakestar0826's Verlet Method
// one way to do that, not necessary the best
package {
import flash.display.BitmapData;
import flash.events.Event;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.display.Sprite;
import flash.display.MovieClip;
public class FlashTest extends Sprite {
private var _pointA:VerletPoint;
private var _pointB:VerletPoint;
private var _pointC:VerletPoint;
private var _stickA:VerletStick;
private var _stickB:VerletStick;
private var _stickC:VerletStick;
private var _stageRect:BitmapData;
public var ground:MovieClip = new MovieClip();
public function FlashTest() {
// write as3 code here..
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
ground.graphics.beginFill(0xFF0000);
ground.graphics.drawRect(0, 0, 300, 40);
ground.graphics.endFill();
addChild(ground);
ground.x = 100;
ground.y = 300;
ground.rotation = -10;
_stageRect = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0);
_stageRect.draw (ground, ground.transform.matrix);
_pointA = new VerletPoint(100, 100);
_pointB = new VerletPoint(200, 100);
_pointC = new VerletPoint(150, 200);
_stickA = new VerletStick(_pointA, _pointB);
_stickB = new VerletStick(_pointB, _pointC);
_stickC = new VerletStick(_pointC, _pointA);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):void
{
_pointA.y += 0.5;
//_pointA.update();
_pointB.y += 0.5;
//_pointB.update();
_pointC.y += 0.5;
//_pointC.update();
//繰り返しを増やすと剛体に近づく。stickのupdateメソッドにより、点同士の斥力?が働くため
for(var i:int = 0;i < 5;i++)
{
_pointA.constrain(_stageRect);
_pointB.constrain(_stageRect);
_pointC.constrain(_stageRect);
// _stickA.update();
// _stickB.update();
// _stickC.update();
}
graphics.clear();
_pointA.render(graphics);
_pointB.render(graphics);
_pointC.render(graphics);
_stickA.render(graphics);
_stickB.render(graphics);
_stickC.render(graphics);
}
}
}
import flash.display.MovieClip;
import flash.display.Graphics;
import flash.display.BitmapData;
import flash.geom.Rectangle;
class VerletPoint
{
public var x:Number;
public var y:Number;
private var _oldX:Number;
private var _oldY:Number;
public var movieclip:String = new String;
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 setPosition(x:Number, y:Number):void
{
this.x = _oldX = x;
this.y = _oldY = y;
}
public function constrain(bd:BitmapData):void
{
var rect:Rectangle = bd.rect;
x = Math.max(rect.left, Math.min(rect.right, x));
y = Math.max(rect.top, Math.min(rect.bottom, y));
if (hitTestXY (bd, x, y)) {
// now we spiral away from x, y to find unoccupied pixel
for (var i:int = 1; i < 123; i++) {
var j:int;
for (j = -i; j < i; j++) {
if (!hitTestXY (bd, x + j, y - i)) {
x += j; y -= i; return;
}
if (!hitTestXY (bd, x + i, y - j)) {
x += i; y -= j; return;
}
if (!hitTestXY (bd, x - j, y + i)) {
x -= j; y += i; return;
}
if (!hitTestXY (bd, x - i, y + j)) {
x -= i; y += j; return;
}
}
}
}
}
private function hitTestXY (bd:BitmapData, X:int, Y:int):Boolean {
return ((bd.getPixel32 (X, Y) / 0x1000000) > 127);
}
public function set vx(value:Number):void
{
_oldX = x - value;
}
public function get vx():Number
{
return x - _oldX;
}
public function set vy(value:Number):void
{
_oldY = y - value;
}
public function get vy():Number
{
return y - _oldY;
}
public function render(g:Graphics):void
{
g.beginFill(0);
g.drawCircle(x, y, 4);
g.endFill();
}
}
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 = _pointA.x - _pointB.x;
var dy:Number = _pointA.y - _pointB.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)/* it means diff * cos(θ)*/ / 2;
var offsetY:Number = (diff * dy / dist)/* it means diff * sin(θ)*/ / 2;
_pointA.x -= offsetX;
_pointA.y -= offsetY;
_pointB.x += offsetX;
_pointB.y += offsetY;
}
public function render(g:Graphics):void
{
g.lineStyle(0);
g.moveTo(_pointA.x, _pointA.y);
g.lineTo(_pointB.x, _pointB.y);
}
}