FoxTailColor
狐の尻尾です。ちょっとプルプルしすぎです。
細かい修正や、説明コメントはまだ
キーボードのLで、ロック解除
paqさんのコードを見てアイデアを思いついて、先っぽを白くしてみました。
/**
* Copyright tail_y ( http://wonderfl.net/user/tail_y )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/lxhI
*/
package
{
/*
狐の尻尾です。ちょっとプルプルしすぎです。
細かい修正や、説明コメントはまだ
キーボードのLで、ロック解除
paqさんのコードを見てアイデアを思いついて、先っぽを白くしてみました。
*/
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.GradientType;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.display.StageQuality;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.filters.BevelFilter;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
public class FoxTailColor extends Sprite
{
public function FoxTailColor()
{
addEventListener(Event.ADDED_TO_STAGE, init); // flexBuilderとの互換性。
Wonderfl.capture_delay(1);
}
public static const STAGE_W:uint = 465;
public static const STAGE_H:uint = 465;
private static const _PI:Number = Math.PI;
private static const _PI2:Number = 2.0 * _PI;
private static const _WALL_LEFT:Number = 0;
private static const _WALL_RIGHT:Number = 465;
private static const _GROUND_LINE:Number = 400;
private static const _DERIVATION:int = 4;
private static const _GRAVITY:Number = 0.4 / _DERIVATION;
private static const _ROTATION_RATE:Number = 0.05 / _DERIVATION; // 自身バネ(根元)
private static const _VERTICAL_RATE:Number = 0.5 / _DERIVATION; // ターゲットバネ(さきっぽ)
private static const _MOUSE_PULL_RATE:Number = 0.1 / _DERIVATION;
private static const _FRICTION:Number = 1 - 0.1 / _DERIVATION;
private static const _MOUSE_ROTATE_FRICTION:Number = 1 - 0.8 / _DERIVATION;
private static const _MOUSE_MOVE_FRICTION:Number = 1 - 0.5 / _DERIVATION;
// 色設定
private static const _COLOR:uint = 0xE8B453;
private static const _BEVEL_H_COLOR:uint = 0xffffff;
private static const _BEVEL_S_COLOR:uint = 0x000000;
private static const _BEVEL_H_ALPHA:Number = 0.1;
private static const _BEVEL_S_ALPHA:Number = 0.2;
private var _boneList:Array = [];
private var _dragId:int = -1;
private var _boneLayer:Sprite;
private var _alphaLayer:Sprite;
private var _displayLayer:Bitmap;
private var _displayBitmapData:BitmapData = new BitmapData(STAGE_W, STAGE_H, true, 0x00000000);
private var _shadowLayer:Bitmap;
private var _shadow:BitmapData = new BitmapData(STAGE_W, STAGE_H, true, 0x00000000);
private var _gray:BitmapData = new BitmapData(STAGE_W, STAGE_H, false, 0x888888);
private var _clear:BitmapData = new BitmapData(STAGE_W, STAGE_H, true, 0x00000000);
private var _cover:BitmapData = new BitmapData(STAGE_W, STAGE_H, true, 0x00000000);
private var _bevel:BevelFilter = new BevelFilter(10, 100, _BEVEL_H_COLOR, _BEVEL_H_ALPHA, _BEVEL_S_COLOR, _BEVEL_S_ALPHA, 33, 33, 1, 1);
private var _topLock:Boolean = true;
private static const _LOCK_Y:int = 50;
private function init(e:Event):void { // ここから開始
removeEventListener(Event.ADDED_TO_STAGE, init);
// SWF設定
stage.frameRate = 30;
stage.quality = StageQuality.MEDIUM;
var bg:Sprite = new Sprite(); // wonderflではキャプチャに背景色が反映されないので、背景色Spriteで覆う。
bg.graphics.beginFill(0xffffff, 1);
bg.graphics.drawRect(0, 0, STAGE_W, STAGE_H);
addChild(bg);
// 色々準備
var coverGradient:Sprite = new Sprite();
var matrix:Matrix = new Matrix()
matrix.createGradientBox(STAGE_W, STAGE_H, Math.PI / 2, STAGE_W / 2, STAGE_H / 2)
coverGradient.graphics.beginGradientFill(GradientType.LINEAR, [0xffffff, 0xffffff], [1, 0], [0, 230], matrix);
coverGradient.graphics.drawRect(0, 0, STAGE_W, STAGE_H);
_cover.draw(coverGradient);
_shadowLayer = new Bitmap(_shadow);
_alphaLayer = new Sprite();
_boneLayer = new Sprite();
addChild(_shadowLayer);
//addChild(_alphaLayer);
addChild(_boneLayer);
_boneLayer.alpha = 0; // マウスを取ってもらうので、完全には消さない
_displayLayer = new Bitmap(_displayBitmapData);
addChild(_displayLayer);
// 骨組みを用意する。
var color1:uint = _COLOR;
var color2:uint = 0xeeeeee;
var tmpR:Number = 0;
addBone(tmpR+= 1, 15, color2, tmpR+20);
addBone(tmpR+= 7, 22, color2, tmpR+20);
addBone(tmpR+= 10, 30, color2, tmpR+20);
addBone(tmpR+= 10, 30, color2, tmpR+20);
addBone(tmpR+= 10, 30, color2, tmpR+20);
addBone(tmpR+= 6, 30, color1, tmpR+20);
addBone(tmpR+= 3, 30, color1, tmpR+20);
addBone(tmpR-= 4, 30, color1, tmpR+20);
addBone(tmpR-= 7, 30, color1, tmpR+20);
addBone(tmpR-= 12, 30, color1, tmpR+20);
addBone(tmpR-= 12, 20, color1, tmpR+20);
// ドラッグ解除
stage.addEventListener(MouseEvent.MOUSE_UP, bornMouseUpEvent());
// フレームの処理を登録
addEventListener(Event.ENTER_FRAME, frame);
// キーの処理を登録
stage.addEventListener(KeyboardEvent.KEY_DOWN, key);
}
private var _id:int = 0;
private var _lastX:Number = 50;
private function addBone(radius:Number, connectLength:Number, color:uint, colorSize:Number):void{
var bone:BoneCircle = new BoneCircle(radius, connectLength, color, colorSize);
bone.y = _LOCK_Y;
bone.x = _lastX;
_boneList.push(bone);
_boneLayer.addChild(bone);
// マウスイベント
bone.addEventListener(MouseEvent.MOUSE_DOWN, bornMouseDownEvent(_id++));
_lastX += connectLength;
}
// フレーム挙動
private function frame(event:Event):void{
for (var i:int=0; i<_DERIVATION; i++){
rotate();
foce();
move();
}
draw();
drawShadow();
debugDraw();
}
// ボーンの向きを決定する
private function rotate():void{
var l:int = _boneList.length;
for (var i:int=0; i < l; i++){
var baceBone:BoneCircle = _boneList[i];
var targetBone:BoneCircle = _boneList[i+1];
if (i + 1 < l){
calcConnectRForce(baceBone, targetBone, 0);
calcConnectRForce(targetBone, baceBone, _PI);
}
if (i == _dragId) baceBone.vr *= _MOUSE_ROTATE_FRICTION;
baceBone.vr *= _FRICTION; // 摩擦
}
}
// 接続されたパーツの回転方向を計算する
private function calcConnectRForce(baceBone:BoneCircle, targetBone:BoneCircle, connectAngle:Number):void{
var angle:Number = Math.atan2(targetBone.y - baceBone.y, targetBone.x - baceBone.x);
baceBone.vr += ajustRadian(angle - (connectAngle + baceBone.radian)) * _ROTATION_RATE;
}
// 力関係、加速度を整理する。
private function foce():void{
var i:int;
var l:int = _boneList.length;
var bone:BoneCircle;
for (i=0; i < l; i++){
bone = _boneList[i];
bone.vy += _GRAVITY;
if (_dragId == i){ // マウスで引っ張る
var vPoint:Point = pullForce(bone.x, bone.y, mouseX, mouseY, _MOUSE_PULL_RATE);
bone.vx += vPoint.x;
bone.vy += vPoint.y;
}
if (i + 1 < l){
calcConnectFoce(bone, _boneList[i+1], 0);
calcConnectFoce(_boneList[i+1], bone, _PI);
}
// 摩擦
bone = _boneList[i];
bone.vx *= _FRICTION;
bone.vy *= _FRICTION;
if (i == _dragId){
bone.vx *= _MOUSE_MOVE_FRICTION;
bone.vy *= _MOUSE_MOVE_FRICTION;
}
}
}
// 接続された2パーツの力を計算する
private function calcConnectFoce(baceBone:BoneCircle, targetBone:BoneCircle, connectAngle:Number):void{
var toAngle:Number = ajustRadian(connectAngle + baceBone.radian);
var toX:Number = baceBone.x + Math.cos(toAngle) * baceBone.connectLength;
var toY:Number = baceBone.y + Math.sin(toAngle) * baceBone.connectLength;
var vx:Number = (targetBone.x - toX) * _VERTICAL_RATE;
var vy:Number = (targetBone.y - toY) * _VERTICAL_RATE;
baceBone.vx += vx;
baceBone.vy += vy;
targetBone.vx -= vx;
targetBone.vy -= vy;
}
// ポイントx1 y1を、ポイントx2 y2へ、係数rateだけ移動させる場合の、XYの力を返す
private function pullForce(x1:Number, y1:Number, x2:Number, y2:Number, rate:Number):Point{
var point:Point = new Point();
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));
}
// radian角度を、-π~πの範囲に修正する
private function ajustRadian(radian:Number):Number{
return radian - _PI2 * Math.floor( 0.5 + radian / _PI2);
}
// 移動を反映。
private function move():void{
for (var i:int=0; i < _boneList.length; i++){
var bone:BoneCircle = _boneList[i];
bone.x += bone.vx;
bone.y += bone.vy;
bone.radian += bone.vr;
// 壁チェック
if (0 < bone.vy && _GROUND_LINE - bone.radius < bone.y){
bone.y = _GROUND_LINE - bone.radius;
bone.vy = 0;
}
if (bone.vx < 0 && bone.x < _WALL_LEFT + bone.radius){
bone.x = _WALL_LEFT + bone.radius;
bone.vx = 0;
}else if (0 < bone.vx && _WALL_RIGHT - bone.radius < bone.x){
bone.x = _WALL_RIGHT - bone.radius;
bone.vx = 0;
}
// 回転方向を反映
bone.rotation = bone.radian * 180 / Math.PI;
}
if (_topLock){
bone = _boneList[_boneList.length - 1];
bone.vy = 0;
bone.y = _LOCK_Y;
}
}
private var _rect:Rectangle = new Rectangle(0, 0, STAGE_W, STAGE_H);
private var _point:Point = new Point();
private var _alphaChannel:BitmapData = new BitmapData(STAGE_W, STAGE_H, true, 0x00000000);
// 表示。
private function draw():void{
var pointListX:Array = [];
var pointListY:Array = [];
var i:int;
var l:int = _boneList.length;
for (i=0; i < l; i++){
var bone:BoneCircle = _boneList[i];
var cosR:Number = Math.cos(bone.radian + _PI/2)*bone.radius;
var sinR:Number = Math.sin(bone.radian + _PI/2)*bone.radius;
pointListX.push(bone.x + cosR);
pointListY.push(bone.y + sinR);
pointListX.unshift(bone.x - cosR);
pointListY.unshift(bone.y - sinR);
}
var g:Graphics = _alphaLayer.graphics;
g.clear();
g.beginFill(_COLOR, 1);
l = pointListX.length - 1;
i = 0;
var baceX:Number = (pointListX[i] + pointListX[i+1])/2;
var baceY:Number = (pointListY[i] + pointListY[i+1])/2;
g.moveTo(baceX, baceY);
for (i=1; i < l; i++){
g.curveTo(pointListX[i], pointListY[i], (pointListX[i] + pointListX[i+1])/2, (pointListY[i] + pointListY[i+1])/2);
}
g.lineTo(baceX, baceY);
_alphaChannel.copyPixels(_clear, _rect, _point);
_alphaChannel.draw(_alphaLayer);
_displayBitmapData.lock();
_displayBitmapData.copyPixels(_clear, _rect, _point);
_displayBitmapData.draw(_boneLayer);
_displayBitmapData.copyChannel(_alphaChannel, _rect, _point, BitmapDataChannel.ALPHA, BitmapDataChannel.ALPHA);
_displayBitmapData.applyFilter(_displayBitmapData, _rect, _point, _bevel);
_displayBitmapData.unlock();
}
private var _shadowMatrix:Matrix = new Matrix(1, 0, 0, 0.5, 0, STAGE_H/2-30);
private var _shadowColor:ColorTransform = new ColorTransform(0,0,0,1, 0,0,0,0);
private var _shadowBlur:BlurFilter = new BlurFilter(30, 30, 1);
private function drawShadow():void{
_shadow.lock();
_shadow.copyPixels(_gray, _rect, _point);
_shadow.draw(_alphaLayer, _shadowMatrix, _shadowColor);
_shadow.applyFilter(_shadow, _rect, _point, _shadowBlur);
_shadow.draw(_cover);
_shadow.unlock();
}
// デバッグ表示。
private function debugDraw():void{
}
// マウスイベント
private function bornMouseDownEvent(i:int):Function{
return function (event:Event):void{ startBornDrag(i);};
}
private function bornMouseUpEvent():Function{
return function (event:Event):void{ endBornDrag();};
}
// ドラッグ
private function startBornDrag(bornNum:int):void{
_dragId = bornNum;
}
private function endBornDrag():void{
_dragId = -1;
}
private function key(event:KeyboardEvent):void{
if (event.keyCode == 76){ // L
trace("changeLock");
_topLock = !_topLock;
}
/*
if (event.keyCode == 68){ // D
trace("changeDisplay");
_boneLayer.alpha = _boneLayer.alpha ? 0 : 1;
}*/
}
}
}
import flash.display.Sprite;
import flash.display.Graphics;
import flash.geom.Matrix;
import flash.display.GradientType;
class BoneCircle extends Sprite
{
public var radius:Number; // 半径
public var connectLength:Number; // 次パーツとのつながりの長さ
public var radian:Number = 0; // 一時的な回転量。
public var color:uint;
public var vx:Number = 0;
public var vy:Number = 0;
public var vr:Number = 0;
public function BoneCircle(radius:Number, connectLength:Number, color:uint, colorSize:Number)
{
this.radius = radius;
this.connectLength = connectLength;
this.color = color;
// マウスでつかめるように広めに範囲をとる
graphics.beginFill(0x000000, 0);
graphics.lineStyle(0, 0, 0);
graphics.drawCircle(0, 0, radius + 20);
var r:Number = colorSize;
var matrix:Matrix = new Matrix()
matrix.createGradientBox(r*2, r*2, 0, -r, -r);
graphics.beginGradientFill(GradientType.RADIAL, [color, color], [1, 0], [0, 255], matrix);
graphics.drawCircle(0, 0, r);
}
}