POPSブログ

三次ベジェ曲線で文字を動かす/4

90

  Category:  as32012/04/21 pops 

三次ベジェ曲線で文字を動かす4、シュミュレーションテストのボタンなどを削除、コードを簡略化したものです。


三次ベジェ曲線と画像の運動、コードを簡略化

シュミュレーションテストでのコードは、ボタンなどが多くあり判り難いので、ボタンなどを削除、コードを簡略化したものです。
画像の運動の場合、文字を動かすのと構造が違いますので注意ください。



注意、FlashTest188c.swf、は画像を読み込んでいるため、当方専用になります。/main/images/xxx.jpg


簡単な説明

スクリプト中の画像URLを使用者の環境にあわせて書き換えてください。
スクリプトに詳細説明があります、条件を変えればそれなりに運動します。また前ページのシュミュレーションの説明と動作を確認ください。
また、新たなベジェ曲線を作り登録してもそれなりの運動をします。変更書き換えなどは自由です。


AS3

FlashTest188c.as


//動く画像表示テスト簡略化
//FlashTest188c
//三次ベジェ曲線
//
package
{
	
	import flash.display.*;
	import flash.events.*;
	import flash.net.*;
	import flash.geom.*;
	import flash.system.*;
	import flash.utils.*;
	import flash.text.*;
	import flash.filters.DropShadowFilter;
	
	//TweenLite
	import com.greensock.*;
	import com.greensock.easing.*;
	
	[SWF(width="465", height="465", frameRate="30", backgroundColor="0xFFFFFF")]

	public class FlashTest188c extends Sprite {
		
		//補間数(高いほど綺麗で重い)
		static public const	INTERPOLATE:Number = 50;
		private var d:Number = 0;// 係数
		private var plus:Number = 0.01;// 加算量
		
		//layer container
		private var container:Sprite;
		//TEXT
		private var tf:TextField;
		//BTN
		private var btn_1:Sprite;
		
		//MOVE-IMAGE
		private var photomax:int;
		//格納容器1
		private var bez_balls:Array = [];//要素bez_ball格納容器
		private var count_bez:Array = [];//INTERPOLATE減算用配列
		//ベジェ曲線
		private var p0:Object;
		private var p1:Object;
		private var p2:Object;
		private var p3:Object;
		private var first_points:Array = [];//同一地点オブジェクト格納容器

		//-------------------------------------------------------
		//画像指定pointer位置
		private var pointer_x:Number = 420;
		private var pointer_y:Number = 100;
		//container位置
		private var container_x:Number = 12;
		private var container_y:Number = 300;
		//距離/350以外は波形がかわる/その間隔のラインを作るのがベター
		private var ball_len_x:Number = 350;//350使用
		private var ball_len_y:Number = 350;//350未使用
		//初期位置を同一指定位置する
		private var firstPoint:int = 1;//0移動しない,1強制移動pointer位置
		//曲線番号
		private var no:int = 3;//0-5
		//回転数、360で1回転
		private var rot_v:Number = 360;//0,360,-360,180,-180
		//順序切り替え
		private var delay_no:int = 0;//0左,1右,2中,3外
		//遅延反転/注意、指定位置の場合に交互反転は機能しない
		private var inversion_v:int = 0;//0通常動作,2交互遅延,3交互反転
		//画像のおおきさ
		private var image_W:Number = 80;
		private var image_H:Number = 60;
		//-------------------------------------------------------

		//逆転係数
		private var chg_x:Number = 1;
		private var chg_y:Number = 1;
		private var chg_xyno:Number = 0;
		//グローバルカウント
		private var gl_count:int = 0;
		//LOADER
		private var loader:Loader;
		//Loading
		private var indicator:DisplayObject;
		//現在表示画像配列番号
		private var countImage:int = 0;
		//画像Bitmap
		private var mainImages:Array = [];//Array-Bitmap
		//画像収容Sprite
		private var mainImageBox:Sprite;
		//URL
		private var imageUrls:Array = [];
		//画像位置保存用	
		private var _arrX:Array = [];//X位置保存
		private var _arrY:Array = [];//Y位置保存
		private var _arrW:Array = [];//幅保存
		private var _arrH:Array = [];//高さ保存
		//Filter
		private var shade:DropShadowFilter;
		
		public function FlashTest188c():void {
						
			//BASE/白背景0xF0F0F0
			graphics.beginFill(0xF0F0F0);
			graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
			graphics.endFill();
			
			//text
			tf = createTextField(10,5, 300, 20);
			tf.textColor = 0x000000;
			tf.text = "";
			addChild(tf);
			
			//BTN-1
			btn_1 = createRoundBTN("アニメ", 13, 0x000000, 60, 20, 0xFF69B4, 1, 5);
			btn_1.x = 420;
			btn_1.y = 15;
			btn_1.buttonMode = true;
			addChild(btn_1);
			btn_1.visible = false;
			
			//MOVE文字containerレーヤー
			container = createSquare(0, 0, stage.stageWidth, 1, 0xEEEEEE, 0);
			container.x = container_x;
			container.y = container_y;
			addChild(container);
						
			//LOADING
			indicator = new Indicator();
			indicator.x = 12;
			indicator.y = 15;
			indicator.addEventListener(Event.ENTER_FRAME, step);//回転Listener
			addChild(indicator);
			indicator.visible = false;
			
			//goto-init
			init();
		}
		
		// INIT
		private function init():void {
						
			//goto-main
			main_action();
		}
		
		// MAIN-ACTION
		private function main_action():void {
			//main_action as3 hear
			tf.text = "三次ベジェ曲線";
			//画像読み込みURLセット
			loadImage_Url_Set();
		}
		
		// 画像URL-SET
		private function loadImage_Url_Set():void
		{
			//画像URL 80x60
			imageUrls = [
				"/main/images/photo_bz1.jpg",
				"/main/images/photo_bz2.jpg",
				"/main/images/photo_bz3.jpg",
				"/main/images/photo_bz4.jpg",
				"/main/images/photo_bz5.jpg"
			];
			
			//カウント
			countImage = 0;
			//画像数
			photomax = imageUrls.length;
			//LOADING表示
			indicator.visible = true;
			//GOTO-loadImage
			loadImage();
		}
		// 画像をロード
		private function loadImage():void
		{
			//loaderセット
			loader = new Loader();
			var imageName:String = imageUrls[countImage];
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete_img);
			loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);//Error
			loader.load(new URLRequest(imageName));//loader
		}

		private function onComplete_img(event:Event):void
		{
			loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete_img);
			tf.text = "画像読み込み中";
			
			//画像の加工保存
			//Matrixを使用した場合
			var mainloader:Loader = event.currentTarget.loader;
			var ratio:Number = image_W / loader.width;//縮尺比率
			var matrix:Matrix = new Matrix();
			matrix.scale(ratio, ratio);
			var bd2:BitmapData = new BitmapData(image_W, image_H, false);
			bd2.draw(mainloader, matrix);//Matrixを適応
			mainImages.push(bd2);
			
			//画像大きさ受け渡し
			_arrW.push(event.target.content.width);
			_arrH.push(event.target.content.height);
			
			countImage ++;
			
			//全て読み込んだら画像の加工に、まだなら残り画像をロードする
			if (countImage >= photomax) {
				//LOADING非表示
				indicator.visible = false;
				//画像をロード終了
				make_ImageBox();
				
			} else {
				//残り画像をLoad
				loadImage();
			}
			
		}

		//画像運動表示
		private function make_ImageBox():void {
			//max再計算
			photomax = mainImages.length;
			//Filter
			shade = new DropShadowFilter(1, 90, 0x000000, 0.4, 4, 4, 2, 3, false, false);
			var allpoint:Number = 0;
			var i:int = 0;
			for (i = 0; i < photomax; i++) {
				
				//BezImgBallクラス生成/Ballクラスに工夫しても、BallクラスにaddChildしても何らかの処理が可能
				var ball:BezImgBall = new BezImgBall(mainImages[i], _arrW[i], _arrH[i]);
				//識別番号をいれる
				ball.count_no = i;
				ball.filters = [shade];
				bez_balls[i] = ball;
				//X位置中心補正
				allpoint += _arrW[i]/2;
				_arrX[i] = allpoint;
				_arrY[i] = 0;//Yは0
				//間隔プラス
				allpoint += (_arrW[i]/2 + 10);
				container.addChild(ball);
				//
			}
			
			//btn_1にListenerを設定
			btn_1.addEventListener( MouseEvent.CLICK, show_image );			
			//GOTO-animate
			show_image();
			
		}
				
		//animate show-image
		private function show_image( e:MouseEvent = null ):void {
			
			tf.text = "三次ベジェ曲線 アニメ実行中";
			//ボタン非表示
			btn_1.visible = false;
			
//交互に変える/削除ください
if (firstPoint == 1) { firstPoint = 0; }
else { firstPoint = 1; }

			var p0_v:Object;
			var p1_v:Object;
			var p2_v:Object;
			var p3_v:Object;
			
			//ベジェ曲線サンプル波形 A-Bの間350
			//A-Bの間を変えられるようにしているが本来はかえないでその大きさの線形を作ること、変更すればゆがむ
			switch (no) {
				case 0:
					p0_v = {x:0,y:0};
					p1_v = {x:30,y:-150};
					p2_v = {x:320,y:-150};
					p3_v = {x:ball_len_x, y:0};
				break;
				case 1:
					p0_v = {x:0,y:0};
					p1_v = {x:130,y:-80};
					p2_v = {x:220,y:-80};
					p3_v = {x:ball_len_x,y:0};
				break;
				case 2:
					p0_v = {x:0,y:0};
					p1_v = {x:-130,y:-150};
					p2_v = {x:220,y:-80};
					p3_v = {x:ball_len_x,y:0};
				break;
				case 3:
					p0_v = {x:0,y:0};
					p1_v = {x:150,y:-180};
					p2_v = {x:200,y:180};
					p3_v = {x:350,y:0};
				break;
				case 4:
					p0_v = {x:0,y:0};
					p1_v = {x:0,y:150};
					p2_v = {x:130,y:220};
					p3_v = {x:ball_len_x,y:0};
				break;
				case 5:
					p0_v = {x:0,y:0};
					p1_v = {x:130,y:50};
					p2_v = {x:0,y:-250};
					p3_v = {x:ball_len_x,y:0};
				break;
				default:
					//ノーマル
					p0_v = {x:0,y:0};
					p1_v = {x:30,y:-150};
					p2_v = {x:320,y:-150};
					p3_v = {x:ball_len_x, y:0};
			}
			
			//位相切り替え
			p0_v.x *=chg_x;
			p0_v.y *=chg_y;
			p1_v.x *=chg_x;
			p1_v.y *=chg_y;
			p2_v.x *=chg_x;
			p2_v.y *=chg_y;
			p3_v.x *=chg_x;
			p3_v.y *=chg_y;

			//出現位置を文字初期位置に強制移動
			if (firstPoint) {
				p3_v = { x:pointer_x - container_x, y:pointer_y - container_y };
			}
			
			//グローバルに代入
			p0 = p0_v, p1 = p1_v, p2 = p2_v, p3 = p3_v;
			
			//順序切り替え
			var delay_v:Number = 0;
			var delay_total:Number = photomax * 0.5;
			var txline_mv:Number = (photomax - 1) / 2;
			//中外の場合加算する数値
			var d_chg_v:Number = Math.floor(Math.random() * 4 ) * 0.25;
			var flag3:int = 1;
			var i:int = 0;
			for (i = 0; i < photomax; i++) {
				
				//同一地点オブジェクト格納容器に要素ごとの初期位置を代入
				if (firstPoint) {
					first_points[i] = { x:pointer_x - container_x - _arrX[i], y:pointer_y - container_y - _arrY[i] }
				}
				//初期位置、ポインターにあわせる/1番目の位置、そのほかは実際右にある
				if (firstPoint) {
					bez_balls[i].x = pointer_x - container_x;
					bez_balls[i].y = pointer_y - container_y;
				}
				else {
					//見えない場用に移動/位相補正
					bez_balls[i].x = (stage.stageWidth + 200)*chg_x;
					bez_balls[i].y = container.y;
				}
				
				//scale/文字ではないので0でもOK
				bez_balls[i].scaleX = 0.1;
				bez_balls[i].scaleY = 0.1;
				
				//INTERPOLATE減算用配列
				count_bez[i] = INTERPOLATE;//50
				
				//delay値の変化/中外4種類
				delay_v = i * 0.5;//左
				if (delay_no == 1) { delay_v = delay_total - i * 0.5; }//右
				if (delay_no == 2) { delay_v = Math.abs((i + d_chg_v) - txline_mv)*0.5; }//中
				if (delay_no == 3) { delay_v = (delay_total / 2) - Math.abs((i + d_chg_v) - txline_mv) * 0.5; }//外
				
				//遅延フラグクリア
				bez_balls[i]._chg_x = 1;
				bez_balls[i]._chg_y = 1;
				
				//遅延inversion_v/chgflag
				if (inversion_v == 1) {
					if (flag3 < 0) { delay_v += 2.25; }
				}
				//逆転inversion_v/chgflag
				if (inversion_v == 2) {
					if (flag3 < 0) {
						bez_balls[i]._chg_x = -1;
						bez_balls[i]._chg_y = -1;
					}
				}
				
				//グローバルカウント
				gl_count = 0;
				
				//遅延させるTweenLite
				var myTween:TweenLite = new TweenLite(bez_balls[i],0.5,{delay:delay_v, scaleX:1, scaleY:1, onComplete:tw_onComplete,onCompleteParams:[i]});
				flag3 *= -1;
			}
		}
		//TweenLite-onComplete
		private function tw_onComplete(param1:int):void {
			//onEnterFrame処理
			bez_balls[param1].addEventListener(Event.ENTER_FRAME, onEnterFrame_bez);
		}
		
		//ball onEnterFrame
		private function onEnterFrame_bez(e:Event):void {
			//
			var count:Number = INTERPOLATE;//50
			//as Ballで問題なくコンパイル
			var mv_ball:BezImgBall = e.currentTarget as BezImgBall;
			var ball_no:int = mv_ball.count_no;
			
			if (gl_count < photomax) {
				//回転rot_vをcountでわる
				mv_ball.rotation += rot_v / count;
				
				//最後0になるように初めに減算する(INTERPOLATE)
				//INTERPOLATE減算用配列
				count_bez[ball_no] -= 1;
				
				var dd:Number = count_bez[ball_no] / count;
				if (dd > 1) { dd = 1; }//強制的に1にする
				if (dd < 0) { dd = 0; }//最後0にする
				
				//個別に初期位置を同一にする
				if (firstPoint) {
					p3 = first_points[ball_no];
				}
				
				//保存係数/位相反転
				var cx:Number = mv_ball._chg_x;
				var cy:Number = mv_ball._chg_y;
				//指定位置の場合反転させない
				if (firstPoint) { cx = cy = 1;}
				
				//今回の座標
				var pos:Object = CubicBezPoint( p0, p1, p2, p3, dd);
				mv_ball.x = pos.x * cx + _arrX[ball_no];
				mv_ball.y = pos.y * cy + _arrY[ball_no];
				//removeEventListener
				if (count_bez[ball_no] <= 0) {
					
					//グローバルカウント/反転するとカウントが正確でないのでこちらで判定
					gl_count ++;
					//回転0
					mv_ball.rotation = 0;
					bez_balls[ball_no].removeEventListener(Event.ENTER_FRAME, onEnterFrame_bez);
					//最後になったら終了処理に
					if (gl_count == photomax) { show_end(); }
				}
				
			}
		}

		//終了処理
		//ボタン表示作動中にボタンを押すと崩れるので非表示にしている
		private function show_end ():void {
			gl_count = 0;
			btn_1.visible = true;
			tf.text = "三次ベジェ曲線 アニメ終了"
		}
		
		/* --------------------------------------
		3次ベジェ曲線上の1点を取得する
		第01引数	頂点データ1(開始)
		第02引数	頂点データ2(制御1)
		第03引数	頂点データ3(制御2)
		第04引数	頂点データ4(終了)
		第05引数	係数(0 ~ 1)
		-------------------------------------- */
		private function CubicBezPoint( p0:Object, p1:Object, p2:Object, p3:Object, d:Number):Object {
			
			var o:Object = {x:0,y:0};
			var tmp:Number = (1 - d) * (1 - d) * (1 - d);
			
			o.x += tmp * p0.x;	
			o.y += tmp * p0.y;
			
			tmp = 3 * d * (1-d) * (1-d);
			o.x += tmp * p1.x;
			o.y += tmp * p1.y;
			
			tmp = 3 * d * d * (1-d);
			o.x += tmp * p2.x;
			o.y += tmp * p2.y;
			
			tmp = d * d * d;
			o.x += tmp * p3.x;
			o.y += tmp * p3.y;
			
			return o;
		}

		//ERROR
		private function ioErrorHandler(event:IOErrorEvent):void {
			//ERROR処理
			tf.text = "LOADING-EROOR";
			
			//画像ERRORならカウントをすすめて次ぎ画像ロードに進む
			countImage ++;
			loadImage();
		}
		//LOADING回転
		private function step(evt:Event):void {
			indicator.rotation = (indicator.rotation + 360 / stage.frameRate) % 360;
		}
		
		//create-box
		private function createSquare(x:Number, y:Number, width:Number, height:Number, color:Number, alpha:Number):Sprite {
			var s:Sprite = new Sprite();
			s.graphics.beginFill(color, alpha);
			s.graphics.drawRect(x, y, width, height);
			s.graphics.endFill();
			//addChild(s);
			return s;
		}
		//create-Roundbox
		private function createSquare2(x:Number, y:Number, width:Number, height:Number, color:Number, alpha:Number, round:Number):Sprite {
			var rs:Sprite = new Sprite();
			rs.graphics.beginFill(color, alpha);
			rs.graphics.drawRoundRect(x, y, width, height, round);
			rs.graphics.endFill();
			//addChild(rs);
			return rs;
		}
		//create-text
		private function createTextField(x:Number, y:Number, width:Number, height:Number):TextField {
			var result:TextField = new TextField();
			result.x = x;
			result.y = y;
			result.width = width;
			result.height = height;
			//addChild(result);
			return result;
		}
		//create-RoundBTN/原点中央
		private function createRoundBTN(text:String, t_size:int, t_color:uint, width:Number, height:Number, color:uint, alpha:Number, round:Number):Sprite {
			var rsbt:Sprite = new Sprite();
			rsbt.graphics.beginFill(color, alpha);
			rsbt.graphics.drawRoundRect(-width/2, -height/2, width, height, round);
			rsbt.graphics.endFill();
			addChild(rsbt);
			var r:TextField = new TextField();
			var fmt:TextFormat = new TextFormat('_ゴシック', t_size, null, null, null, null, null, null, TextFormatAlign.CENTER );
			r.defaultTextFormat = fmt;
			r.textColor = t_color;
			r.selectable = false;
			//r.autoSize = TextFieldAutoSize.LEFT;
			r.text = text;
			r.width = width;
			r.x = -width / 2;
			r.y = -height / 2 + 2;
			rsbt.addChild(r);
			return rsbt;
		}
	}
}

