Macっぽい球体を描画するAquaSphere.as

iDrop2007-09-26


Macっぽい球体を描画するAS2用クラスを作ってみました。
AquaSphere.as

サンプルは、にゃあプロジェクト様のところで、素敵なのを作っていただいちゃいましたので、そちらをご覧ください。

上記の他に、以下のライブラリが必要ですので、それぞれのサイトからDLしてください。

  1. CASA Framework(ご存知AS2用便利ライブラリ。楕円の描画に利用)
  2. ColorConversion.as(神コーダーGuy WatsonさんのRGB/HSB変換クラス)

(昨日あたりから、なぜかGuy Watsonさんのサイトflashguru.co.ukにアクセスできない模様です。サイトが復旧するまで一時的に、僕がDLしたasファイルをこちらにUPさせていただきます。)

AquaSphereの使い方はこんな感じです。

var target:MovieClip = this	//描画先
var hue:Number = 230;		//色相(0〜360)
var radius:Number = 100;	//球の半径
var x:Number = 10;			//x座標
var y:Number = 10;			//y座標
var hasDropShadow:Boolean = true;	//ドロップシャドウの有無

var sphere:AquaSphere = new AquaSphere(target, hue, radius, x, y, hasDropShadow);

パラメータの「色相(hue)って何じゃい?」という方は、Wikiのこのページ に詳しい解説がありますが、「そんなの読んでられねーだろ、ゴルァ」というやんちゃな方は、「色相とは色味(いろみ)のことで、0〜360度で表現されるもの」と考えてもらえばよろしいかと思います。ちなみにFlashのカラーウィンドウもデフォルトはRGBでの設定となっていますが、オプション(右上の三角)でHSBでの設定へ変更することができまするんですよぉ。

インスタンス化したAquaSphereオブジェクトのカラーを変更するには、colorize(hue)というメソッドをご利用ください。

sphere.colorize(110)


ところで、このクラスには、どうもイケてない点があります。それは、例えばこのオブジェクトの透明度を変えたいとか、マウスイベントを設定したいという場合、ムービークリップと同様に

sphere._alpha = 80;
sphere.onRollOver = function() {
	trace("onRollOver");
}

みたいなスクリプトが書けるようにしたいのです。ですが、「それじゃあ、MovieClipクラスを継承させればokじゃん」と、そのようにしてみたところ、どうも上手くいきませんでした。この件については、後日エントリーするつもりですが、現在はMovieClipクラスを継承しないで、上記のようなケースの対応は、

var wrapper:MovieClip = sphere.getWrapper();
wrapper._alpha = 80;
wrapper.onRollOver = function():Void {
	trace ("onRollOVer");
}

のように、AquaSphereクラス内で生成している全ての描画オブジェクトを内包しているMovieClipへの参照を返すgetWrapper()というメソッドを利用し、このオブジェクトのプロパティやメソッドを操作する、という苦肉の策を採っています。

んー、我ながらイケてない…。

最後に一応、スクリプトを晒しておきます。「ここ変だよ」とかいう部分がありましたら、本人が凹まない程度にご指摘いただけましたら幸いでございます。

import ColorConversion;
import flash.filters.BlurFilter;
import flash.filters.DropShadowFilter;
import flash.filters.GlowFilter;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Transform;
import org.casaframework.math.geom.Ellipse;
import org.casaframework.util.DrawUtil;

class AquaSphere {
	
	private static var DROP_SHADOW_DEPTH:Number = 0;
	private static var BASE_CIRCLE_DEPTH:Number = 1;
	private static var HIGHLIGHT_DEPTH:Number = 2;
	private static var INNER_GLOW_DEPTH:Number = 3;
	private static var BASE_SATURATION:Number = 75;
	private static var BASE_BRIGHTNESS:Number = 78;
	
	private var holderClip:MovieClip;
	private var baseClip:MovieClip;
	private var innerGlowClip:MovieClip;
	private var dropShadowClip:MovieClip;
	private var baseEllipse:Ellipse;
	private var highlightClip:MovieClip;
	private var radius:Number;
	private var baseHue:Number;	
	private var hasDropShadow:Boolean = false;
	
