In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

forked from: 吹き出しクラス

Get Adobe Flash player
by ezshine 28 Apr 2009
// forked from tatsuya's 吹き出しクラス
package {
    import flash.display.Sprite;
    [SWF(width=465, height=465, backgroundColor=0xFFFFFF, frameRate=30)]

    public class FlashTest extends Sprite {
        public function FlashTest() {
            var textStr1:String = "あんなの飾りです。偉い人にはそれが分からんのですよ。\n(通常モード)あんなの飾りです。偉い人にはそれが分からんのですよ。\n(通常モード)";
            var textStr2:String = "あんなの飾りです。偉い人にはそれが分からんのですよ。\n(debugモード)";
            var fukidashi1:Fukidashi = new Fukidashi(stage, 70 , 250 , 150 , textStr1);//通常モードでオブジェクト作成
	    var fukidashi2:Fukidashi = new Fukidashi(stage, 270 , 250 , 150 , textStr2, true);//debugモードでオブジェクト作成
       }
    }
}

import flash.accessibility.AccessibilityProperties;
import flash.display.*;
import flash.events.*;
import flash.geom.Point;
import flash.text.*;

internal class Fukidashi {
		
		public var bottomSheet:Sprite;//このクラスで描画するのを乗せるSprite
		
		public const REP_LENGTH:Number=2;//コントロールポイントの位置を決めるための代表値
		public const PADDING:Number=5;
		
