forked from: loco roco v0.2 (改造PuyoDot)
改造 from http://wonderfl.net/c/kwty
too many changes are made, i'll say it's more than fork
i think i should keep most of the original comments
thanks @tail_y @http://wonderfl.net/user/tail_y
zonnbe@2010
PuyoDot
プヨっとしたドット。
下のほうにあるパレットから拾ってきて表示するよ。
ぐりぐりしたり、引っ張ったり、新しいドット絵を追加して遊んでね。
(マップが意外と見ずらくなった。wonderflって等倍フォントじゃないんだね
等倍のテキストエディタか何かで編集すると楽かも)
本当はドットを編集する機能も入れたかったんだけど
力尽きるどころの話じゃなかったから今回は諦めた。
でもいつか作りたいね。
ドット状、任意外形の弾性体を表現します。
こういう、ぐにぐにしたものは、各頂点をテンションで繋ぐfladdict式が一番軽くて綺麗なのですが、
そうすると自由な形にはしにくいという欠点があります。
今回の手法では、小さな点が、バネで繋がっているモデルをしており、一部が欠けてもそれらしい動作をします。
バネは回転方向への力も持ち、隣の点を、距離だけではなく正常な角度に保とうとします。
欠点として、点の数が多くなるため圧倒的に重いことと
力の伝わり方が遅いため、伸びやすい物体になってしまうことです。
前者はリファクタリングしていく必要があります。
後者は、今回解決のために点を2個先まで接続する手法をとりました。
キング・カズマのドットバージョンを入れたかったんだけど
16x32ドットは重くなりすぎて断念。
軽量化して、そのくらいは動くようになりたい。
/**
* Copyright harada0523 ( http://wonderfl.net/user/harada0523 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/sVNR
*/
// forked from zonnbe's loco roco v0.2 (改造PuyoDot)
/**
*
* 改造 from http://wonderfl.net/c/kwty
* too many changes are made, i'll say it's more than fork
* i think i should keep most of the original comments
*
* thanks @tail_y @http://wonderfl.net/user/tail_y
*
* zonnbe@2010
*/
package
{
/*
PuyoDot
プヨっとしたドット。
下のほうにあるパレットから拾ってきて表示するよ。
ぐりぐりしたり、引っ張ったり、新しいドット絵を追加して遊んでね。
(マップが意外と見ずらくなった。wonderflって等倍フォントじゃないんだね
等倍のテキストエディタか何かで編集すると楽かも)
本当はドットを編集する機能も入れたかったんだけど
力尽きるどころの話じゃなかったから今回は諦めた。
でもいつか作りたいね。
*/
/*
ドット状、任意外形の弾性体を表現します。
こういう、ぐにぐにしたものは、各頂点をテンションで繋ぐfladdict式が一番軽くて綺麗なのですが、
そうすると自由な形にはしにくいという欠点があります。
今回の手法では、小さな点が、バネで繋がっているモデルをしており、一部が欠けてもそれらしい動作をします。
バネは回転方向への力も持ち、隣の点を、距離だけではなく正常な角度に保とうとします。
欠点として、点の数が多くなるため圧倒的に重いことと
力の伝わり方が遅いため、伸びやすい物体になってしまうことです。
前者はリファクタリングしていく必要があります。
後者は、今回解決のために点を2個先まで接続する手法をとりました。
キング・カズマのドットバージョンを入れたかったんだけど
16x32ドットは重くなりすぎて断念。
軽量化して、そのくらいは動くようになりたい。
*/
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.GradientType;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageQuality;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.system.LoaderContext;
import flash.net.URLRequest;
import flash.utils.*;
import flash.ui.Keyboard;
import frocessing.color.ColorHSV;
import com.bit101.components.PushButton;
import net.hires.debug.Stats;
public class PuyoDot3 extends Sprite
{
public static const STAGE_W:uint = 465;
public static const STAGE_H:uint = 465;
private static const _WALL_LEFT:Number = 0;
private static const _WALL_RIGHT:Number = 465;
private static const _GROUND_LINE:Number = 350;
// パーティクル
//private var _dotMap:DotMap;
private var _particleList:Array = []; //:Array :Particle
private var _particleDistance:int;
private var _w:int;
private var _h:int;
// ドラッグ
private var _dragIdX:int = -1;
private var _dragIdY:int = -1;
// レイヤー
private var _bgLayer:Bitmap;
private var _displayLayer:Bitmap;
private var _debugLayer:Sprite;
private var _debugDisplayList:Array = [];
private var _dragLayer:Sprite;
private var _dragList:Array = [];
// ビットマップ
private var _clearBitmap:BitmapData = new BitmapData(STAGE_W, STAGE_H, true, 0x00000000);
private var _displayBitmap:BitmapData = new BitmapData(STAGE_W, STAGE_H);
private var _bgBitmap:BitmapData = new BitmapData(STAGE_W, STAGE_H);
private var _gradiationBitmap:BitmapData = new BitmapData(STAGE_W, STAGE_H);
private var _reflectAlphaBitmap:BitmapData = new BitmapData(STAGE_W, STAGE_H, true, 0x00000000);
private var _rect:Rectangle = new Rectangle(0, 0, STAGE_W, STAGE_H);
private var _point:Point = new Point();
private var _refrectPoint:Point = new Point(0, -2*_GROUND_LINE + STAGE_H);
private var blobPuyos:Vector.<BlobPuyo> = new Vector.<BlobPuyo>(0, false);
//plastic surgery
public var GRAPHIC_URL:String = "http://nullurban.appspot.com/loco3.png";
private var loader :Loader;
private var bmpd :BitmapData;
private var mouth_bmpd :BitmapData;
private var mouth2_bmpd :BitmapData;
private var eyes_bmpd :BitmapData;
private var hair_bmpd :BitmapData;
private var blobsMouth :Vector.<Bitmap> = new Vector.<Bitmap>(0, false);
private var blobsFace :Vector.<MovieClip> = new Vector.<MovieClip>(0, false);
private var blobsEyes :Vector.<MovieClip> = new Vector.<MovieClip>(0, false);
private var vcolor:ColorHSV = new ColorHSV(0,0.6,1,0.5);
private var fps:int = 2;
public function PuyoDot3()
{
addEventListener(Event.ADDED_TO_STAGE, initGRAPHIC); // flexBuilderとの互換性。
}
private function initGRAPHIC(e:Event):void { // ここから開始
removeEventListener(Event.ADDED_TO_STAGE, initGRAPHIC);
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, init);
loader.load(new URLRequest(GRAPHIC_URL), new LoaderContext(true));
}
private function init(e:Event):void
{
//prepare organs
bmpd = Bitmap(loader.content).bitmapData;
mouth_bmpd = new BitmapData(7, 7, true, 0x0);
mouth_bmpd.copyPixels(bmpd, new Rectangle(17,0,7,7), new Point());
mouth2_bmpd = new BitmapData(7, 7, true, 0x0);
mouth2_bmpd.copyPixels(bmpd, new Rectangle(24,0,3,7), new Point(3,0));
eyes_bmpd = new BitmapData(17, 7, true, 0x0);
eyes_bmpd.copyPixels(bmpd, new Rectangle(0,0,17,7), new Point());
hair_bmpd = new BitmapData(25, 13, true, 0x0);
hair_bmpd.copyPixels(bmpd, new Rectangle(0,8,25,14), new Point());
// SWF設定
stage.frameRate = 60;
////v0.2
stage.quality = StageQuality.HIGH; //LOW
var bg:Sprite = new Sprite(); // wonderflではキャプチャに背景色が反映されないので、背景色Spriteで覆う。
bg.graphics.beginFill(0xaaaaaa);
bg.graphics.drawRect(0, 0, STAGE_W, STAGE_H);
addChild(bg);
addChild(_bgLayer = new Bitmap(_bgBitmap));
addChild(_displayLayer = new Bitmap(_displayBitmap));
addChild(_debugLayer = new Sprite());
addChild(_dragLayer = new Sprite());
_debugLayer.visible = false;
_bgLayer.scaleY = -1;
_bgLayer.y = STAGE_H;
////v0.2
var I:int = 0;
var J:int = 0;
var K:int = 0;
var VX:Number = 0;
var VY:Number = 0;
var TRADIUS:Number = 0;
var CRADIUS:Number = 0;
for(I = 0; I < 3; I++)
{
addBlob(I);
}
// デバッグ表示
//debugInit();
displayInit();
var panel:Sprite = new Sprite();
addChild(panel);
new PushButton(panel, stage.stageWidth-85, 5, "add blob", addMoreBlob).setSize(80, 16);
// フレームの処理を登録
addEventListener(Event.ENTER_FRAME, frame);
// マウスドラッグ
//stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpEvent());
////v0.2
stage.addEventListener(MouseEvent.MOUSE_DOWN, onmouseDown);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onmouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP , onmouseUp );
stage.addEventListener(KeyboardEvent.KEY_DOWN, onkeyDown);
addChild(new Stats());
}
private function onkeyDown(e:KeyboardEvent):void
{
if(e.keyCode==Keyboard.UP)
{
if(++fps>3) fps = 1;
stage.frameRate = fps * 30;
}
}
private function addMoreBlob(...arg):void
{
addBlob(blobPuyos.length);
}
private function addBlob(id:int):void
{
vcolor.h = Math.random()*100;
var plastic_organs:Bitmap;
blobsFace.push(new MovieClip());
addChild(blobsFace[id]);
// plastic surgery
plastic_organs = new Bitmap(hair_bmpd.clone());
transformColor(plastic_organs.bitmapData, vcolor.value);
plastic_organs.x = -hair_bmpd.width/2; plastic_organs.y = -hair_bmpd.height*0.9;
blobsFace[id].addChild(plastic_organs);
//eye
blobsEyes.push(new MovieClip());
plastic_organs = new Bitmap(eyes_bmpd);
blobsEyes[id].addChild(plastic_organs);
plastic_organs.y = -eyes_bmpd.height/2;
blobsEyes[id].x = -eyes_bmpd.width/2; blobsEyes[id].y = 3+eyes_bmpd.height/2;
blobsFace[id].addChild(blobsEyes[id]);
//mouth
plastic_organs = new Bitmap(mouth_bmpd);
plastic_organs.x = -mouth_bmpd.width/2; plastic_organs.y = eyes_bmpd.height+3;
blobsFace[id].addChild(plastic_organs);
blobsMouth.push(plastic_organs);
blobPuyos.push(new BlobPuyo(vcolor.value, 50+Math.random()*365, 50, 30 + Math.random()*5));
blobPuyos[id].blink = Math.random() * 3000;
}
private function transformColor(bmd:BitmapData, c:uint):void
{
var i:int = 0;
var to_R:uint = (c & 0xFF0000);
var to_G:uint = (c & 0x00FF00);
var to_B:uint = (c & 0x0000FF);
var paletteR:Array = [];
var paletteG:Array = [];
var paletteB:Array = [];
var r:Number;
for (i = 0; i < 256; i++) {
paletteR[i] = (to_R);
paletteG[i] = (to_G);
paletteB[i] = (to_B);
}
bmd.paletteMap(hair_bmpd, hair_bmpd.rect, hair_bmpd.rect.topLeft, paletteR, paletteG, paletteB);
}
// フレーム挙動
private function frame(event:Event):void{
/*
for (var i:int=0; i<_DERIVATION; i++){
rotate(); // 回転の計算
force(); // 力の計算
move(); // 移動処理
}
calcMID();
/**/
//debugDraw();
var i:int = 0;
var j:int = 0;
var d:int = 0;
//for (var d:int=0; d<GB._DERIVATION; d++){
for (d=0; d<1; d++){
//calculate diff
for(i = 0; i<blobPuyos.length; i++)
blobPuyos[i].setup();
//check contacts
for(i = 0; i<blobPuyos.length; i++)
for(j = 0; j <blobPuyos.length; j++)
if(i != j)
blobPuyos[i].xcontact(blobPuyos[j]);
/**/
//response
for(i = 0; i<blobPuyos.length; i++)
blobPuyos[i].update();
}
draw(); // 描画処理
}
private var _drawShape:Shape = new Shape();
private function displayInit():void{
var g:Graphics = _drawShape.graphics;
g.clear();
var matrix:Matrix = new Matrix();
matrix.createGradientBox(STAGE_W, STAGE_H, Math.PI / 2, 0, 0);
g.beginGradientFill(GradientType.LINEAR, [0xa3a3a3, 0x676767], [1, 1], [0, 255], matrix);
g.drawRect(0, 0, STAGE_W, STAGE_H);
_gradiationBitmap.draw(_drawShape);
g.clear();
g.beginGradientFill(GradientType.LINEAR, [0x000000, 0x000000], [0, 0.7], [125, 230], matrix);
g.drawRect(0, 0, STAGE_W, STAGE_H);
_reflectAlphaBitmap.draw(_drawShape);
}
private function draw():void{
var g:Graphics = _drawShape.graphics;
var particle:Particle;
g.clear();
////v0.2
//g.lineStyle(0.1, 0xFF0000);
var I:int = 0;
var J:int = 0;
var K:int = 0;
/*
g.moveTo(_VERTS[0].x, _VERTS[0].y);
for(I = 0; I < _VERTS.length; I++)
{
J = (I+1)%_VERTS.length;
g.lineTo(_VERTS[J].x, _VERTS[J].y);
//g.moveTo(_VERTS[I].x, _VERTS[I].y);
//g.lineTo(CENT_PARTICLE.x, CENT_PARTICLE.y);
}
/**/
var BVI:Particle;
var BPI:Particle;
for(I = 0; I < blobPuyos.length; I++)
{
BVI = blobPuyos[I]._VERTS[blobPuyos[I].head];
BPI = blobPuyos[I].pvn[blobPuyos[I].head];
blobsFace[I].x = BVI.x;
blobsFace[I].y = BVI.y;
blobsFace[I].rotation = Math.atan2(BPI.y, BPI.x)/(Math.PI/180) - 90;
if(blobPuyos[I]._DRAG_ID!=-1)
blobsMouth[I].bitmapData = mouth2_bmpd;
else
blobsMouth[I].bitmapData = mouth_bmpd;
if(int((blobPuyos[I].blink+getTimer())%3000)<200) blobsEyes[I].scaleY = ((blobPuyos[I].blink+getTimer())%200)/200;
g.beginFill(blobPuyos[I].color);
g.moveTo(blobPuyos[I]._MIDS[0].x, blobPuyos[I]._MIDS[0].y);
for(J = 0;J < blobPuyos[I]._VERTS.length; J++)
{
K = (J+1) % blobPuyos[I]._VERTS.length;
g.curveTo(blobPuyos[I]._VERTS[K].x, blobPuyos[I]._VERTS[K].y, blobPuyos[I]._MIDS[K].x, blobPuyos[I]._MIDS[K].y);
}
g.endFill();
}
/**/
_displayBitmap.copyPixels(_clearBitmap, _rect, _point);
_displayBitmap.draw(_drawShape);
_bgBitmap.copyPixels(_gradiationBitmap, _rect, _point);
_bgBitmap.copyPixels(_displayBitmap, _rect, _refrectPoint, _reflectAlphaBitmap, _point, true);
}
////v0.2
private function onmouseDown(e:MouseEvent):void
{
var I:int = 0;
for(I = 0; I < blobPuyos.length; I++)
{
blobPuyos[I].detectDrag(mouseX, mouseY);
}
}
private function onmouseMove(e:MouseEvent):void
{
var I:int = 0;
for(I = 0; I < blobPuyos.length; I++)
{
blobPuyos[I].moveDrag(mouseX, mouseY);
}
}
private function onmouseUp(e:MouseEvent):void
{
var I:int = 0;
for(I = 0; I < blobPuyos.length; I++)
{
blobPuyos[I].cancelDrag();
}
}
}
}
class BlobPuyo {
//EXXXXXTRA!!!!
private var _OLD_PARTICLE_AREA :Number = 0;
private var VERT_COUNT :int = 16;
public var RADIUS :Number = 30;
public var _VERTS :Vector.<Particle> = new Vector.<Particle>(0, false);
public var _MIDS :Vector.<Particle> = new Vector.<Particle>(0, false);
//private var _VERT_DISTANCE :Number = 0;
//private var _CENT_DISTANCE :Number = 0;
public var _DRAG_ID :int = -1;
//private var _CENTERX :Number = stage.stageWidth/2;
//private var _CENTERY :Number = 50;
public var CENT_PARTICLE :Particle = new Particle(); //SPECIAL, center of blob
public var d :Vector.<Particle> = new Vector.<Particle>(0, false);
public var disp :Vector.<Particle> = new Vector.<Particle>(0, false);
public var cdiv :int = 0;
public var fdiv :Vector.<int> = new Vector.<int>(0, false);
public var pvn :Vector.<Particle> = new Vector.<Particle>(0, false);
public var sd :Number = 0.3;
private var mouse_x:Number = 0;
private var mouse_y:Number = 0;
public var blink:Number = 0;
public var color:uint = 0;
public var head:int = 0;
public function BlobPuyo(c:uint, px:Number, py:Number, ra:Number = 30, v:int = 16) {
color = c;
VERT_COUNT = v;
CENT_PARTICLE.x = px;
CENT_PARTICLE.y = py;
RADIUS = ra;
// constructor code
var D_RAD:Number = GB._RADIAN360 / VERT_COUNT;
var I:int = 0;
var J:int = 0;
var K:int = 0;
var VX:Number = 0;
var VY:Number = 0;
var TRADIUS:Number = 0;
var CRADIUS:Number = 0;
switch(int(Math.random()*5))
{
case 0:
//ピーナッツ
head = 4;
for(I = 0; I < VERT_COUNT; I++)
{
CRADIUS = Math.abs(Math.abs(I*D_RAD)%(Math.PI)-(Math.PI/2));
TRADIUS = RADIUS*1/2 + (RADIUS*1/2 * (CRADIUS)/(Math.PI/2));
VX = CENT_PARTICLE.x + Math.cos(I*D_RAD) * TRADIUS;
VY = CENT_PARTICLE.y + Math.sin(I*D_RAD) * TRADIUS;
_VERTS.push(new Particle(VX, VY));
_MIDS.push(new Particle());
d.push(new Particle(0, 0));
disp.push(new Particle(0, 0));
fdiv.push(0);
pvn.push(new Particle());
}
/**/
break;
case 1:
//三角
head = 5;
for(I = 0; I < VERT_COUNT; I++)
{
CRADIUS = Math.abs(Math.abs(I*D_RAD)%(Math.PI*2/3)-(Math.PI/3));
TRADIUS = RADIUS*3/4 + (RADIUS*1/4 * (CRADIUS)/(Math.PI/3));
VX = CENT_PARTICLE.x + Math.cos(I*D_RAD) * TRADIUS;
VY = CENT_PARTICLE.y + Math.sin(I*D_RAD) * TRADIUS;
_VERTS.push(new Particle(VX, VY));
_MIDS.push(new Particle());
d.push(new Particle(0, 0));
disp.push(new Particle(0, 0));
fdiv.push(0);
pvn.push(new Particle());
}
/**/
break;
case 2:
//方
head = 4;
for(I = 0; I < VERT_COUNT; I++)
{
CRADIUS = Math.abs(Math.abs(I*D_RAD)%(Math.PI/2)-(Math.PI/4));
TRADIUS = RADIUS*3/4 + (RADIUS/4 * (Math.PI/4-CRADIUS)/(Math.PI/4));
VX = CENT_PARTICLE.x + Math.cos(I*D_RAD+Math.PI/4) * TRADIUS;
VY = CENT_PARTICLE.y + Math.sin(I*D_RAD+Math.PI/4) * TRADIUS;
_VERTS.push(new Particle(VX, VY));
_MIDS.push(new Particle());
d.push(new Particle(0, 0));
disp.push(new Particle(0, 0));
fdiv.push(0);
pvn.push(new Particle());
}
/**/
break;
case 3:
//円
head = 0;
for(I = 0; I < VERT_COUNT; I++)
{
VX = CENT_PARTICLE.x + Math.cos(I*D_RAD) * RADIUS;
VY = CENT_PARTICLE.y + Math.sin(I*D_RAD) * RADIUS;
_VERTS.push(new Particle(VX, VY));
_MIDS.push(new Particle());
d.push(new Particle(0, 0));
disp.push(new Particle(0, 0));
fdiv.push(0);
pvn.push(new Particle());
}
/**/
break;
case 4:
//星
head = 0;
for(I = 0; I < VERT_COUNT; I++)
{
CRADIUS = Math.abs(Math.abs(I*D_RAD)%(Math.PI*2/5)-(Math.PI/5));
TRADIUS = RADIUS*1/2 + (RADIUS*1/2 * (CRADIUS)/(Math.PI/5));
VX = CENT_PARTICLE.x + Math.cos(I*D_RAD) * TRADIUS;
VY = CENT_PARTICLE.y + Math.sin(I*D_RAD) * TRADIUS;
_VERTS.push(new Particle(VX, VY));
_MIDS.push(new Particle());
d.push(new Particle(0, 0));
disp.push(new Particle(0, 0));
fdiv.push(0);
pvn.push(new Particle());
}
/**/
break;
}
_VERTS.fixed = true;
_MIDS.fixed = true;
d.fixed = true;
disp.fixed = true;
fdiv.fixed = true;
pvn.fixed = true;
var NEXT_PARTICLE:Particle;
var PREV_PARTICLE:Particle;
var CURR_PARTICLE:Particle;
var TARR:Array;
for(I = 0; I < VERT_COUNT; I++)
{
J = (VERT_COUNT+I-1)%VERT_COUNT; //PREV
K = (I+1)%VERT_COUNT
CURR_PARTICLE = _VERTS[I];
PREV_PARTICLE = _VERTS[J];
NEXT_PARTICLE = _VERTS[K];
CURR_PARTICLE.upRADIAN = calcRADIAN (CENT_PARTICLE, CURR_PARTICLE);
CURR_PARTICLE.downRADIAN = calcRADIAN (CURR_PARTICLE, CENT_PARTICLE);
CURR_PARTICLE.nextRADIAN = calcRADIAN (CURR_PARTICLE, NEXT_PARTICLE);
CURR_PARTICLE.prevRADIAN = calcRADIAN (CURR_PARTICLE, PREV_PARTICLE);
CURR_PARTICLE.hDISTANCE = calcDISTANCE(CURR_PARTICLE, NEXT_PARTICLE);
CURR_PARTICLE.vDISTANCE = calcDISTANCE(CURR_PARTICLE, CENT_PARTICLE);
TARR = [CURR_PARTICLE, NEXT_PARTICLE, CENT_PARTICLE];
CURR_PARTICLE.AREA = calcAREA(TARR); //FOR GAS
}
}
private function calcRADIAN(PA:*, PB:*):Number { return Math.atan2(PB.y - PA.y, PB.x - PA.x); }
private function calcDISTANCE(PA:*, PB:*):Number
{
var VX:Number = PB.x - PA.x;
var VY:Number = PB.y - PA.y;
return Math.sqrt(VX*VX+VY*VY);
}
private function calcMID():void
{
var I:int = 0;
var J:int = 0;
for (I=0; I<_VERTS.length; I++)
{
J = (I+1) % _VERTS.length;
_MIDS[I].x = (_VERTS[I].x+_VERTS[J].x)/2;
_MIDS[I].y = (_VERTS[I].y+_VERTS[J].y)/2;
}
}
////v0.1
private function calcAREA(arr:Array):Number
{
var a:Number=0;
var n1:*;
var n2:*;
for (var i:int=0; i<arr.length; i++)
{
n1 = arr[i];
n2 = arr[(i+1)%arr.length];
a += (n1.x-n2.x)*(n1.y+n2.y);
}
return a/2;
}
private function vertexNORMAL(np:*, n:*, nn:*):Particle
{
var dpx:Number=np.x-n.x;
var dpy:Number=np.y-n.y;
var dnx:Number=nn.x-n.x;
var dny:Number=nn.y-n.y;
var nx:Number=-dny;
var ny:Number=dnx;
var na:Number=Math.sqrt(nx*nx+ny*ny);
if (na==0)
{
nx=1; ny=0;
} else {
nx/=na; ny/=na;
}
//rotate dp anti-clockwise by 90C
var px:Number=dpy;
var py:Number=-dpx;
var pa:Number=Math.sqrt(px*px+py*py);
if (pa==0)
{
px=1; py=0;
} else {
px/=pa; py/=pa;
}
var fx:Number=nx+px;
var fy:Number=ny+py;
var fa:Number=Math.sqrt(fx*fx+fy*fy);
if (fa==0)
{
fx=1; fy=0;
} else {
fx/=fa; fy/=fa;
}
return new Particle(fx,fy);
}
// ボーンの向きを決定する
private function rotate():void{
///v0.2
var I:int = 0;
var J:int = 0;
var CURR_PARTICLE:Particle;
var NEXT_PARTICLE:Particle;
for(I = 0; I < _VERTS.length; I++)
{
J = (I+1)%_VERTS.length;
CURR_PARTICLE = _VERTS[I];
NEXT_PARTICLE = _VERTS[J];
calcConnectRForce(CURR_PARTICLE, NEXT_PARTICLE, CURR_PARTICLE.nextRADIAN);
calcConnectRForce(NEXT_PARTICLE, CURR_PARTICLE, NEXT_PARTICLE.prevRADIAN);
calcConnectRForce(CURR_PARTICLE, CENT_PARTICLE, CURR_PARTICLE.downRADIAN);
calcConnectRForce(CENT_PARTICLE, CURR_PARTICLE, CURR_PARTICLE.upRADIAN );
if (_DRAG_ID == I)
CURR_PARTICLE.vr *= GB._MOUSE_ROTATE_FRICTION;
else
CURR_PARTICLE.vr *= GB._ROTATE_FRICTION; // 摩擦
CURR_PARTICLE.radian += CURR_PARTICLE.vr;
}
CENT_PARTICLE.vr *= GB._ROTATE_FRICTION;
CENT_PARTICLE.radian += CENT_PARTICLE.vr;
}
// 接続されたパーツの回転方向を計算する
private function calcConnectRForce(particle:Particle, targetParticle:Particle, connectAngle:Number):void{
var angle:Number = Math.atan2(targetParticle.y - particle.y, targetParticle.x - particle.x);
particle.vr += ajustRadian(angle - (connectAngle + particle.radian)) * GB._ROTATION_RATE;
}
private function force():void{
////v0.2
var I:int = 0;
var J:int = 0;
var K:int = 0;
var CURR_PARTICLE:Particle;
var NEXT_PARTICLE:Particle;
//var TARR:Array;
var NEW_PARTICLE_AREA:Number = 0;
var GAS_PRESSURE:Number = 0;
var PREV_PARTICLE:Particle;
var VERT_PARTICLE:Particle;
var FCOMP:Number = 0;
var AREA_DIFF:Number = 0;
for(I = 0; I < _VERTS.length; I++)
{
CURR_PARTICLE = _VERTS[I];
NEXT_PARTICLE = _VERTS[(I+1)%_VERTS.length];
var TARR:Array = [CURR_PARTICLE, NEXT_PARTICLE, CENT_PARTICLE];
NEW_PARTICLE_AREA = calcAREA(TARR); //FOR GAS
AREA_DIFF = NEW_PARTICLE_AREA - CURR_PARTICLE.AREA;
FCOMP = (AREA_DIFF>100 || AREA_DIFF<-100)?0.00333:GB._COMP;
GAS_PRESSURE = (AREA_DIFF)*FCOMP/TARR.length;
for (J = 0; J < TARR.length; J++)
{
PREV_PARTICLE = TARR[(TARR.length+J-1)%TARR.length];
CURR_PARTICLE = TARR[J];
NEXT_PARTICLE = TARR[(J+1)%TARR.length];
VERT_PARTICLE = vertexNORMAL(PREV_PARTICLE,CURR_PARTICLE,NEXT_PARTICLE);
CURR_PARTICLE.vx += VERT_PARTICLE.x*GAS_PRESSURE;
CURR_PARTICLE.vy += VERT_PARTICLE.y*GAS_PRESSURE;
}
/**/
PREV_PARTICLE = _VERTS[(_VERTS.length+I-1)%_VERTS.length];
CURR_PARTICLE = _VERTS[I];
NEXT_PARTICLE = _VERTS[(I+1)%_VERTS.length];
VERT_PARTICLE = vertexNORMAL(PREV_PARTICLE,CURR_PARTICLE,NEXT_PARTICLE);
pvn[I].x = VERT_PARTICLE.x;
pvn[I].y = VERT_PARTICLE.y;
calcConnectFoce(CURR_PARTICLE, NEXT_PARTICLE, CURR_PARTICLE.nextRADIAN, CURR_PARTICLE.hDISTANCE, I, (I+1)%_VERTS.length);
calcConnectFoce(NEXT_PARTICLE, CURR_PARTICLE, NEXT_PARTICLE.prevRADIAN, CURR_PARTICLE.hDISTANCE, (I+1)%_VERTS.length, I);
calcConnectFoce(CURR_PARTICLE, CENT_PARTICLE, CURR_PARTICLE.downRADIAN, CURR_PARTICLE.vDISTANCE, I, -1);
calcConnectFoce(CENT_PARTICLE, CURR_PARTICLE, CURR_PARTICLE.upRADIAN , CURR_PARTICLE.vDISTANCE, -1, I);
CURR_PARTICLE.ay += GB._GRAVITY;
if (_DRAG_ID == I){ // マウスで引っ張る
var point:Particle = pullForce(CURR_PARTICLE.x, CURR_PARTICLE.y, mouse_x, mouse_y, GB._MOUSE_PULL_RATE);
CURR_PARTICLE.ax += point.x;
CURR_PARTICLE.ay += point.y;
CURR_PARTICLE.vx *= GB._MOUSE_MOVE_FRICTION;
CURR_PARTICLE.vy *= GB._MOUSE_MOVE_FRICTION;
}
}
CENT_PARTICLE.ay += GB._GRAVITY;
}
// 接続された2パーツの力を計算する
private function calcConnectFoce(particle:Particle, targetParticle:Particle, connectAngle:Number, distance:Number, A:int, B:int):void{
var toAngle:Number = ajustRadian(connectAngle + particle.radian);
var toX:Number = particle.x + Math.cos(toAngle) * distance;
var toY:Number = particle.y + Math.sin(toAngle) * distance;
var ax:Number = (targetParticle.x - toX) * GB._VERTICAL_RATE;
var ay:Number = (targetParticle.y - toY) * GB._VERTICAL_RATE;
particle.ax += ax;
particle.ay += ay;
if(A<0)
{
cdiv++;
} else {
fdiv[A]++;
}
/**/
targetParticle.ax -= ax;
targetParticle.ay -= ay;
if(B<0)
{
cdiv++;
} else {
fdiv[B]++;
}
/**/
}
// radian角度を、-π~πの範囲に修正する
private function ajustRadian(radian:Number):Number{
return radian - GB._PI2 * Math.floor( 0.5 + radian / GB._PI2);
}
// ポイントx1 y1を、ポイントx2 y2へ、係数rateだけ移動させる場合の、XYの力を返す
private function pullForce(x1:Number, y1:Number, x2:Number, y2:Number, rate:Number):Particle{
var point:Particle = new Particle();
var distance:Number = calcDistance(x1, y1, x2, y2);
var angle:Number = Math.atan2(y2 - y1, x2 - x1);
point.x = Math.cos(angle) * distance * rate;
point.y = Math.sin(angle) * distance * rate;
return point;
}
// ポイントx1 y1から、ポイントx2 y2までの距離
private function calcDistance(x1:Number, y1:Number, x2:Number, y2:Number):Number{
return Math.sqrt(Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2));
}
private function updatePARTICLE(CURR_PARTICLE:Particle):void
{
CURR_PARTICLE.ax += -GB._FRICTION * CURR_PARTICLE.vx;
CURR_PARTICLE.ay += -GB._FRICTION * CURR_PARTICLE.vy;
// 速度、位置への反映
CURR_PARTICLE.vx += CURR_PARTICLE.ax;
CURR_PARTICLE.vy += CURR_PARTICLE.ay;
CURR_PARTICLE.x += CURR_PARTICLE.vx;
CURR_PARTICLE.y += CURR_PARTICLE.vy;
CURR_PARTICLE.ax = 0;
CURR_PARTICLE.ay = 0; // 力をクリア
// 壁チェック
if (0 < CURR_PARTICLE.vy && GB._GROUND_LINE < CURR_PARTICLE.y){
CURR_PARTICLE.y = GB._GROUND_LINE;
CURR_PARTICLE.vy *= -0.8;
if (CURR_PARTICLE.vy < -50) CURR_PARTICLE.vy = -50;
CURR_PARTICLE.vx *= GB._GROUND_FRICTION;
}
if (CURR_PARTICLE.vx < 0 && CURR_PARTICLE.x < GB._WALL_LEFT){
CURR_PARTICLE.x = GB._WALL_LEFT;
CURR_PARTICLE.vx = 0;
CURR_PARTICLE.vy *= GB._GROUND_FRICTION;
}else if (0 < CURR_PARTICLE.vx && GB._WALL_RIGHT < CURR_PARTICLE.x){
CURR_PARTICLE.x = GB._WALL_RIGHT;
CURR_PARTICLE.vx = 0;
CURR_PARTICLE.vy *= GB._GROUND_FRICTION;
}
}
private function move():void
{
////v0.2
var I:int = 0;
var CURR_PARTICLE:Particle;
for(I = 0; I < _VERTS.length; I++)
{
updatePARTICLE(_VERTS[I]);
}
updatePARTICLE(CENT_PARTICLE);
}
public function detectDrag(m_x:Number, m_y:Number):void
{
var MAX_DISTANCE:Number = 9999;
var VX:Number = 0;
var VY:Number = 0;
var DIST:Number = 0;
for(var I:int = 0; I < _VERTS.length; I++)
{
VX = m_x - _VERTS[I].x;
VY = m_y - _VERTS[I].y;
DIST = Math.sqrt(VX*VX+VY*VY);
if(DIST<MAX_DISTANCE && DIST<15)
{
MAX_DISTANCE = DIST;
_DRAG_ID = I;
}
}
}
public function moveDrag(m_x:Number, m_y:Number):void
{
mouse_x = m_x; mouse_y = m_y;
}
public function cancelDrag():void
{
_DRAG_ID = -1;
}
public function setup():void
{
var i :int = 0;
var k :int;
var vx :Number = 0;
var vy :Number = 0;
var len :Number = 0;
var diff :Number = 0;
var nx :Number = 0;
var ny :Number = 0;
var ux :Number = 0;
var uy :Number = 0;
var VI :Particle;
var VK :Particle;
for(i = 0; i < _VERTS.length; i++)
{
k = (i + 1) % _VERTS.length;
VI = _VERTS[i];
VK = _VERTS[k];
vx = VK.x - VI.x;
vy = VK.y - VI.y;
len = Math.sqrt(vx * vx + vy * vy);
diff = VI.nextRADIAN - len;
nx = vx / len;
ny = vy / len;
ux = diff * nx;
uy = diff * ny;
d[i].x = nx;
d[i].y = ny;
}
}
public function update():void
{
//for (var i:int=0; i<GB._DERIVATION; i++){
response();
rotate(); // 回転の計算
force(); // 力の計算
move(); // 移動処理
//}
calcMID();
//draw(); // 描画処理
}
private function response():void
{
var i:int = 0;
var j:int = 0;
var n1:Particle;
var n2:Particle;
var np:Particle;
var n :Particle;
var nn:Particle;
var vn:Particle;
var fx:Number=0;
var fy:Number=0;
var dx:Number=0;
var dy:Number=0;
var da:Number=0;
var px:Number=0;
var py:Number=0;
var gx:Number =0;
var gy:Number = 0;
var vx:Number = 0;
var vy:Number = 0;
var xlen:Number = 0;
var VI:Particle;
var DI:Particle;
for(i = 0; i < _VERTS.length; i++)
if(fdiv[i] > 0)
{
VI = _VERTS[i];
DI = disp[i];
gx = DI.x / (fdiv[i]);
gy = DI.y / (fdiv[i]);
VI.x = VI.x + gx;
VI.y = VI.y + gy;
VI.vx = VI.vx + gx;
VI.vy = VI.vy + gy;
DI.x = 0.0;
DI.y = 0.0;
fdiv[i] = 0;
}
}
public function inPoly(px:Number, py:Number):Boolean
{
var i:int, j:int;
var c:Boolean = false;
var VI:Particle;
var VJ:Particle;
for (i = 0, j = _VERTS.length-1; i < _VERTS.length; j = i++) {
VI = _VERTS[i]; VJ = _VERTS[j];
if ( ((VI.y>py) != (VJ.y>py)) && (px < (VJ.x-VI.x) * (py-VI.y) / (VJ.y-VI.y) + VI.x) )
c = !c;
}
return c;
}
public function notTooClose(b:BlobPuyo):Boolean
{
return (calcDISTANCE(CENT_PARTICLE, b.CENT_PARTICLE)>RADIUS+b.RADIUS);
}
public function intersected(p1:*, p2:*, p3:*, p4:*):Boolean
{
var s1_x:Number, s1_y:Number, s2_x:Number, s2_y:Number;
s1_x = p2.x - p1.x; s1_y = p2.y - p1.y;
s2_x = p4.x - p3.x; s2_y = p4.y - p3.y;
var s:Number, t:Number;
s = (-s1_y * (p1.x - p3.x) + s1_x * (p1.y - p3.y)) / (-s2_x * s1_y + s1_x * s2_y);
t = ( s2_x * (p1.y - p3.y) - s2_y * (p1.x - p3.x)) / (-s2_x * s1_y + s1_x * s2_y);
if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
{
return true;
}
return false;
}
public function xcontact(blob:BlobPuyo):void
{
if(notTooClose(blob)) return;
var i:int = 0;
var j:int;
var l:int = 0;
var k:int = 0;
var o:int = 0;
var sx:Number = 0;
var sy:Number = 0;
var angle:Number = 0;
var cosa:Number = 0;
var sina:Number = 0;
var x1:Number = 0;
var y1:Number = 0;
var vx1:Number = 0;
var yb:Number = 0;
var vy1:Number = 0;
var yy1:Number = 0;
var adj:Number = 0;
var gx :Number = 0;
var gy :Number = 0;
var cx :Number = 0;
var cy :Number = 0;
var dp :Number = 0;
var f1 :Number = 0;
var f2 :Number = 0;
var vx :Number = 0;
var vy :Number = 0;
var len :Number = 0;
var diff :Number = 0;
var bvx:Number = 0;
var bvy:Number = 0;
var blen:Number = 0;
var pavn:Particle = new Particle(0, 0);
var VI:Particle;
var VK:Particle;
var VO:Particle;
var BV:Particle;
var DI:Particle;
var BD:Particle;
var BDJ:Particle;
var BDK:Particle;
var PV:Particle;
for(i = 0; i < _VERTS.length; i++) {
VI = _VERTS[i];
DI = disp[i];
PV = pvn[i];
if(blob.inPoly(VI.x, VI.y))
{
j = (i+1) % _VERTS.length;
BDJ = blob.disp[j];
for(o = 0; o < blob._VERTS.length; o++) {
k = (o+1) % blob._VERTS.length;
VO = blob._VERTS[o];
VK = blob._VERTS[k];
BD = blob.d[o];
BDK = blob.disp[k];
//if(inBetween(_VERTS[o], _VERTS[i], _VERTS[l]) || ){
sx = VI.x-VO.x;
sy = VI.y-VO.y;
angle = Math.atan2(VK.y-VO.y,VK.x-VO.x);
cosa = Math.cos(angle);
sina = Math.sin(angle);
x1 = sx*cosa+sy*sina;
y1 = sy*cosa-sx*sina;
pavn.x = VI.x + PV.x * RADIUS;
pavn.y = VI.y + PV.y * RADIUS;
if (y1>0 && intersected(VI, pavn, VK, VO)) {
vx = VI.x - VO.x;
vy = VI.y - VO.y;
dp = vx * BD.x + vy * BD.y;
bvx = VK.x-VO.x;
bvy = VK.y-VO.y;
blen = Math.sqrt(bvx*bvx+bvy*bvy);
cx = VO.x + dp * BD.x;
cy = VO.y + dp * BD.y;
vx = VI.x - cx;
vy = VI.y - cy;
diff = 4 /4;
gx = diff * vx;
gy = diff * vy;
DI.x -= gx;
DI.y -= gy;
fdiv[i]++;
f1 = dp / blen;
f2 = 1.0 - f1;
BDJ.x += f2 * gx;
BDJ.y += f2 * gy;
blob.fdiv[j]++;
BDK.x += f1 * gx;
BDK.y += f1 * gy;
blob.fdiv[k]++;
VI.vx = vx1*cosa-vy1*sina;
VI.vy = vy1*cosa+vx1*sina;
VI.x += VI.vx;
VI.y += VI.vy;
break;
}
}
//}
}
}
}
}
class Particle
{
public var x:Number = 0; // 位置
public var y:Number = 0;
public var vx:Number = 0; // 速度
public var vy:Number = 0;
public var ax:Number = 0; // 加速度=力 TOTO:最後まで意味無かったら消す
public var ay:Number = 0;
public var radian:Number = 0; // 向き
public var vr:Number = 0; // 向き速度
//public var color:uint = 0x000000; // パーティクルの色。右下の枠の色
//public var connect:Array = [true, true, true, true]; // パーティクルの接続状態を毎回チェックしなくていいように、保持しておく
////v0.2
public var upRADIAN :Number = 0;
public var downRADIAN :Number = 0;
public var prevRADIAN :Number = 0;
public var nextRADIAN :Number = 0;
public var AREA :Number = 0;
public var vDISTANCE :Number = 0;
public var hDISTANCE :Number = 0;
public function Particle(px:Number = 0, py:Number = 0) { x = px; y = py; }
}
class GB {
public static const _WALL_LEFT :Number = 0;
public static const _WALL_RIGHT :Number = 465;
public static const _GROUND_LINE :Number = 350;
public static const _DOT_CONNECT_MAX :int = 4;
public static const _DERIVATION :int = 3; // 計算の分割数。 //3
public static const _MAP_SIZE :Number = 400;
public static const _PI :Number = Math.PI;
public static const _PI2 :Number = 2.0 * _PI;
public static const _RADIAN90 :Number = _PI * 0.5;
public static const _RADIAN180 :Number = _PI * 1.0;
public static const _RADIAN270 :Number = _PI * -0.5;
////v0.2
public static const _RADIAN360 :Number = _PI * 2;
public static const _TO_DEGREE :Number = 180 / _PI;
public static const _COMP :Number = 0.0133; //0.1
public static const _GRAVITY :Number = 0.6 / _DERIVATION; //0.3 //0.6
public static const _ROTATION_RATE :Number = 0.05 / _DERIVATION; // 自身バネ(根元) //0.05
public static const _VERTICAL_RATE :Number = 0.166 / _DERIVATION; // ターゲットバネ(さきっぽ) //0.2 //0.133
public static const _MOUSE_PULL_RATE :Number = 2.0 / _DERIVATION;
public static const _FRICTION :Number = 0.1 / _DERIVATION;
public static const _ROTATE_FRICTION :Number = 1 - 0.2 / _DERIVATION;
public static const _MOUSE_ROTATE_FRICTION :Number = 1 - 0.8 / _DERIVATION;
public static const _MOUSE_MOVE_FRICTION :Number = 1 - 0.5 / _DERIVATION;
public static const _GROUND_FRICTION :Number = 1 - 0.5 / _DERIVATION; // 1 - 0.2 // 1 - 0.5
public function GB() {}
}