	/*
	 * AquaSphereコンストラクタ
	 * @param target:MovieClip AquaSphereオブジェクトの生成先
	 * @param hue:Number 球体のベースカラーの色相(0〜360)
	 * @param r:Number 半径
	 * @param x:x座標
	 * @param y:y座標
	 * @param bDropShadow:Boolean
	 */
	public function AquaSphere(target:MovieClip, hue:Number, r:Number, x:Number, y:Number, bDropShadow:Boolean) {
		holderClip = target.createEmptyMovieClip("holderClip", target.getNextHighestDepth());
		radius = r;
		hasDropShadow = bDropShadow;
		holderClip._x = x;
		holderClip._y = y;
		buildClips();
		colorize(hue);
	}
	
	/*
	 * 球のカラーを変更
	 * @param hue:色相(0〜360)
	 */
	public function colorize(hue:Number):Void {
		setBaseHue(hue);
		colorBaseClip();
		colorInnerGlowClip();
	}
	
	/*
	 * ドロップシャドウの表示/非表示の切替え
	 */
	public function toggleDropShadow():Void {
		if (hasDropShadow) {
			removeMovieClip(dropShadowClip);
		} else {
			buildDropShadowClip();
		}
		hasDropShadow = !hasDropShadow;
	}
	
	/*
	 * ラッパーMovieClipを参照
	 */
	public function getWrapper():MovieClip {
		return holderClip;
	}
	
	/*
	 * 色相の設定
	 */
	private function setBaseHue(hue:Number):Void {
		hue %= 360;
		if (hue < 0) hue += 360;
		baseHue = Math.floor(hue);
	}
	
	/*
	 * 必要なMovieClipを生成
	 */
	private function buildClips():Void {
		buildBaseClip();
		buildHighlightClip();
		buildInnerGlowClip();
		if (hasDropShadow != false) buildDropShadowClip();
	}
	
	/*
	 * ベースとなるMovieClipを生成
	 */
	private function buildBaseClip():Void {
		var diameter:Number = radius * 2;
		baseClip = holderClip.createEmptyMovieClip("baseClip", BASE_CIRCLE_DEPTH);
		baseEllipse = new Ellipse(0, 0, diameter, diameter);
	}
	
	/*
	 * 球体上部の光の反射を表現するMovieClipを生成
	 */
	private function buildHighlightClip():Void {
		highlightClip = holderClip.createEmptyMovieClip("innerGlow", HIGHLIGHT_DEPTH);
		var diameter:Number = radius * 2 * 0.9;
		var x:Number = -(diameter / 2);
		var y:Number = 0;
		var highlightEllipse:Ellipse = new Ellipse(x, y, diameter, diameter);
		highlightClip._x = radius;
		highlightClip._y = radius * .05;
		
		var fillType:String = "linear"
		var colors:Array = [0xffffff, 0xffffff];
		var alphas:Array = [100, 0];
		var ratios:Array = [0, 255 * .75];
		var matrix:Matrix = new Matrix();
		var offsetX:Number = -(diameter / 2);
		var offsetY:Number = 0;
		matrix.createGradientBox(diameter, diameter, 90 * Math.PI / 180, offsetX, offsetY);
		highlightClip.beginGradientFill(fillType, colors, alphas, ratios, matrix);
		DrawUtil.drawEllipse(highlightClip, highlightEllipse);
		highlightClip.endFill();
		highlightClip._xscale = 80;
		highlightClip._yscale = 75;
		highlightClip._alpha = 70;
	}
	
	/*
	 * 球体の内側の光彩を表現するMovieClipを生成
	 */
	private function buildInnerGlowClip():Void {
		innerGlowClip = highlightClip.duplicateMovieClip("innerGlow", INNER_GLOW_DEPTH);
		innerGlowClip._rotation += 180;
		innerGlowClip._y = (radius * 2) - (radius * .1);
	}
	