		public const TAIL_POSITION:uint = 5;//この番号のラインの途中に尻尾を作成(変えるとだめ!)
		public const TAIL_POSITION_RATE:Number = 0.5;//ベジェ曲線のtがこの値を中心として尻尾が生える
		public const TAIL_WIDTH_RATE:Number = 0.04;//TAIL_POSITION_RATE-TAIL_WIDTH_RATE ~ TAIL_POSITION_RATE+TAIL_WIDTH_RATE で尻尾の根元
		
		
		public var commentTF:TextField;//文字列はこのテキストフィールドで表示
		
		
		public function Fukidashi(st:Object , tailX0:Number , tailY0:Number, w0:Number , textStr:String , fDebug:Boolean=false) {// コンストラクタ
			
			var ii:uint;
			var h0:Number;//文字列を表示する高さ(横幅w0は引数で受け、文字数によりh0を後で決めてます)
			
			
			//bottomSheetの作成
			bottomSheet = new Sprite();
			st.addChild(bottomSheet);
			bottomSheet.visible = true;//デフォルトは表示
			
			if (fDebug) {
				var debugSheet:Sprite = new Sprite();//デバッグ用の点などはここに描きます
			}
			
			
			//デバッグ時のみtailX0 , tailY0の表示
			if (fDebug) {
				var tailTopSpr:Sprite = new Sprite();
				tailTopSpr.graphics.beginFill(0xFF0000);
				tailTopSpr.graphics.drawCircle(tailX0, tailY0, 3);
				tailTopSpr.graphics.endFill();
				st.addChild(tailTopSpr);
			}
			
			
			//テキストフィールド設定
			commentTF= new TextField();
			commentTF.text = textStr;
			commentTF.width = w0 + 4;
			commentTF.multiline = true;
			commentTF.wordWrap = true;
			h0 = commentTF.textHeight + 4;//ここでテキストフィールドの高さを決めてます
			commentTF.height = h0;
			
			if (fDebug) {
				//テキストフィールドのデバッグ用表示
				var displayArea:Sprite = new Sprite();
				displayArea.graphics.beginFill(0xEEEEEE);
				displayArea.graphics.drawRect(0, 0, w0, h0);
				displayArea.graphics.endFill();
				debugSheet.addChild(displayArea);
				
				//PADDINGを考慮した外枠の表示(ここにアンカーポイントが乗ります)
				var displayFrame:Sprite = new Sprite();
				displayFrame.graphics.lineStyle(0, 0xAAAAAA);
				displayFrame.graphics.drawRect(-PADDING, -PADDING, w0+2*PADDING, h0+2*PADDING);
				debugSheet.addChild(displayFrame);
			}
			
			
			//アンカーポイント
			var anchorPoint:Array = new Array();
			anchorPoint.push(new Point(w0 *0.11, -PADDING ) ) ;
			anchorPoint.push(new Point(w0 *0.675, -PADDING ) ) ;
			anchorPoint.push(new Point(w0 + PADDING , h0 *0.21));
			anchorPoint.push(new Point(w0 + PADDING , h0 *0.9));
			anchorPoint.push(new Point(w0 *0.825, h0 + PADDING ) ) ;
			anchorPoint.push(new Point(w0 *0.36, h0 + PADDING ) ) ;
			anchorPoint.push(new Point(-PADDING , h0 *0.85));
			anchorPoint.push(new Point( -PADDING , h0 * 0.25));
			
			var nAnchorPoint:int = anchorPoint.length;//アンカーポイントの数
			
			if (fDebug) {//アンカーポイントのデバッグ用表示
				for (ii = 0; ii < nAnchorPoint; ii++) drawDebugDot(anchorPoint[ii].x , anchorPoint[ii].y , 0x0000CC);
			}
			
			
			//コントロールポイントの位置を決める係数
			//※コントロールポイント座標はアンカーポイントからの相対座標で、この係数とREP_LENGTHから決まります
			var keisuuArr:Array = new Array();
			keisuuArr.push( { x:1.6 , y:-2.4 } );
			keisuuArr.push( { x:-2.4 , y:-2 } );
			keisuuArr.push( { x:8.2 , y:-2 } );
			keisuuArr.push( { x:1.8 , y:-5.6 } );
			keisuuArr.push( { x:1.6 , y:2.8 } );
			keisuuArr.push( { x:1.4 , y:-2.6 } );
			keisuuArr.push( { x:0.8 , y:3.6 } );
			keisuuArr.push( { x:3.8 , y:1.2 } );
			keisuuArr.push( { x:-3.2 , y:1.8 } );
			keisuuArr.push( { x:3.4 , y:2 } );
			keisuuArr.push( { x:-5.4 , y:2.4 } );
			keisuuArr.push( { x:-1.6 , y:5 } );
			keisuuArr.push( { x:-1.4 , y:-2 } );
			keisuuArr.push( { x:-1.6 , y:2.4 } );
			keisuuArr.push( { x:-1 , y:-2.4 } );
			keisuuArr.push( { x: -5.2 , y: -0.8 } );
			
			
			//コントロールポイント
			var controlPoint:Array = new Array();
			//コントロールポイント座標計算
			var ite1:int, ite2:int, xx:Number, yy:Number;
			for (ii = 0; ii < nAnchorPoint; ii++) {
				
				ite2 = ii * 2;
				ite1 =  (ite2 - 1 == -1) ? 15 : ite2 - 1;
				
				xx = REP_LENGTH * keisuuArr[ite1].x;
				yy = REP_LENGTH * keisuuArr[ite1].y;
				controlPoint.push(new Point(xx, yy));
				
				xx = REP_LENGTH * keisuuArr[ite2].x;
				yy = REP_LENGTH * keisuuArr[ite2].y;
				controlPoint.push(new Point(xx, yy));
				
			}
			var nControlPoint:int = controlPoint.length;//コントロールポイントの数
			
			
			//ベジェ曲線を描く
			//※輪郭は3次ベジェ曲線を直線をつないで表示、尻尾部分は2次ベジェ曲線(curveToメソッド)で表示してます
			var tailTopPt:Point;//尻尾の先端の座標
			var p0:Point, p1:Point, p2:Point, p3:Point , t:Number, pt:Point , dt:Number=0.02;
			var nextnn:uint;
			var bezierCurveSpr:Sprite = new Sprite();//ベジェ曲線はここに乗せます
			bottomSheet.addChild(bezierCurveSpr);
			bezierCurveSpr.graphics.beginFill(0xFFFFFF);//吹き出し内部の色
			bezierCurveSpr.graphics.lineStyle(0, 0x333333);//吹き出しの線の幅と色
			for (ii = 0; ii < nAnchorPoint; ii++) {
				drawBezierCurve(ii);
			}
			bezierCurveSpr.graphics.endFill();
			function drawBezierCurve(nn:uint):void {//ベジェ曲線を描く
				
				p0 = new Point(anchorPoint[nn].x , anchorPoint[nn].y);//アンカーポイント
				nextnn = (nn + 1 == nAnchorPoint) ? 0 : nn + 1;//最後だと次のnnは0になる
				p3 = new Point(anchorPoint[nextnn].x , anchorPoint[nextnn].y);//アンカーポイント
				
				ite1 = nn * 2 + 1;
				ite2 =  (ite1 + 1 == nControlPoint) ? 0 : ite1 + 1;
				
				p1 = new Point(p0.x+controlPoint[ite1].x , p0.y+controlPoint[ite1].y);//コントロールポイント
				p2 = new Point(p3.x+controlPoint[ite2].x , p3.y+controlPoint[ite2].y);//コントロールポイント
				
				if (fDebug) {//デバッグ時のコントロールポイントの表示
					drawDebugDot(p1.x , p1.y , 0x990000);
					drawDebugDot(p2.x , p2.y , 0x990000);
				}
				
				if (nn==0) bezierCurveSpr.graphics.moveTo(p0.x, p0.y);//最初だけmoveするけどそれ以降は不要
				
				for (t = 0.0; t <= 1.0; t += dt) {
					if ( (nn == TAIL_POSITION) && (TAIL_POSITION_RATE - TAIL_WIDTH_RATE < t) && (t < TAIL_POSITION_RATE + TAIL_WIDTH_RATE) ) {//尻尾の根元の部分か?
						
						if ( (TAIL_POSITION_RATE-dt/2 < t)&&(t < TAIL_POSITION_RATE+dt/2) ) {
							//↑t==TAIL_POSITION_RATEで評価すると誤差のせいかtrueにならないことがあったのでこんな風にしてます
							//↑がtrueの場合のみ1回だけ↓の関数をCALLして尻尾を描きます
							drawTail(getBezierPoint(TAIL_POSITION_RATE-TAIL_WIDTH_RATE),getBezierPoint(t),getBezierPoint(TAIL_POSITION_RATE+TAIL_WIDTH_RATE));
						}
					}else{//通常こちらで輪郭を描く
						pt = getBezierPoint(t);
						bezierCurveSpr.graphics.lineTo(pt.x, pt.y);
					}
				}
				bezierCurveSpr.graphics.lineTo(p3.x, p3.y);
			}
			function drawTail(tailPtA:Point, tailPtC:Point, tailPtB:Point):void {//尻尾部分の描画(ここは1回だけCALLされます)
				//ここは2次のベジェ曲線(curveToメソッド)で描く
				tailTopPt= new Point(tailPtC.x - 17 , tailPtC.y + 20);//尻尾の先っぽの位置をこのようにして決めてます
				
				//第1の線
				drawATailCurve(1, tailPtA, tailTopPt);
				
				//第2の線
				drawATailCurve(2, tailTopPt, tailPtB);
				
				function drawATailCurve(curveNumber:uint, p0:Point , p1:Point):void {//1つの2次ベジェ曲線を描きます
					//p0,p1はアンカーポイント
					var pCent:Point;//2つのアンカーポイントの中点
					var pCont:Point;//コントロールポイント
					pCent = new Point( (p0.x + p1.x) / 2 , (p0.y + p1.y) / 2);
					
					//コントロールポイントは中点を通り、アンカーポイントを結ぶ直線と直交する直線上にあるように計算
					var tpt1:Point , tpt2:Point, rad:Number = 10 * Math.PI / 180;//この角度を小さくするほど直線に近くなる
					if (curveNumber==2) rad *= -1;
					var xl1:Number = p0.x - pCent.x;
					var yl1:Number = p0.y - pCent.y;
					tpt1 = new Point(pCent.x + Math.cos(rad) * xl1 - Math.sin(rad) * yl1 , pCent.y + Math.sin(rad) * xl1 + Math.cos(rad) * yl1);
					rad *= -1;
					xl1 = p1.x - pCent.x;
					yl1 = p1.y - pCent.y;
					tpt2 = new Point(pCent.x + Math.cos(rad) * xl1 - Math.sin(rad) * yl1 , pCent.y + Math.sin(rad) * xl1 + Math.cos(rad) * yl1);
					
					pCont = new Point( (tpt1.x + tpt2.x) / 2 , (tpt1.y + tpt2.y) / 2);
					
					bezierCurveSpr.graphics.curveTo(pCont.x , pCont.y , p1.x , p1.y);//2次ベジェ曲線
				}
			}
			function getBezierPoint(t:Number):Point {//3次ベジェ曲線を求める式
				return new Point(Math.pow(1 - t, 3)  * p0.x + 3 * t * Math.pow(1 - t, 2) * p1.x + 3 * t * t * (1 - t) * p2.x + t * t * t * p3.x , Math.pow(1 - t, 3)  * p0.y + 3 * t * Math.pow(1 - t, 2) * p1.y + 3 * t * t * (1 - t) * p2.y + t * t * t * p3.y);
			}
			
			
			//位置調整(引数の座標に尻尾の先が来るようにbottomSheetを移動)
			bottomSheet.x = tailX0-tailTopPt.x;
			bottomSheet.y = tailY0-tailTopPt.y;
			
			
			//デバッグ時のみ
			if (fDebug) bottomSheet.addChild(debugSheet);
			
			
			//テキストフィールド
			bottomSheet.addChild(commentTF);//ベジェ曲線より後じゃないとだめなのでここでaddChildしてます
			
			
			function drawDebugDot(xx:Number , yy:Number , color:Number):void {//デバッグ用の点の表示
				var dot:Sprite = new Sprite();
				dot.graphics.beginFill(color);
				dot.graphics.drawCircle(xx, yy, 3);
				dot.graphics.endFill();
				debugSheet.addChild(dot);
			}
		}////////////////////////////////////////////////////////////////////////////////コンストラクタ
		
		
		
		////////////////////////////////////////////////////////////////////////////////
		public function set visible(f:Boolean):void {
			bottomSheet.visible = f;
		}////////////////////////////////////////////////////////////////////////////////
}