//MarkerBallクラス
import flash.display.Sprite;
class MarkerBall extends Sprite {
	//
	private var _color:uint;
	private var _radius:Number;	
	//未使用
	private var _x:Number = 0;
	private var _y:Number = 0;

	public function MarkerBall(radius:Number = 5, color:uint = 0xFF0000) {
		
		_color = color;
		_radius = radius;
		
		var b:Sprite = new Sprite();
		//xy
		b.x = 0;
		b.y = 0;
		//円の描画
		b.graphics.beginFill(_color, 1);
		b.graphics.drawCircle(0, 0, _radius);
		b.graphics.endFill();
		addChild(b);
		//
	}
}

//BezImgBall運動クラス
import flash.display.*;
import flash.geom.*;
class BezImgBall extends Sprite {

	public var angle:Number;
	public var radian:Number;
	public var pointX:Number;
	public var pointY:Number;
	//番号
	public var count_no:Number;
	//回転方向 0=左 1=右
	public var direction:int;
	//逆転係数
	public var chgFlag:Number = 1;
	//逆転係数2
	public var _chg_x:Number = 1;
	public var _chg_y:Number = 1;
	//画像
	public var bitmap_img:BitmapData;
	public var width_v:Number;
	public var height_v:Number;
	//未使用
	private var _x:Number = 0;
	private var _y:Number = 0;

