fussa-fussa
ランキングを見るとふさふさ系が多い印象だったので、手持ちの古いコードをASに変換。
尻尾で敵を倒すシューティングゲームを作った際にひねり出したアルゴリズム。
IKもFKも知らなかった際のものなので、かなり不安定(少し動かすと毛先が
はげしく乱れる)けど、限定的には使えると思う
これを使ってマッチの煙を表現しようと思ったけど、完成せず。今日は断念
とりあえずUP(2010/4/1)
基部をドラッグすると移動
下部のマイナス丸印をクリックすると吸引
/**
* Copyright zendenmushi ( http://wonderfl.net/user/zendenmushi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/xEwN
*/
// ランキングを見るとふさふさ系が多い印象だったので、手持ちの古いコードをASに変換。
// 尻尾で敵を倒すシューティングゲームを作った際にひねり出したアルゴリズム。
// IKもFKも知らなかった際のものなので、かなり不安定(少し動かすと毛先が
// はげしく乱れる)けど、限定的には使えると思う
// これを使ってマッチの煙を表現しようと思ったけど、完成せず。今日は断念
// とりあえずUP(2010/4/1)
// 基部をドラッグすると移動
// 下部のマイナス丸印をクリックすると吸引
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
import flash.geom.Point;
import frocessing.core.F5BitmapData2D;
/**
* ...
* @author TMaeda
*/
[SWF(width=465,height=465,backgroundColor=0,frameRate=60)]
public class ClackledHair extends Sprite
{
private var canvas : F5BitmapData2D;
private var hairs : Vector.<Tail> = new Vector.<Tail>;
private var blur : BlurFilter = new BlurFilter(4, 4, 1);
private var colorTrans : ColorTransform = new ColorTransform(0.8, 0.8, 0.9, 0.99);
private var center : Point = new Point();
private var isDown : Boolean = false;
private var tempPos : Point = new Point();
private var lastPos : Point = new Point();
private var rootPos : Point = new Point();
private var zeroPos : Point = new Point(0, 0);
private var plusBall : Point = new Point();
private var negative : Boolean = true;
private var selIndex : int = -1;
private var rad : Number = 0;
public function ClackledHair()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event=null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
addEventListener(Event.ENTER_FRAME, enterFrame);
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
canvas = new F5BitmapData2D(stage.stageWidth, stage.stageHeight, true, 0xff000000);
addChild( new Bitmap(canvas.bitmapData) );
center.x = stage.stageWidth / 2;
center.y = stage.stageHeight*2 / 3;
for (var i : int = 0 ; i < 100; i++) {
hairs[i] = new Tail();
hairs[i].init(center, 270+Math.random()*20-10, 16, 16, 1, true);
}
rootPos.x = center.x;
rootPos.y = center.y;
plusBall.x = center.x;
plusBall.y = stage.stageHeight - 30;
}
private function dist(a : Point, b : Point): Number
{
return Math.sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
private function mouseDown(e:MouseEvent):void
{
lastPos.x = e.stageX;
lastPos.y = e.stageY;
selIndex = (dist(lastPos, plusBall) < 8) ? 0 : (dist(lastPos, rootPos) < 8) ? 1 : -1;
isDown = true;
}
private function mouseUp(e:MouseEvent):void
{
if ((dist(lastPos, plusBall) < 1) && (selIndex == 0)) {
negative = !negative;
}
isDown = false;
}
private function enterFrame(e:Event):void
{
var i : int, j : int;
var hair_len : int;
var hair_cnt : int = hairs.length;
canvas.bitmapData.colorTransform(canvas.bitmapData.rect, colorTrans);
canvas.bitmapData.applyFilter(canvas.bitmapData, canvas.bitmapData.rect, zeroPos, blur);
if (isDown) {
switch (selIndex) {
case 0: {
plusBall.x = stage.mouseX;
plusBall.y = stage.mouseY;
break;
}
case 1: {
rootPos.x += (stage.mouseX-rootPos.x)/4;
rootPos.y += (stage.mouseY-rootPos.y)/4;
break;
}
}
}
rad += Math.random();
canvas.beginDraw();
canvas.bitmapData.lock();
canvas.stroke(0xff, 0xff, 0xff);
canvas.noFill();
canvas.circle(rootPos.x, rootPos.y, 8);
canvas.circle(plusBall.x, plusBall.y, 8);
canvas.moveTo(plusBall.x - 3, plusBall.y);
canvas.lineTo(plusBall.x + 3, plusBall.y);
if (!negative) {
canvas.moveTo(plusBall.x , plusBall.y - 3);
canvas.lineTo(plusBall.x , plusBall.y + 3);
}
for (i = 0; i < hair_cnt; i++) {
var tail : Tail = hairs[i];
tempPos.x = rootPos.x + Math.cos(rad) * 4;
tempPos.y = rootPos.y + Math.sin(rad) * 4;
tail.stepFrame(tempPos, 0, negative? null : plusBall);
hair_len = tail.tails.length;
canvas.moveTo(tail.rootpos.x, tail.rootpos.y);
for (j = 0; j < hair_len; j++) {
canvas.stroke(0xff*j/hair_len, 0x80, 0x40);
canvas.lineTo(tail.tails[j].term.x, tail.tails[j].term.y);
}
}
canvas.bitmapData.unlock();
canvas.endDraw();
}
}
}
import flash.geom.Point;
class Tail
{
public var tails : Vector.<TailItem>;
public var rootpos : Point = new Point();
public var rootangle : Number;
private var flexAngle : Number;
private var segLen : int;
public var segCnt : int;
private var temppos1 : Point = new Point();
private var temppos2 : Point = new Point();
private var befterm : Point = new Point();
private var autoWave : Boolean;
private var waveState : int;
private var absorb : Number = 0;
private const maxlen : int = 32;
public function Tail()
{
tails = new Vector.<TailItem>;
}
public function init(pos : Point, angle : Number, seglen : int, len : int, flexlevel : Number, autowave : Boolean = true ) : void
{
flexAngle = Math.min(flexlevel, 1.0)*2 * Math.PI;
rootangle = angle * Math.PI / 180;
segCnt = Math.min(maxlen, len);
segLen = seglen;
autoWave = autowave;
waveState = 0;
rootpos.x = pos.x;
rootpos.y = pos.y;
for (var i : int = 0; i < segCnt; i++) {
/*if (i < tails.length)*/ tails[i] = new TailItem;
tails[i].pos.x = pos.x;
tails[i].pos.y = pos.y;
tails[i].len = segLen+Math.random()*(segLen);
tails[i].angle = 0;
}
}
public function tailPos(index : int, /*out*/ pos : Point, term : Point = null) : void
{
if (index < segCnt) {
pos.x = tails[index].pos.x;
pos.y = tails[index].pos.y;
if (term) {
term.x = tails[index].term.x;
term.y = tails[index].term.y;
}
}
}
public function stepFrame(newpos : Point, rotate_angle : Number, tail_target : Point = null) : void
{
var i : int, cosa : Number, sina : Number, rad : Number;
var angle : Number = rootangle+rotate_angle;
waveState = (waveState + 1) & 0x3f;
if (autoWave) {
if (waveState >= 0x20) {
angle = angle + (0x20 - (waveState & 0x1f) - 0x10)*Math.PI/180;
} else {
angle = angle + (waveState-0x10)*Math.PI/180;
}
}
if (tail_target) {
absorb = 1.0;
} else if (absorb > 0) {
absorb /= 2;
} else absorb = 0;
rootpos.x = newpos.x;
rootpos.y = newpos.y;
for (i = 0; i < segCnt; i++) {
if (i == 0) {
tails[i].pos.x = newpos.x;
tails[i].pos.y = newpos.y;
if (autoWave) {
tails[i].pos.x += Math.random() * 8-4;
tails[i].pos.y += Math.random() * 8-4;
}
} else {
tails[i].pos.x += (tails[i-1].term.x-tails[i].pos.x)/((i*absorb/4+1));
tails[i].pos.y += (tails[i-1].term.y-tails[i].pos.y)/((i*absorb/4+1));
}
computeUnitVector(Math.cos(angle) * segLen, Math.sin(angle) * segLen, 0, 0, temppos1);
if (!computeUnitVector(tails[i].term.x, tails[i].term.y, tails[i].pos.x, tails[i].pos.y, temppos2)) {
temppos2.x = temppos1.x;
temppos2.y = temppos1.y;
}
cosa = dotProduct(temppos1.x, temppos1.y, temppos2.x, temppos2.y);
sina = crossProductZ(temppos1.x, temppos1.y, temppos2.x, temppos2.y);
if (cosa < -1) rad = Math.PI; else if (cosa > 1) rad = 0; else rad = Math.acos(cosa);
//trace(cosa + " " + rad);
if (cosa < 0) rad = Math.PI-rad;
if (sina < 0) rad = -rad;
//trace(">"+cosa + " " + rad);
if ((rad < 0) && ( -flexAngle > rad)) rad = -flexAngle;
if ((rad > 0) && ( flexAngle < rad)) rad = flexAngle;
rad += (0-rad) /4;
tails[i].angle = angle+rad;
angle = tails[i].angle;
tails[i].term.x = tails[i].pos.x + Math.cos(angle)*tails[i].len;
tails[i].term.y = tails[i].pos.y + Math.sin(angle)*tails[i].len;
}
if (tail_target) {
befterm.x = tail_target.x;
befterm.y = tail_target.y;
for (i = segCnt - 1; i > 0; i--) {
temppos2.x = tails[i].term.x + (befterm.x - tails[i].term.x) / ((segCnt - i)/2 + 1) ;
temppos2.y = tails[i].term.y + (befterm.y - tails[i].term.y) / ((segCnt - i)/2 + 1) ;
if (computeUnitVector(temppos2.x, temppos2.y, tails[i].pos.x, tails[i].pos.y, temppos1)) {
tails[i].term.x = temppos2.x;
tails[i].term.y = temppos2.y;
tails[i].pos.x = temppos2.x - (temppos1.x)*tails[i].len;
tails[i].pos.y = temppos2.y - (temppos1.y)*tails[i].len;
befterm.x = tails[i].pos.x;
befterm.y = tails[i].pos.y;
}
}
}
}
public function computeUnitVector(x0 : Number, y0 : Number, x1 : Number, y1 : Number, /*out*/ u : Point) : Boolean
{
var len : Number = Math.sqrt( (y0 - y1) * (y0 - y1) + (x0 - x1) * (x0 - x1) );
if (len > 0) {
u.x = (x0 - x1) / len;
u.y = (y0 - y1) / len;
return true;
} else return false;
}
public function dotProduct(x0 : Number, y0 : Number, x1 : Number, y1 : Number) : Number
{
return x0 * x1 + y0 * y1;
}
public function crossProductZ(x0 : Number, y0 : Number, x1 : Number, y1 : Number) : Number
{
return x0 * y1 - y0 * x1;
}
}
class TailItem
{
public var pos : Point = new Point();
public var angle : Number;
public var term : Point = new Point();
public var len : Number;
}