傾斜プラクティス ver.5 パーティクルをグループ化して凸包で囲む
傾斜プラクティス ver.5 グループを凸包で囲む&グループらしい動きのまとまり
mouse drag 地形スクロール
click 地形隆起/沈降
[space] 上記隆起/沈降トグル
[enter] 地形リセット
[r] パーティクルリセット
--------------------------------------------
グループが視覚的にわかるように凸包で囲んでみた。
グループがまとまって動く仕組みと、グループ同士の衝突判定を入れたよ。
----------------------------------
/**
* Copyright lagash ( http://wonderfl.net/user/lagash )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/gG3S
*/
// 傾斜プラクティス ver.5 グループを凸包で囲む&グループらしい動きのまとまり
//
//
// mouse drag 地形スクロール
// click 地形隆起/沈降
// [space] 上記隆起/沈降トグル
// [enter] 地形リセット
// [r] パーティクルリセット
//--------------------------------------------
// グループが視覚的にわかるように凸包で囲んでみた。
// グループがまとまって動く仕組みと、グループ同士の衝突判定を入れたよ。
// ----------------------------------
package {
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Shape;
import flash.display.Bitmap;
import flash.display.Stage;
import flash.display.BitmapData;
import flash.display.DisplayObjectContainer;
import flash.display.LineScaleMode;
import flash.display.BlendMode;
import flash.events.MouseEvent;
import flash.filters.ColorMatrixFilter;
import flash.filters.DisplacementMapFilter;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.utils.ByteArray;
import flash.filters.BlurFilter;
import flash.system.LoaderContext;
import net.hires.debug.Stats;
public class partest extends Sprite {
var bmp:Bitmap;
var bmp2:Bitmap;
var blk:BitmapData;
var slopeBmp:Bitmap;
var bgbmp:Bitmap;
var bgbmp_source:Bitmap;
var rotateBmp:Bitmap;
var groupsContainer:Sprite;
var shape1:Shape;
var curves:Object;
var rotationColor:Number;
var baseMatrix: Matrix = new Matrix();
var baseRect:Rectangle;
var basePoint:Point;
var baseColorTransform:ColorTransform;
var baseColorTransform2:ColorTransform;
var ColorMatrixFilter1:ColorMatrixFilter;
var ColorMatrixFilter2:ColorMatrixFilter;
var keishaMap:BitmapData;
const maxParticles = 500;
static public var forceMap: BitmapData;
//private var COLOR: uint = 0xFFFFFF;
private var seed: int;
private var mw: int;
private var mh: int;
private var arr: Array;
private var point: Point;
private var point2: Point;
static public var stageWidth;
static public var stageHeight;
var centerX:uint;
var centerY:uint;
var onDrag:Boolean=false;
var onDragX:int=0;
var onDragY:int = 0;
var onDragStartX:int = 0;
var onDragStartY:int = 0;
var toggleBW:Boolean = true;
private var particles:Vector.<particle>=new Vector.<particle>();
private var sidesVec=particles;
private var groups:Vector.<groupObject> = new Vector.<groupObject>();
private var textDisp:TextField;
/* 三角関数高速化
static public const _TABLE_SIZE:int = 0x10000;
static public const _PI:Number = Math.PI;
static public const _TWO_PI:Number = 2 * _PI;
static public const _TWO_PI_SCALE:Number = _TABLE_SIZE / _TWO_PI;
static public const _HALF_PI:Number = _PI / 2;
static public const _table:Vector.<Number> = new function ():Vector.<Number>{
var table:Vector.<Number> = new Vector.<Number>(_TABLE_SIZE, true);
for (var i:uint = 0; i < _TABLE_SIZE; i++) {
table[i] = Math.sin(i / _TWO_PI_SCALE);
}
return table;
};
*/
public function partest() {
super();
addEventListener(Event.ADDED_TO_STAGE, addToStageHandlr);
}
private function addToStageHandlr(e:Event) {
removeEventListener(Event.ADDED_TO_STAGE, addToStageHandlr);
stage.frameRate = 30;
//stage.doubleClickEnabled=true;
stageWidth = stage.stageWidth;
stageHeight = stage.stageHeight;
this.buttonMode=this.useHandCursor = true;
forceMap = new BitmapData(stageWidth / 2+1, stageHeight / 2+1);
bmp = new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, true, 0xff000000), "auto", true);//bitmap処理用
bmp.alpha = 1;
bmp.blendMode=BlendMode.ADD;
bmp2 = new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x00000000), "auto", true);//bitmap処理用
bmp2.alpha = 1;
//bmp2.filters = [new BlurFilter(32, 32, 2)];
bmp2.blendMode = BlendMode.ADD;
blk = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x01000000);
slopeBmp = new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight, true, 0xff000000), "auto", true);//bitmap処理用
bgbmp = new Bitmap(new BitmapData(stage.stageWidth * 3, stage.stageHeight * 3), "auto", true);//bitmap処理用
bgbmp.x = -stage.stageWidth;
bgbmp.y = -stage.stageHeight;
bgbmp_source = new Bitmap(new BitmapData(stage.stageWidth, stage.stageHeight), "auto", true);//bitmap処理用
rotateBmp = new Bitmap(new BitmapData(stage.stageWidth * 3, stage.stageHeight * 3), "auto", true);//bitmap処理用
groupsContainer = new Sprite();
shape1 = new Shape();
shape1.filters = [new BlurFilter(64, 64, 2)];
textDisp = new TextField();
textDisp.width=stage.stageWidth;
textDisp.y = stage.stageHeight-20;
textDisp.textColor = 0xffffff;
textDisp.cacheAsBitmap;
basePoint = new Point(0, 0);
baseRect = new Rectangle(0, 0, stageWidth, stageHeight);
baseColorTransform = new ColorTransform;
baseColorTransform.redMultiplier = .03;
baseColorTransform.greenMultiplier = .06;
baseColorTransform.blueMultiplier = .02;
//baseColorTransform.redOffset = baseColorTransform.greenOffset = baseColorTransform.blueOffset = -10;
baseColorTransform2 = new ColorTransform;
baseColorTransform2.redMultiplier = baseColorTransform2.greenMultiplier = baseColorTransform2.blueMultiplier = 5;
//baseColorTransform2.redOffset =
baseColorTransform2.greenOffset = 20;
//baseColorTransform2.blueOffset = 20;
ColorMatrixFilter1 = new ColorMatrixFilter([
.03, 0, 0, 0, 0,
0, .06, 0, 0, 0,
0, 0, .02, 0, 0,
0, 0, 0, 1, 0
]);
ColorMatrixFilter2 = new ColorMatrixFilter([
5, 0, 0, 0, 0,
0, 5, 0, 0, 20,
0, 0, 5, 0, 0,
0, 0, 0, 1, 0
]);
bgbmp.filters = [ColorMatrixFilter1,ColorMatrixFilter2];
baseMatrix.identity();
baseMatrix.scale(2,2);
//addChild(slopeBmp);
addChild(bgbmp);
addChild(bmp2);
addChild(bmp);
var st=new Stats();st.blendMode=BlendMode.SCREEN;
addChild(st);
addChild(textDisp);
//addChild(rotateBmp);
init();
setMap();
//イベント登録
//stage.addEventListener(MouseEvent.DOUBLE_CLICK, mouseClickHandlr);
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandlr);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandlr);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandlr);
//stage.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandlr);
stage.addEventListener(Event.ENTER_FRAME, enterframeHandlr);
stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent) {
if (e.charCode == 32) toggleBW = (!toggleBW);
if (e.charCode == 13) setMap();
if (e.charCode == 114) init();
} );
}
private function mouseClickHandlr(e) {
setMap();
}
private function mouseDownHandlr(e) {
onDragX=onDragStartX=e.currentTarget.mouseX;
onDragY=onDragStartY=e.currentTarget.mouseY;
onDrag=true;
}
private function mouseUpHandlr(e) {
onDrag = false;
if (onDragStartX == e.currentTarget.mouseX && onDragStartY == e.currentTarget.mouseY) {
bgbmp.bitmapData.lock();
shape1.graphics.clear();
shape1.graphics.beginFill(0xffffff * uint(toggleBW), .2);
for (var i = -1; i < 2; i++) for (var j = -1; j < 2; j++) shape1.graphics.drawCircle(e.currentTarget.mouseX+i*stageWidth, e.currentTarget.mouseY+j*stageHeight, 32);
bgbmp_source.bitmapData.draw(shape1);
forceMap.draw(bgbmp_source.bitmapData, new Matrix(.5, 0, 0, .5, 0, 0));
for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) bgbmp.bitmapData.copyPixels( bgbmp_source.bitmapData, baseRect, new Point(i * stageWidth, j * stageHeight));
bgbmp.bitmapData.unlock();
}
}
private function mouseMoveHandlr(e) {
if (!onDrag) return;
bgbmp.x -=onDragX-e.currentTarget.mouseX;
bgbmp.y -=onDragY-e.currentTarget.mouseY;
onDragX = e.currentTarget.mouseX;
onDragY = e.currentTarget.mouseY;
bgbmp_source.bitmapData.copyPixels(bgbmp.bitmapData, new Rectangle(-bgbmp.x, -bgbmp.y,stageWidth,stageHeight), basePoint);
forceMap.draw(bgbmp_source.bitmapData, new Matrix(.5, 0, 0, .5, 0, 0));
for (var i = 0; i < 3; i++) for (var j = 0; j < 3; j++) bgbmp.bitmapData.copyPixels( bgbmp_source.bitmapData, baseRect, new Point(i * stageWidth, j * stageHeight));
bgbmp.x = -stageWidth;
bgbmp.y = -stageHeight;
}
private function mouseWheelHandlr(e:MouseEvent) {
return;
}
//初期化
private function init() {
var sidePer=0;
if(sidesVec){
var tmpYellow=sidesVec.length;
var tmpCyan=particles.length-sidesVec.length;
sidePer=(tmpCyan-tmpYellow)/2;
}
var currentParticlesLength=particles.length;
for (var i = 0; i < maxParticles-currentParticlesLength; i++) {
if (i != 0) {
particles.push(new particle(stage.stageWidth * Math.random(), stage.stageHeight * Math.random(), particles.length, particles[particles.length - 1]));
}else {
particles.push(new particle(stage.stageWidth * Math.random(), stage.stageHeight * Math.random(), 0));
}
particles[particles.length-1].side = (particles[particles.length-1].yy<stage.stageHeight/2+sidePer)?true:false;
}
}
function setMap():void{
forceMap.perlinNoise(mw = forceMap.width >> 2, mh = forceMap.height >> 2, 3,
seed = Math.random() * 0xFFFF, true, true, 1,true);
arr = [point = new Point(), point2 = new Point()];
bgbmp_source.bitmapData.draw(forceMap,baseMatrix);
for (var i = 0; i < 3; i++)for (var j = 0; j < 3; j++)bgbmp.bitmapData.copyPixels( bgbmp_source.bitmapData, baseRect,new Point(i*stageWidth,j*stageHeight));
rotateBmp.bitmapData.copyPixels(bgbmp.bitmapData, new Rectangle(0, 0, bgbmp.bitmapData.width, bgbmp.bitmapData.height), basePoint);
keishaMap = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x00000000);//傾斜データ保存用
}
//メイン
private function enterframeHandlr(e){
var flg_2 = 0;
bmp.bitmapData.lock();
bmp2.bitmapData.lock();
centerX = centerY = 0;
var col: uint, h: Number;
particles.sort(sortParticles);
function sortParticles(x, y):Number {
if (x.xx > y.xx) { return 1; } else { return -1; }
return 0;
}
var tmpTx = 0; var tmpTy = 0;
var yHp:Number=0;
var cHp:Number=0;
var pl=particles.length;
for (var i = 0; i < pl; i++) {
var tmpObj = particles[i];
var sideColor = 0xee * int(tmpObj.side);
col = 0xee;// * i / maxParticles;
col = (0x10000 * sideColor) + (0x100 * col) + (col-sideColor);
//当たり判定
if (i != 0) {
var hitcnt = i;
while (hitcnt) {
hitcnt--;
if ( tmpObj.xx - particles[hitcnt].xx > 3) {
break;
}
if( Math.abs(tmpObj.yy - particles[hitcnt].yy) < 3){// && tmpObj.side!=particles[hitcnt].side) {
var tmpCol=0x666666;
if(tmpObj.side!=particles[hitcnt].side){
var dm = tmpObj.getTl() - particles[hitcnt].getTl();
if (dm > 0) { particles[hitcnt].hp -= dm; } else { tmpObj.hp += dm; }
tmpCol=0xff0000;
}
for (var exp = 1; exp < 4;exp++){
bmp.bitmapData.setPixel(tmpObj.xx - exp, tmpObj.yy-exp, tmpCol );
bmp.bitmapData.setPixel(tmpObj.xx + exp, tmpObj.yy+exp, tmpCol );
bmp.bitmapData.setPixel(tmpObj.xx-exp, tmpObj.yy + exp, tmpCol );
bmp.bitmapData.setPixel(tmpObj.xx+exp, tmpObj.yy - exp, tmpCol );
}
//var tmpTl = tmpObj.getTl()+particles[hitcnt].getTl();
tmpTx = (tmpObj.tx*tmpObj.hp - particles[hitcnt].tx*particles[hitcnt].hp);///tmpTl;
tmpTy = (tmpObj.ty*tmpObj.hp - particles[hitcnt].ty*particles[hitcnt].hp);///tmpTl;
tmpObj.tx += tmpTx / tmpObj.hp;
tmpObj.ty += tmpTy / tmpObj.hp;
particles[hitcnt].tx -= tmpTx / particles[hitcnt].hp;
particles[hitcnt].ty -= tmpTy / particles[hitcnt].hp;
/* tmpTx = particles[hitcnt].tx;
tmpTy = particles[hitcnt].ty;
if(particles[hitcnt].tx*tmpObj.tx<0)particles[hitcnt].tx += tmpObj.tx;
if(particles[hitcnt].ty*tmpObj.ty<0)particles[hitcnt].ty += tmpObj.ty;
if(tmpObj.tx*tmpTx<0)tmpObj.tx += tmpTx;
if(tmpObj.ty*tmpTy<0)tmpObj.ty += tmpTy;
*/
}
break;
}
}
centerX += tmpObj.xx;
centerY += tmpObj.yy;
/* var tmpCol = keishaMap.getPixel32(tmpObj.xx, tmpObj.yy);
if (forceMap.getPixel(tmpObj.xx>>1, tmpObj.yy>>1)!=slopeBmp.bitmapData.getPixel(tmpObj.xx, tmpObj.yy)) tmpCol=setMapPoint(int(tmpObj.xx), int(tmpObj.yy));
var bX = tmpCol >>> 16;
var bY = tmpCol & 0xffff;
var dx = int(uint((((bX&0x8000)<<16)>>16)+(bX&0x7fff)))*.00001;
var dy = int(uint((((bY&0x8000)<<16)>>16)+(bY&0x7fff)))*.00001;
*/
var vec = getSlopeVector(tmpObj.xx, tmpObj.yy);
var spdLim=3;
tmpObj.tx = tmpObj.tx * .999 + vec.x;
tmpObj.ty = tmpObj.ty * .999 + vec.y;
var tl=getLineLength(0,0,tmpObj.tx,tmpObj.ty);
if(tl>spdLim){tmpObj.tx=tmpObj.tx/tl*spdLim;tmpObj.ty=tmpObj.ty/tl*spdLim;}
tmpObj.xx += tmpObj.tx;
tmpObj.yy += tmpObj.ty;
if (tmpObj.xx < 0 || tmpObj.xx >= stageWidth) { tmpObj.xx = uint(tmpObj.tx < 0) * (stageWidth-1);}
if (tmpObj.yy < 0 || tmpObj.yy >= stageHeight) { tmpObj.yy = uint(tmpObj.ty < 0) * (stageHeight-1);}
bmp.bitmapData.setPixel(tmpObj.xx, tmpObj.yy, col );
if (tmpObj.hp < 0) {
var ccc = 0x5555;
for ( exp = 1; exp < 20;exp++){
bmp.bitmapData.setPixel(tmpObj.xx - exp, tmpObj.yy, ccc );
bmp.bitmapData.setPixel(tmpObj.xx + exp, tmpObj.yy, ccc );
bmp.bitmapData.setPixel(tmpObj.xx, tmpObj.yy + exp, ccc );
bmp.bitmapData.setPixel(tmpObj.xx, tmpObj.yy - exp, ccc );
}
}
yHp+=(tmpObj.side)?tmpObj.hp:0;
cHp += (!tmpObj.side)?tmpObj.hp:0;
//所属グループチェック
if(tmpObj.groupFlg){
if (getLineLength(tmpObj.group.ox, tmpObj.group.oy, tmpObj.xx, tmpObj.yy) > 80) {
tmpObj.group.removeMember(tmpObj);
tmpObj.groupFlg = false;
}
}else if (!tmpObj.groupFlg) {
if (groups.length == 0) {
var newGrp = new groupObject();
newGrp.side = tmpObj.side;
newGrp.addMember(tmpObj);
tmpObj.group = newGrp;
tmpObj.groupFlg = true;
groups.push(newGrp);
}else {
var mostNearGroup;
var mNGLength=70;
var gl = groups.length;
for ( gId = 0; gId < gl; gId++) {
var tmpGrp = groups[gId];
var tmpLength = getLineLength(tmpGrp.ox, tmpGrp.oy, tmpObj.xx, tmpObj.yy);
if ((!mNGLength || mNGLength > tmpLength) && tmpGrp.side==tmpObj.side) {
mNGLength = tmpLength;
mostNearGroup = tmpGrp;
}
}
if (mNGLength < 70) {
mostNearGroup.addMember(tmpObj);
tmpObj.group = mostNearGroup;
tmpObj.groupFlg = true;
}else {
newGrp = new groupObject();
newGrp.side = tmpObj.side;
newGrp.addMember(tmpObj);
tmpObj.group = newGrp;
tmpObj.groupFlg = true;
groups.push(newGrp);
}
}
}
}
centerX /= particles.length;
centerY /= particles.length;
//パーティクルの整理
particles=particles.filter(hpCheck,null);
function hpCheck(item:particle, index:int, vector:Vector.<particle>):Boolean {
if (item.hp<=0) {
if (item.groupFlg) item.group.removeMember(item);
return false;
}
return true;
}
sidesVec=particles.filter(sideCheck,null);
function sideCheck(item:particle, index:int, vector:Vector.<particle>):Boolean {
if (item.side==false) { return false; }
return true;
}
//パーティクルのリセット判定
//if(particles.length<maxParticles*.1 || sidesVec.length<10 || particles.length-sidesVec.length<10)init();
var gStr = "";
var gmLength:uint;
bmp2.bitmapData.copyPixels(blk, baseRect, basePoint);
//グループの整理
groups=groups.filter(groupsCheck,null);
function groupsCheck(item:groupObject, index:int, vector:Vector.<groupObject>):Boolean {
item.calc();
if (item.length<=4) {
for (var gId in item.members) item.members[gId].groupFlg = false;
if (item.shape.root) groupsContainer.removeChild(item.shape);
return false;
}
if (!item.shape.root) groupsContainer.addChild(item.shape);
return true;
}
/* groups.sort(sortGroups);
function sortGroups(x, y):Number {
if (x.ox > y.ox) { return 1; } else { return -1; }
return 0;
}
*/
//パーティクルのグループ化動作
for (var gId in groups) {
tmpGrp = groups[gId];
gmLength += tmpGrp.length;
var vec = getSlopeVector(tmpGrp.ox, tmpGrp.oy);
tmpGrp.tx += vec.x;
tmpGrp.ty += vec.y;
//当たり判定
for(var hitId in groups) {
if (gId == hitId) break;
// if ( tmpGrp.ox - groups[hitcnt].ox > 70)break;
// if( Math.abs(tmpGrp.oy - groups[hitcnt].oy) < 70){// && tmpObj.side!=particles[hitcnt].side) {
if ( tmpGrp.shape.hitTestObject(groups[hitId].shape)) {// && tmpObj.side!=particles[hitcnt].side) {
//trace("hit "+gId+" & "+hitId);
var tmpTl = getLineLength(tmpGrp.ox, tmpGrp.oy, groups[hitId].ox, groups[hitId].oy);
tmpTx = (tmpGrp.ox*tmpGrp.length - groups[hitId].ox*groups[hitId].length)/(tmpTl*tmpTl);
tmpTy = (tmpGrp.oy*tmpGrp.length - groups[hitId].oy*groups[hitId].length)/(tmpTl*tmpTl);
tmpGrp.tx += tmpTx/tmpGrp.length;
tmpGrp.ty += tmpTy/tmpGrp.length;
groups[hitId].tx -= tmpTx/groups[hitId].length;
groups[hitId].ty -= tmpTy/groups[hitId].length;
//tmpTx = groups[hitId].tx;
//tmpTy = groups[hitId].ty;
//groups[hitId].tx += tmpGrp.tx;
//groups[hitId].ty += tmpGrp.ty;
//tmpGrp.tx += tmpTx;
//tmpGrp.ty += tmpTy;
}
}
spdLim = 1000;
var tl=getLineLength(0,0,tmpGrp.tx,tmpGrp.ty);
if (tl > spdLim) { tmpGrp.tx = (tmpGrp.tx / tl) * spdLim; tmpGrp.ty = (tmpGrp.ty / tl) * spdLim; }
var tmpLx;
var tmpLy;
var tmpL;
for ( i in tmpGrp.members) {
tmpObj = tmpGrp.members[i];
/* tmpLx=tmpGrp.ox - tmpObj.xx;
tmpLy=tmpGrp.oy - tmpObj.yy;
tmpL=Math.sqrt(Math.pow(tmpLx, 2) + Math.pow(tmpLy, 2));
tmpObj.tx += (tmpLx / tmpL) >> 4;
tmpObj.ty += (tmpLy / tmpL) >> 4;
*/
if (tmpObj.tx * tmpGrp.tx < 0) tmpObj.tx += tmpGrp.tx;
if (tmpObj.ty * tmpGrp.ty < 0) tmpObj.ty += tmpGrp.ty;
}
//if (gId == 0) {
tmpGrp.Compute();
bmp2.bitmapData.draw(tmpGrp.shape);
//}
}
gStr += "[" + gmLength + " / "+particles.length+" ("+uint((gmLength/particles.length)*100)+"%)]";
//画面表示系処理
bmp.bitmapData.applyFilter(bmp.bitmapData, baseRect, basePoint, new BlurFilter(2, 2, 2));
bmp.bitmapData.unlock();
bmp2.bitmapData.unlock();
//ステータス表示
textDisp.text = "yellow:" + sidesVec.length + "(" + yHp + ") / cyan: " + (particles.length - sidesVec.length) + "(" + cHp + ") groups: " + groups.length + " " + gStr + " drawMode:" + ((toggleBW)?"rise":"fall");
//stage.removeEventListener(Event.ENTER_FRAME, enterframeHandlr);
}
function setMapPoint(tmpX,tmpY):uint{
var col = forceMap.getPixel(tmpX >> 1, tmpY >> 1);
var dx = 0;
var dy = 0;
for (var py = -1; py < 2; py++){
for (var px = -1; px < 2; px++) {
if (px == 0 && py == 0) continue;
var ppx = tmpX + px;
var ppy = tmpY + py;
if (ppx < 0 || ppx >= stageWidth) { ppx = int(ppx<0)* (stageWidth-1); }
if (ppy < 0 || ppy >= stageHeight){ ppy = int(ppy<0)* (stageHeight-1);}
var tmpcol = forceMap.getPixel(ppx >> 1, ppy >> 1);
//slopeBmp.bitmapData.setPixel(ppx, ppy, tmpcol);
if (px*px + py*py == 1) {
dx += (col - tmpcol) * px;
dy += (col - tmpcol) * py;
}else {
dx += (col - tmpcol) * px*.7;
dy += (col - tmpcol) * py*.7;
}
}
}
slopeBmp.bitmapData.setPixel(tmpX, tmpY, col);
col = uint((uint((uint(dx/5)&0x80000000)>>>16)+(uint(dx/5)&0x7fff)<<16)+uint((uint(dy/5) & 0x80000000) >>> 16) + (uint(dy/5) & 0x7fff));
keishaMap.setPixel32(tmpX, tmpY, col);
return col;
}
//傾斜マップから傾きベクトルを取得
private function getSlopeVector(xx:int, yy:int):Point {
var tmpCol = keishaMap.getPixel32(xx, yy);
if (forceMap.getPixel(xx>>1, yy>>1)!=slopeBmp.bitmapData.getPixel(xx, yy)) tmpCol=setMapPoint(xx,yy);
var bX = tmpCol >>> 16;
var bY = tmpCol & 0xffff;
var dx = int(uint((((bX&0x8000)<<16)>>16)+(bX&0x7fff)))*.00001;
var dy = int(uint((((bY & 0x8000) << 16) >> 16) + (bY & 0x7fff))) * .00001;
return new Point(dx, dy);
}
//
function getLineLength(x1:Number,y1:Number,x2:Number,y2:Number):Number
{
var vx=x1-x2;
var vy=y1-y2;
var vl=Math.sqrt(Math.pow(vx,2)+Math.pow(vy,2));
return vl;
}
}
}
class bugfix {
function bugfix():void {
}
}
import adobe.utils.ProductManager;
import flash.display.Shader;
import flash.geom.Point;
import flash.geom.Vector3D;
import flash.display.Shape;
import flash.utils.ByteArray;
class particle extends bugfix{
var xx:Number=0;
var yy:Number=0;
var tx:Number=0;
var ty:Number=0;
var dl:Number = 0;
var hp:int;
var side:Boolean;
var group:groupObject;
var groupFlg:Boolean;
function particle(... args):void {
xx = args[0];
yy = args[1];
var sd;
tx = Math.cos(sd=Math.random() * Math.PI * 2) * .5;
ty = Math.cos(sd) * .5;
groupFlg = false;
hp = 10;
}
function getTl():Number {
return Math.sqrt(Math.pow(tx,2)+Math.pow(ty,2));
}
}
class groupObject extends bugfix{
var members:Vector.<particle> = new Vector.<particle>();
var mLength:uint;
var px:Number;
var py:Number;
var ox:Number;
var oy:Number;
var ttx:Number;
var tty:Number;
var tx:Number;
var ty:Number;
var side:Boolean;
var shape:Shape;
function groupObject():void {
mLength = px = py = ox = oy = tx = ty = 0;
shape = new Shape();
shape.cacheAsBitmap = true;
}
function calc() {
mLength = members.length;
//if (mLength < 1) return;
px = py = ttx = tty = 0;
for (var i in members) {
px += members[i].xx;
py += members[i].yy;
ttx += members[i].tx;
tty += members[i].ty;
}
ox = px / mLength;
oy = py / mLength;
tx = ttx / mLength;
ty = tty / mLength;
//Compute();
}
function addMember(p:particle) {
members.push(p);
mLength = members.length;
px += p.xx;
py += p.yy;
ox = px / mLength;
oy = py / mLength;
ttx += p.tx;
tty += p.ty;
tx = ttx / mLength;
ty = tty / mLength;
//Compute();
}
function removeMember(p:particle) {
members.splice(members.indexOf(p), 1);
mLength = members.length;
px -= p.xx;
py -= p.yy;
ox = px / mLength;
oy = py / mLength;
ttx -= p.tx;
tty -= p.ty;
tx = ttx / mLength;
ty = tty / mLength;
//Compute();
}
function get length():uint {
mLength = members.length;
return mLength;
}
//------------------------------------------------------------------------------------------------
//QuickHull via http://asura.iaigiri.com/OpenGL/gl50.htmlのコードを元にさせていただいてます
//------------------------------------------------------------------------------------------------
var m_Points:Vector.<Point> = new Vector.<Point>();
var m_Ignore:Vector.<Boolean> = new Vector.<Boolean>();
var m_UpperHull:Vector.<Boolean> = new Vector.<Boolean>();
var m_EdgeIndex:Vector.<Array> = new Vector.<Array>();
//-------------------------------------------------------------------------------------------------
// Desc : 凸包を求める
function Compute():void
{
shape.graphics.clear();
m_Points.length = m_Ignore.length = m_UpperHull.length = m_EdgeIndex.length = 0;
members.forEach(setMPoints, null);
function setMPoints(item:particle, idx:int, vect:Vector.<particle>) {
m_Points.push(new Point(item.xx,item.yy));
}
m_Ignore.length = m_UpperHull.length = m_Points.length;
if (m_Points.length < 3) return;
// 最初の稜線を求める
var axis:Array = FindFirstEdge();
// 稜線が見つからなかったら終了
if ( axis[0] == -1 && axis[1] == -1 ) return;
// 稜線を追加
//m_RenderingFlag.push( false );
//axis[2] = false;
m_EdgeIndex.push( axis ) ;
// 上側の領域と下側の領域に分ける
CheckUpperOrLower( axis );
// 再帰呼び出しによって凸包を求める
RecursiveCallCompute( axis, true ); // 上側の領域
RecursiveCallCompute( axis, false ); // 下側の領域
//shape.graphics.lineStyle(2, 0x0000ff,1);
//shape.graphics.moveTo(m_Points[axis[0]].x, m_Points[axis[0]].y);
//shape.graphics.lineTo(m_Points[axis[1]].x, m_Points[axis[1]].y);
RenderConvexHull();
}
//------------------------------------------------------------------------------------------------
// Desc : 最初の稜線を求める
function FindFirstEdge():Array
{
var index:Array=[0, 0];
var max:Point, min:Point;
// 点の数が2よりも小さい場合は-1を返して終了
if ( m_Points.length < 4 )
return [ -1, -1 ];
// 初期化
max = min = m_Points[0];
// x座標が最大と最小となる二つの点を求める
for ( var i=0; i<m_Points.length; i++ )
{
// 最小値
if ( m_Points[i].x < min.x )
{
index[0] = i;
min = m_Points[i];
}
// 最大値
if ( m_Points[i].x > max.x )
{
index[1] = i;
max = m_Points[i];
}
}
// 算出結果
return index;
}
//-------------------------------------------------------------------------------------------------
// Desc : 計算関数を再帰呼び出し
function RecursiveCallCompute( index:Array, uh:Boolean ):void
{
var edge1:Array = [];
var edge2:Array = [];
var UpperHull = uh;
// 最も遠い点を求める
var farestPoint:int = FarestPointFromEdge( index, UpperHull );
// 点が見つからなかった場合は終了
if ( farestPoint == -1 ) { return;}
// 三角形を形成する3点は処理から外す
m_Ignore[index[0]] = true;
m_Ignore[index[1]] = true;
m_Ignore[farestPoint] = true;
// デバッグ用
//m_Colors[farestPoint] = Vector4f( 0.0f, 1.0f, 1.0f, 1.0f );
// 三角形内部にある点を処理の対象から外す
for ( var i=0; i<m_Points.length; i++ )
{
if (m_Ignore[i] == true) continue;
var result:Boolean = IsInsideOfTriangle(
m_Points[index[0]],
m_Points[index[1]],
m_Points[farestPoint],
m_Points[i] );
// 内部にあった場合
if ( result ) { m_Ignore[i] = true;}
}
// 凸包の描画用
if (m_EdgeIndex.indexOf([index[0], index[1], true]) > -1) { trace("!"); m_EdgeIndex[m_EdgeIndex.indexOf([index[0], index[1], true])][2] = false; }
if (m_EdgeIndex.indexOf([index[1], index[0], true]) > -1){ trace("!");m_EdgeIndex[m_EdgeIndex.indexOf([index[1], index[0], true])][2] = false;}
index[2] = false;
// 稜線を追加
edge1 = [index[0], farestPoint, true];
edge2 = [farestPoint, index[1], true];
m_EdgeIndex.push( edge1 );
m_EdgeIndex.push( edge2 );
// 再帰呼び出し
RecursiveCallCompute( edge1, UpperHull );
RecursiveCallCompute( edge2, UpperHull );
return;
}
//-------------------------------------------------------------------------------------------------
// Desc : 稜線に向かって垂線を下ろしたとき,垂線の長さが最大となる点のインデックスを返す
function FarestPointFromEdge( index:Array, UpperHull:Boolean ):int
{
var t = 0;
var v1:Point, v2:Point, v3:Point, v:Point;
var max = -1;
var result:int = -1;
// 稜線
v1 = m_Points[index[0]];
v2 = m_Points[index[1]];
v = new Point();
var mv1 = new Point();
for ( var i=0; i<m_Points.length; i++ )
{
// 稜線を形成する点は処理の対象外
if ( index[0] == i ) continue;
if ( index[1] == i ) continue;
// 領域が異なる場合も処理の対象外
if ( m_UpperHull[i] != UpperHull ) continue;
// すでに処理されている場合も処理の対象外
if ( m_Ignore[i] ) continue;
v3 = m_Points[i];
// 上側の領域の場合
if ( UpperHull )
{
if ( LineQuation(v1, v2, v3) < 0 ) continue;
}else{// 下側の領域の場合
if ( LineQuation(v1, v2, v3) > 0 ) continue;
}
// 垂線の足の座標
var Line_v1v2:Point = getLine(v1, v2);
var CrossLine_v1v2v3 = getCrossLine(v1, v2, v3);
v = getCrossPoint2Lines(Line_v1v2.x, Line_v1v2.y, CrossLine_v1v2v3.x, CrossLine_v1v2v3.y);
// 垂線の長さを求める
var d = Point.distance(v, v3);
// 最大値とインデックスの更新
if ( d > max )
{
max = d;
mv1 = v;
result = i;
}
}
/*垂線表示
if (result != -1) {
shape.graphics.lineStyle(1,0xffffff,.5);
//shape.graphics.drawCircle(mv1.x, mv1.y,2);
shape.graphics.moveTo(mv1.x, mv1.y);
shape.graphics.lineTo(m_Points[result].x, m_Points[result].y);
//shape.graphics.lineStyle(.5, 0xffffff,.2);
//shape.graphics.drawCircle(m_Points[index[0]].x, m_Points[index[0]].y,1);
//shape.graphics.lineTo(m_Points[index[1]].x, m_Points[index[1]].y);
//shape.graphics.drawCircle(m_Points[index[1]].x, m_Points[index[1]].y,1);
//shape.graphics.lineTo(m_Points[result].x, m_Points[result].y);
//shape.graphics.lineTo(m_Points[index[0]].x, m_Points[index[0]].y);
}
*/
// インデックスを返す
return result;
}
//------------------------------------------------------------------------------------------------
// Desc : 直線の方程式
function LineQuation( v1:Point, v2:Point, v3:Point ):Number
{
var ma = (v2.x - v1.x);
var mb = (v2.y - v1.y);
// 傾き
var m = 0.0;
if ( ma != 0 ) m = mb/ma;
// 直線の方程式に3点の座標を代入した結果を返す
//return (( v3.y - v1.y ) - m * (v3.x - v1.x));
//外積はこっち
return -((v3.x - v1.x) * (v2.y - v1.y) - (v2.x - v1.x) * (v3.y - v1.y));
}
//x1*y2-x2*y1
//------------------------------------------------------------------------------------------------
// Desc : 上側の領域か下側の領域かをチェックする
function CheckUpperOrLower( index:Array ):void
{
var a:Point = m_Points[index[0]];
var b:Point = m_Points[index[1]];
// すべての点を調べる
var c:Point;
for ( var i=0; i<m_Points.length; i++ )
{
c = m_Points[i];
// 上側の領域
if ( LineQuation(a, b, c) > 0 )
{
m_UpperHull[i] = true;
}
// 下側の領域
else
{
m_UpperHull[i] = false;
}
}
}
//-------------------------------------------------------------------------------------------------
// Desc : 三角形内部に点があるかないかを判定。内部ならばture,外部ならばfalseを返す
function IsInsideOfTriangle( v1:Point, v2:Point, v3:Point, point:Point ):Boolean
{
var d0:Vector3D, d1:Vector3D;
var cr:Number;
var result:Array=[ 0, -1, 1 ];
// 三角形を形成する3点a, b, c
var a:Vector3D=new Vector3D(v1.x, v1.y, 0);
var b:Vector3D=new Vector3D(v2.x, v2.y, 0);
var c:Vector3D=new Vector3D(v3.x, v3.y, 0);
// 判定点p
var p:Vector3D=new Vector3D(point.x, point.y, 0);
// 法線ベクトルを算出
var n:Vector3D = a.crossProduct( b );
n.normalize();
/// 符号を調べる
// 1
d0 = p;d0.decrementBy(a);
d1 = b;d1.decrementBy(a);
cr = n.dotProduct(d0.crossProduct( d1 ));
result[0] = (cr==0)?0:cr/Math.abs(cr);
// 2
d0 = p;d0.decrementBy(b);
d1 = c;d1.decrementBy(b);
cr = n.dotProduct(d0.crossProduct( d1 ));
result[1] = (cr==0)?0:cr/Math.abs(cr);
// 3
d0 = p;d0.decrementBy(c);
d1 = a;d1.decrementBy(c);
cr = n.dotProduct(d0.crossProduct( d1 ));
result[2] = (cr==0)?0:cr/Math.abs(cr);
// 符号がすべて同じだった場合は内部
if ( result[0] == result[1] == result[2])return true;
// 符号が一か所でも違えば外部
return false;
}
//------------------------------------------------------------------------------------------------
// Desc : 凸包を描画
function RenderConvexHull():void
{
if(m_EdgeIndex.length<3)return;
shape.graphics.beginFill((0x10000 * 0xee * int(side)) + (0x100 * 0xee) + (0xee-0xee * int(side)), .04);
shape.graphics.lineStyle(.1, (0x10000 * 0xee * int(side)) + (0x100 * 0xee) + (0xee-0xee * int(side)), .01);
var drawPoint:Object = new Object();
for ( var i:int=0; i<m_EdgeIndex.length-1; i++ )
{
if ( m_EdgeIndex[i][2] )
{
drawPoint[String(m_EdgeIndex[i][0])]=m_Points[m_EdgeIndex[i][0]];
drawPoint[String(m_EdgeIndex[i][1])]=m_Points[m_EdgeIndex[i][1]];
}
}
var dPoints:Vector.<Point> = new Vector.<Point>();
for (var j:String in drawPoint) {
dPoints.push(drawPoint[j]);
}
dPoints.sort(sortDP);
function sortDP(a,b) {
if (Math.atan2(a.x-ox,a.y-oy) < Math.atan2(b.x-ox,b.y-oy)) return -1;
if (Math.atan2(a.x-ox,a.y-oy) > Math.atan2(b.x-ox,b.y-oy)) return 1;
return 0;
}
shape.graphics.moveTo((dPoints[0].x + dPoints[dPoints.length-1].x) / 2, (dPoints[0].y + dPoints[dPoints.length-1].y) / 2);
for (i = 0; i < dPoints.length-1; i++) {
shape.graphics.curveTo(dPoints[i].x, dPoints[i].y,(dPoints[i].x + dPoints[i + 1].x) / 2, (dPoints[i].y + dPoints[i+ 1].y) / 2);
}
shape.graphics.curveTo(dPoints[i].x, dPoints[i].y, (dPoints[0].x + dPoints[dPoints.length - 1].x) / 2, (dPoints[0].y + dPoints[dPoints.length - 1].y) / 2);
shape.graphics.endFill();
shape.graphics.lineStyle(.1, (0x10000 * 0xee * int(side)) + (0x100 * 0xee) + (0xee-0xee * int(side)), .05);
shape.graphics.moveTo(dPoints[dPoints.length-1].x, dPoints[dPoints.length-1].y);
for (i = 0; i < dPoints.length; i++) {
shape.graphics.lineTo(dPoints[i].x, dPoints[i].y);
}
shape.graphics.lineStyle(1.5, (0x10000 * 0xee * int(side)) + (0x100 * 0xee) + (0xee-0xee * int(side)), .05);
for (i = 0; i < dPoints.length; i++) {
shape.graphics.drawCircle(dPoints[i].x, dPoints[i].y,4);
}
for (i = 0; i < m_Points.length; i++) {
shape.graphics.drawCircle(m_Points[i].x, m_Points[i].y,1);
}
/* var idx1,idx2;
for ( var i:int=0; i<m_EdgeIndex.length; i++ )
{
if ( m_EdgeIndex[i][2] ) {
idx1 = m_EdgeIndex[i][0];
idx2 = m_EdgeIndex[i][1];
//shape.graphics.lineStyle(.3, (0x10000 * 0xee * int(m_UpperHull[idx1])) + (0x100 * 0xee) + (0xee-0xee * int(m_UpperHull[idx1])), .5);
//shape.graphics.drawCircle(m_Points[idx1].x, m_Points[idx1].y, 3);
shape.graphics.moveTo(m_Points[idx1].x, m_Points[idx1].y);
//shape.graphics.lineStyle(.6, (0x10000 * 0xee * int(m_UpperHull[idx2])) + (0x100 * 0xee) + (0xee-0xee * int(m_UpperHull[idx2])), .5);
shape.graphics.lineTo(m_Points[idx2].x, m_Points[idx2].y);
//shape.graphics.drawCircle(m_Points[idx2].x, m_Points[idx2].y,3);
}
}
*/
}
function getLine(p1:Point,p2:Point):Point //直線 y=[ts.x]x+[ts.y]を返す
{
var vx=p1.x-p2.x;
var vy=p1.y-p2.y;
var ts=new Point();
ts.x=vy/vx;
ts.y=p2.y-ts.x*p2.x;
return ts;
}
function getCrossLine(p1:Point,p2:Point,p3:Point):Point //点p1-p2に直交し、p3を通る直線 y=[ts.x]x+[ts.y]を返す
{
var vx=p1.x-p2.x;
var vy=p1.y-p2.y;
var ts=new Point();
ts.x=-vx/vy;
ts.y=p3.y-ts.x*p3.x;
return ts;
}
function getCrossPoint2Lines(l1a:Number,l1b:Number,l2a:Number,l2b:Number):Point //y=[l1a]x+[l1b],y=[l2a]x+[l2b]の交点を返す
{
var x = (l2b - l1b) / (l1a - l2a);
return new Point(x, l1a * x + l1b);
}
}