	public function BezImgBall(_bitmap_img:BitmapData, _width:Number, _height:Number) {

		bitmap_img = _bitmap_img;
		width_v = _width;
		height_v = _height;
		makebox();
	}
	public function makebox():void {
		var b:Sprite = new Sprite();
		//xy
		b.x = 0;
		b.y = 0;
		var bd:BitmapData = new BitmapData(width_v, height_v);
		bd.draw(bitmap_img);
		//XYの位置に注意
		b.graphics.beginBitmapFill(bd, null, false, false);
		b.graphics.drawRoundRect(0, 0, width_v, height_v, 10);
		b.graphics.endFill();
		//中心補正
		b.x = -width_v / 2;
		b.y = -height_v / 2;
		
		addChild(b);
		//
	}
}

//LOADING-Shape
import flash.display.Shape;
class Indicator extends Shape {
	public function Indicator(){
		var i:uint,
		cx:Number, cy:Number,
		numNeedles:uint = 12,
		innerR:Number = 7,
		outerR:Number = 5,
		cAngle:Number = -Math.PI / 2,
		nAngle:Number;
		nAngle = Math.PI * 2 / numNeedles;
		for (i=0; i<numNeedles; i++){
			cAngle += nAngle;
			cx = Math.cos(cAngle) * innerR;
			cy = Math.sin(cAngle) * innerR;
			graphics.moveTo(cx, cy);
			cx = Math.cos(cAngle) * outerR;
			cy = Math.sin(cAngle) * outerR;
			graphics.lineStyle(2, 0xffffff, i/numNeedles);
			graphics.lineTo(cx, cy);
		}
	}
}

使用画像

1 画像80x60 2 3 4 5

三次ベジェ曲線を描くにHAKUHINさんの「3次ベジェ曲線を描画する」記事を参考にしました。

【参考】HAKUHIN's home page: 3次ベジェ曲線を描画する


三次ベジェ曲線と画像の運動、シュミュレーションテスト

【参考】シュミュレーションテスト: 三次ベジェ曲線で文字を動かす3


以上です。



[ この記事のURL ]


タグ:flash , ActionScript , as3 , photo , series

[ 三次ベジェ曲線で文字を動かす シリーズ記事 ]

三次ベジェ曲線で文字を動かす/42012.04.21
三次ベジェ曲線で文字を動かす/32012.04.20
三次ベジェ曲線で文字を動かす/22012.04.19
三次ベジェ曲線で文字を動かす/12012.04.17

 

ブログ記事一覧



[1]