	/*
	 * ドロップシャドウ用のMovieClipを生成し、DropShadowエフェクトを適用
	 */
	private function buildDropShadowClip():Void {
		dropShadowClip = holderClip.createEmptyMovieClip("dropShadowClip", DROP_SHADOW_DEPTH);
		var diameterX:Number = radius * 1.5;
		var diameterY:Number = radius * .45;
		var ellipse:Ellipse = new Ellipse(0, 0, diameterX, diameterY);
		dropShadowClip.beginFill(0x000000);
		DrawUtil.drawEllipse(dropShadowClip, ellipse);
		dropShadowClip.endFill();
		dropShadowClip._x = (radius * 2 - diameterX) / 2;
		dropShadowClip._y = (radius * 2 - diameterY) / 2;
		
		var distance:Number = radius;
		var angleInDegrees:Number = 90;
		var color:Number = 0x000000;
		var alpha:Number = .5;
		var blurX:Number = diameterX / 10;
		var blurY:Number = blurX;
		var strength:Number = 1;
		var quality:Number = 3;
		var inner:Boolean = false;
		var knockout:Boolean = false;
		var hideObject:Boolean = true;
		var dropShadow:DropShadowFilter = new DropShadowFilter(distance, 
																angleInDegrees, 
																color, 
																alpha, 
																blurX, 
																blurY, 
																strength, 
																quality, 
																inner, 
																knockout, 
																hideObject);
		var filterList:Array = [dropShadow];
		dropShadowClip.filters = filterList;
	}
	
	/*
	 * ベースのカラー設定
	 */
	private function colorBaseClip():Void {
		var baseRgbHex:Number = ColorConversion.hsbtohex24(baseHue, BASE_SATURATION, BASE_BRIGHTNESS);
		baseClip.beginFill(baseRgbHex);
		DrawUtil.drawEllipse(baseClip, baseEllipse);
		baseClip.endFill();
		
		var hue:Number = (baseHue + 6) % 360;
		var saturation:Number = BASE_SATURATION - 25;
		var brightness:Number = BASE_BRIGHTNESS - 25;
		var shadowRGB:Object = ColorConversion.hsbtorgb(hue, saturation, brightness);		
		var shadowRgbHex:Number = ColorConversion.rgbtohex24(shadowRGB.red, shadowRGB.green, shadowRGB.blue);
		var alpha:Number = 1;
		var blurX:Number = radius / 2;
		var blurY:Number = blurX;
		var strength:Number = 2;
		var quality:Number = 3;
		var inner:Boolean = true;
		var knockout:Boolean = false;
		var innderShadow:GlowFilter = new GlowFilter(shadowRgbHex, 
														alpha, 
														blurX, 
														blurY, 
														strength, 
														quality, 
														inner, 
														knockout);
		var filterList:Array = [innderShadow];
		baseClip.filters = filterList;
	}
	
	/*
	 * 内側の光彩のカラー設定
	 */
	private function colorInnerGlowClip():Void {
		var colorTrans:ColorTransform = new ColorTransform();
		var trans:Transform = new Transform(innerGlowClip);
		var hue:Number = (baseHue - 30) % 360;
		if (hue < 0) hue += 360;
		var saturation:Number = 100;
		var brightness:Number = 100;
		var glowRbg:Object = ColorConversion.hsbtorgb(hue, saturation, brightness)
		var glowRgbHex:Number = ColorConversion.rgbtohex24(glowRbg.red, glowRbg.green, glowRbg.blue);
		colorTrans.rgb = glowRgbHex;
		trans.colorTransform = colorTrans;
		
		var blurLen:Number = radius * .15;
		var blurQuality:Number = 3;
		var blur:BlurFilter = new BlurFilter(blurLen, blurLen, blurQuality);
		var filterList:Array = [blur];
		innerGlowClip.filters = filterList;
		innerGlowClip.blendMode = "multiple";
	}
	
}