forked from: Marimo : moves by mouse.
動かしてみる。けど重いね…
目を入れてみる。
/**
* Copyright nutsu ( http://wonderfl.net/user/nutsu )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/mHSL
*/
// forked from tail_y's Marimo
// 動かしてみる。けど重いね…
// 目を入れてみる。
package {
import flash.display.GradientType;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.Event;
import frocessing.geom.FGradientMatrix;
import frocessing.math.FMath;
public class Marimo extends Sprite {
// 空飛ぶマリモ的な物を作る。
// 実際の構造は、マリモというか、やわらかいウニ。
// 球形の表面からパーティクルを飛ばして、それを線で繋ぐ。
// 問題点:線のつなぎ目が汚い 毛の長さが重力によって伸びてしまう ちょっと重い
// できそうなこと:ビットマップにピクセルで描いて縮小するようにすれば、軽くなるかも。パーティクルを制御すれば、地面と毛が接する表現になるかも
public static const STAGE_W:uint = 465;
public static const STAGE_H:uint = 465;
public static const SPHERE_R:Number = 40; // マリモの体の(毛以外の部分の)半径。
public static const PARTICLE_NUM_RATE:uint = 40; // 球体の半円を分割する数。
public static const PARTICLE_STEP:uint = 4; // 線の描画回数。大きいほど長くなる。
public static const PARTICLE_V:uint = 8*PARTICLE_STEP; // 線の勢い。大きいほど長く、粗くなる。
public static const GRAVITY:Number = 0.8; // 重力。毛の長さ補正をしていないので、重力が強すぎると毛が伸びる
public static const RANDOM_RATE:Number = 0.8; // バラつき具合
public static const COLOR_RANDOM_RATE:Number = 0.3; // 色のバラつき具合
public static const GROUND_Y:Number = 400; // 地面位置
public static const SHADOW_W:Number = 150; // 影サイズ
public static const GROUND_H:Number = 30; // 影サイズ
private var _marimoX:Number = STAGE_W/2; // マリモの位置
private var _marimoY:Number = STAGE_H/2 - 50;
private var _display2:Sprite;
public static const COLOR_TIP_TOP:Number = 0x77cc44; // 毛先上部
public static const COLOR_TIP_BOTTOM:Number = 0x339900; // 毛先下部
public static const COLOR_BACE_TOP:Number = 0x116600; // 本体上部
public static const COLOR_BACE_BOTTOM:Number = 0x003300; // 本体下部
private var g:Graphics;
private var gmtx:FGradientMatrix;
private var furalphas:Array = [1,0];
private var furratios:Array = [0,255];
private var furs:Array;
private var offsetX:Number;
private var offsetY:Number;
private var targetX:Number;
private var targetY:Number;
private var draw_gravity:Number;
private var eyeX1:Number = SPHERE_R / 2;
private var eyeX2:Number = -eyeX1;
private var eyeY:Number = -SPHERE_R/4;
private var eyeR:Number = 6;
public function Marimo() {
addEventListener( Event.ADDED_TO_STAGE, init );
}
private function init(e:Event):void {
stage.quality = "medium";
//
_display2 = new Sprite();
addChild(_display2);
//matrix for gradient
gmtx = new FGradientMatrix();
// graphics
g = _display2.graphics;
g.lineStyle();
//
makeFurs();
offsetX = targetX = 0;
offsetY = targetY = 0;
//
addEventListener( Event.ENTER_FRAME, drawMarimo );
}
private function makeFurs():void
{
furs = [];
// 毛
for (var xri:uint = 0; xri < PARTICLE_NUM_RATE; xri++){ // zを先に計算して、奥から手前へ描画
var xAngle:Number = Math.PI*xri / PARTICLE_NUM_RATE; // マリモ中心点から、マリモ表面へのx方向に対する角度
var z:Number = Math.cos(xAngle) * SPHERE_R; // パーティクルを飛ばす原点Z
var r:Number = Math.sin(xAngle) * SPHERE_R; // その時の、断面の半径
// z方向に向いた面の円周上にある点の数。円周の比(=半径の比)で割り出すが、整数に丸めるので、正確ではない。
// (右側でそろっちゃうのが気持ち悪い。ランダムでz回転させてもいいかも。)
var particleRateZ:int = PARTICLE_NUM_RATE * 2 * r / SPHERE_R;
for (var zri:uint = 0; zri < particleRateZ; zri++){ // z方向面に対して、時計回りに描画
var zAngle:Number = Math.PI*zri*2 / particleRateZ; // マリモ中心点から、マリモ表面へのz方向に対する角度
var x:Number = Math.cos(zAngle) * r; // パーティクルを飛ばす原点X
var y:Number = Math.sin(zAngle) * r; // パーティクルを飛ばす原点Y
var vx:Number = PARTICLE_V * x / SPHERE_R; // パーティクルの速度X
var vy:Number = PARTICLE_V * y / SPHERE_R; // パーティクルの速度Y
// 方向をランダムでバラす。(本来は、円形方向へランダムにしなきゃいけないのだけど、面倒なのでこれで)
vx += (PARTICLE_V * RANDOM_RATE) * (0.5 - Math.random());
vy += (PARTICLE_V * RANDOM_RATE) * (0.5 - Math.random());
// 色を決める。上下の位置と、根本までの割合で色を決定する。ランダムもちょっと入れておく。
var yColorRate:Number = ((SPHERE_R + y)/ 2 / SPHERE_R) + COLOR_RANDOM_RATE * (0.5 - Math.random());
var color0:Number = mixColor(COLOR_BACE_TOP, COLOR_BACE_BOTTOM, yColorRate);
var color1:Number = mixColor(COLOR_TIP_TOP, COLOR_TIP_BOTTOM, yColorRate);
// 毛
if( FMath.dist(x,y,eyeX1,eyeY)<eyeR || FMath.dist(x,y,eyeX2,eyeY)<eyeR )continue;
var fur:FurInfo = new FurInfo();
fur.x = _marimoX + x;
fur.y = _marimoY + y;
fur.vx = vx;
fur.vy = vy;
fur.colors = [color0, color1];
furs.push( fur );
}
}
eyeX1 += _marimoX;
eyeX2 += _marimoX;
eyeY += _marimoY;
}
private function drawMarimo( e:Event ):void
{
g.clear();
targetX = (mouseX - _marimoX);
targetY = (mouseY - _marimoY) / 2;
var ax:Number = ( targetX - offsetX );
var ay:Number = ( targetY - offsetY );
var gr:Number = FMath.constrain( GRAVITY - ay / 30, -GRAVITY, 1.5 * GRAVITY );
offsetX += ax * 0.2;
offsetY += ay * 0.2;
draw_gravity = GRAVITY * gr * PARTICLE_STEP * PARTICLE_STEP;
ax = FMath.constrain( ax, -PARTICLE_V/5, PARTICLE_V/5 );
// 影
var ss:Number = ( mouseY + 100 )/ 465;
gmtx.identity();
gmtx.scale( SHADOW_W*ss, GROUND_H*ss );
gmtx.translate( _marimoX+offsetX, GROUND_Y );
g.beginGradientFill(GradientType.RADIAL, [0x000000, 0x000000], [0.3, 0.0], [60, 255], gmtx);
g.drawRect(0, 0, STAGE_W, STAGE_H);
g.endFill();
// 本体
g.beginFill(COLOR_BACE_BOTTOM);
g.drawCircle(_marimoX+offsetX, _marimoY+offsetY, SPHERE_R);
g.endFill();
gmtx.createRadial( eyeX1+offsetX, eyeY+offsetY, eyeR, -Math.PI*0.25 );
g.beginGradientFill( "radial", [0xffffff,0],[1,1],[0,127],gmtx, "pad", "rgb", 0.6 );
g.drawCircle( eyeX1+offsetX, eyeY+offsetY, eyeR );
g.endFill();
gmtx.createRadial( eyeX2+offsetX, eyeY+offsetY, eyeR, -Math.PI*0.75 );
g.beginGradientFill( "radial", [0xffffff,0],[1,1],[0,127],gmtx, "pad", "rgb", 0.6 );
g.drawCircle( eyeX2+offsetX, eyeY+offsetY, eyeR );
g.endFill();
var len:int = furs.length;
for ( var i:int = 0; i < len; i++ )
{
var fur:FurInfo = furs[i];
drawFur( fur.x+offsetX, fur.y+offsetY, fur.vx-ax, fur.vy, fur.colors );
}
}
// 毛を描く
private function drawFur(x:Number, y:Number, vx:Number, vy:Number, colors:Array):void {
var x0:Number = x + vx * 0.75;
var y0:Number = y + vy * 0.75;
var x1:Number = x + vx;
var y1:Number = y + vy + draw_gravity;
var d:Number = Math.sqrt( vx * vx + vy * vy ) / 1.5;
gmtx.createLinear( x, y, x1, y1 );
g.beginGradientFill( "linear", colors, furalphas, furratios, gmtx );
g.moveTo( x, y );
g.curveTo( x0, y0, x1, y1 );
vx /= d;
vy /= d;
g.curveTo( x0+vy, y0-vx, x+vy, y-vx );
g.endFill();
}
// 2つの色を指定した割合で混ぜた色を返す(rate=0ならcolor0)。(ここもかなり軽量化できるはず。グラデーションをキャッシュとして使うとか)
private function mixColor(color0:uint, color1:uint, rate:Number):uint{
if (rate <= 0) return color0;
if (rate >= 1) return color1;
var r:uint = (color0>>16) * (1-rate)
+ (color1>>16) * rate;
var g:uint = ((color0 & 0x00ff00 ) >>8) * (1-rate)
+ ((color1 & 0x00ff00 ) >>8) * rate;
var b:uint = (color0 & 0xff) * (1-rate)
+ (color1 & 0xff) * rate;
return (r << 16) | (g << 8) | (b);
}
}
}
class FurInfo {
public var x:Number;
public var y:Number;
public var vx:Number;
public var vy:Number;
public var colors:Array;
public function FurInfo() {
}
}