FrameSpriteクラス


前々からブツブツ言っていたFrameクラスの最終的な形です。Spriteを拡張してMovieClipのように複数のフレームを持てるようにしました。アニメーションさせたり、フレームアクションを設定することもできます。


package
{
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.Shape;
	import flash.display.Sprite;
	
	public class FrameSprite extends Sprite
	{
// ------------------------------------------------------------------------------------------------
// --プロパティ	-----------------------------------------------------------------------------------
		private var _labelList			:Array;					// ラベルリスト
		private var _objList			:Object;				// オブジェクトリスト
		private var _frameActionList	:Array;					// フレームアクションリスト
		
		private var _currentObj		:DisplayObject;			// 現在のディスプレイオブジェクト
		private var _currentFrame		:uint;					// 現在のフレーム番号
		private var _currentLabel		:String;				// 現在のラベル
		private var _playFlg			:Boolean;				// 再生中ならtrue
		private var _repeatFlg			:Boolean;				// リピート再生するならtrue
		
		private var _labelNum			:uint;					// 一意のラベル名設定用番号
// ------------------------------------------------------------------------------------------------
// --初期処理	-----------------------------------------------------------------------------------
		// ■コンストラクタ
		public function FrameSprite()
		{
			super();
			
			_labelList			= new Array();	// フレームラベルリスト
			_objList			= new Object();	// オブジェクトスプライトリストを生成
			_frameActionList	= new Array();	// フレームアクションリスト
			
			_currentObj			= new Shape();	// オブジェクトは空
			_currentFrame		= 0;			// 現在のフレーム番号はとりあえず0
			_currentLabel		= "";			// 現在のラベルはとりあえず空
			_playFlg			= false;		// アニメーション停止としておく
			_repeatFlg			= true;			// 通常再生にしておく
			
			_labelNum			= 0;			// ラベル名設定用番号
		}
// ------------------------------------------------------------------------------------------------
// --通常メソッド	-------------------------------------------------------------------------------
		/**
		 * ■ディスプレイオブジェクト登録メソッド
		 * 
		 * @param obj	登録するディスプレイオブジェクト
		 * @param label	登録するディスプレイオブジェクトを指すフレームラベル
		 */
		public function addObj(obj:DisplayObject, label:String = ""):DisplayObject
		{
			// ラベルが指定されていないなら
			if (label == "")
			{
				label = "noName0000" + _labelNum;	// 一意のラベルを生成
				++_labelNum;						// ラベル生成用番号をアップ
			}
			_labelList.push(label);					// ラベルを登録
			_objList[label] = obj;					// オブジェクトを登録
			obj.visible = false;					// 見えなくする
			addChild(obj);							// 実際に登録
			
			// 初めて登録するならフレーム移動もしておく
			if (_currentFrame == 0)
			{
				gotoAndAction(label);
			}
			
			return obj;		// 登録したオブジェクトを返す
		}
		
		/**
		 * ■ディスプレイオブジェクトフレーム番号指定登録メソッド
		 * 
		 * @param obj	登録するディスプレイオブジェクト
		 * @param num	登録するディスプレイオブジェクトのフレーム番号
		 * @param label	登録するディスプレイオブジェクトを指すフレームラベル
		 */
		public function addObjAt(obj:DisplayObject, num:uint, label:String = ""):DisplayObject
		{
			// ラベルが指定されていないなら
			if (label == "")
			{
				label = "noName0000" + _labelNum;	// 一意のラベルを生成
				++_labelNum;						// ラベル生成用番号をアップ
			}
			_labelList.splice(num - 1, 0, label);	// ラベルを登録
			_objList[label] = obj;					// オブジェクトを登録
			obj.visible = false;					// 見えなくする
			addChild(obj);							// 実際に登録
			
			// 初めて登録するならフレーム移動もしておく
			if (_currentFrame == 0)
			{
				gotoAndAction(num);
			}
			
			return obj;		// 登録したオブジェクトを返す
		}
		
		/**
		 * ■フレームアクション設定メソッド
		 * 
		 * @param actionFunc	フレームアクションとして登録するメソッド
		 * @param frameNum		登録するフレーム番号
		 */
		public function setFrameAction(actionFunc:Function, frameNum:uint):void
		{
			// リストの指定した番号にメソッドを登録
			_frameActionList[frameNum] = actionFunc;
		}
		
		/**
		 * ■フレーム移動共通メソッド
		 * 
		 * @param frame 移動するフレーム
		 */
		protected function gotoAndAction(frame:*):void
		{
			var label:String = "";	// ラベル
			
			// 指定されたフレームの型がuintなら
			if (frame is uint)
			{
				label			= _labelList[frame - 1];	// ラベルリストからラベルを取得
				_currentFrame	= frame;					// 現在のフレームを設定
			}
			// 指定されたフレームが文字列なら
			else if (frame is String)
			{
				label			= frame;				// ラベルとして使う
				_currentFrame	= getFrameNum(frame);	// 現在のフレームを設定
			}
			// それ以外の型なら
			else
			{
				return;	// 終了
			}
			
			// 対象フレームのディスプレイオブジェクト
			var obj:DisplayObject = _objList[label];
			
			// 表示中のオブジェクトが指定したのオブジェクトと同じでないなら
			if (_currentObj != obj)
			{
				// 対象フレームのディスプレイオブジェクトが存在するなら
				if (obj != null)
				{
					// 表示切替
					_currentObj.visible	= false;
					obj.visible			= true;
					_currentObj			= obj;
					_currentLabel		= label;
				}
			}
			
			// フレームアクションを取得
			var frameAction:Function = _frameActionList[_currentFrame];
			// フレームアクションが設定されているなら
			if (frameAction != null)
			{
				frameAction();	// フレームアクションを実行
			}
		}
		
		/**
		 * ■フレーム番号取得メソッド
		 * 
		 * @param label 対象のラベル
		 */
		private function getFrameNum(label:String):uint
		{
			var list:Array	= _labelList;		// ラベルリスト
			var l:uint		= list.length;		// ラベルリストの長さ
			// ラベルリストの探索
			for (var i:uint = 0; i < l; ++i)
			{
				// 指定したラベルが登録されているラベルと同じなら
				if (label == list[i])
				{
					return i + 1;	// 番号を返す
				}
			}
			
			return null;	// 登録されていないラベルを指定したならnullを返す
		}
		
		/**
		 * ■フレーム取得メソッド
		 * 
		 * @param frame 対象のフレーム
		 */
		
		// ■再生開始メソッド
		public function play():void
		{
			_playFlg = true;	// 再生
		}
		
		// ■再生停止メソッド
		public function stop():void
		{
			_playFlg = false;	// 停止
		}
		
		/**
		 * ■フレーム移動&停止メソッド
		 * 
		 * @param frame 移動するフレーム
		 */
		public function gotoAndStop(frame:*):void
		{
			gotoAndAction(frame);	// フレーム移動
			stop();					// 再生停止
		}
		
		/**
		 * ■フレーム移動&再生メソッド
		 * 
		 * @param frame 移動するフレーム
		 */
		public function gotoAndPlay(frame:*):void
		{
			gotoAndAction(frame);	// フレーム移動
			play();					// 再生開始
		}
		
		// ■リピートメソッド
		public function repeatPlay():void
		{
			_repeatFlg = true;
		}
		// ■リピート停止メソッド
		public function repeatStop():void
		{
			_repeatFlg = false;
		}
		
		// ■アニメーションメソッド
		public function animate():void
		{
			// 再生中なら
			if (_playFlg)
			{
				var f:uint = _currentFrame;		// 現在のフレーム
				
				++f;							// 次のフレームへ
				
				// 最後のフレームまで再生し終えていないなら
				if (f <= _labelList.length)
				{
					gotoAndAction(f);			// フレーム移動
				}
				// 最後のフレームを超えたなら
				if (f > _labelList.length)
				{
					f = _labelList.length;	// 最後のフレームとする
					
					// 繰り返し再生するなら
					if (_repeatFlg)
					{
						// 最初のフレームへ戻る
						gotoAndAction(1);
						f = 1;
					}
				}
				
				_currentFrame = f;	// 現在のフレームを設定
			}
		}
// ------------------------------------------------------------------------------------------------
// --プロパティ関連メソッド	-----------------------------------------------------------------------
		/**
		 * ■オブジェクト取得メソッド
		 * 
		 * @param label 取得するオブジェクトのラベル
		 * 
		 * @return オブジェクト
		 */
		public function getObj(label:String):DisplayObject
		{
			return _objList[label];
		}
		
		// ■フレーム数
		public function get length():uint					{ return _labelList.length;	}
		
		// ■現在のディスプレイオブジェクト
		public function get currentObject():DisplayObject	{ return _currentObj;		}
		
		// ■現在のフレーム番号
		public function get currentFrame():uint			{ return _currentFrame;		}
		
		// ■現在のディスプレイオブジェクトのラベル
		public function get currentLabel():String			{ return _currentLabel;		}
	}
}


基本的な使い方の例を示します。まずはFrameSpriteオブジェクトの生成とステージへの追加です。

var stageSp:Sprite = new Sprite();    // ステージとするスプライト
var frame:FrameSprite = new FrameSprite();    // FrameSpriteの生成

stageSp.addChild(frame);    // ステージに追加

このあたりは通常のSpriteと同じです。


次にフレームを追加します。例として、●と■を描画したShapeをフレーム1、フレーム2に追加します。

var circle:Shape = new Shape();
// ●を描画
var rect:Shape = new Shape();
// ■を描画

frame.addObj(circle);    // ●を追加
frame.addObj(rect);    // ■を追加

addObj()で追加した順にフレーム1、2・・・と登録されていきます。(これを実行した段階だと、フレーム1が表示されています。)
また第2引数にラベルを指定することによって、フレームラベルの設定もできます。

frame.addObj(circle, "maru");    // ラベル名をmaruとして追加
frame.addObj(rect, "sikaku");    // ラベル名をsikakuとして追加


FrameSpriteはMovieClipと同様にgotoAndStop()やgotoAndPlay()でフレームを移動することができます。移動対象のフレームの指定はフレーム番号でもフレームラベルでもどちらでも可能です。

frame.gotoAndStop(2);    // 上の例だと表示が●から■に切り替わる
frame.gotoAndPlay("maru");    // ●が登録されているフレーム1が表示される

gotoAndStop()とgotoAndPlay()の違いは次に説明します。


FrameSpriteはgotoAndPlay()やplay()を実行することによって、アニメーションするよう設定することができます。実際にアニメーションさせるには、animate()を実行します。

frame.gotoAndPlay(1);    // フレーム1に移動してアニメーションするよう設定
frame.animate();    // 実際にアニメーションし、表示はフレーム2に切り替わる

AS1, 2でのonEnterFrame内でanimate()をループ実行すると通常のMovieClipと同じようにアニメーションします。
また、今回の例では2つフレームが登録されていますが、フレーム2の状態でanimate()するとループして再びフレーム1が表示されます。

frame.gotoAndPlay(2);    // フレーム2に移動
frame.animate();    // アニメーションし、表示はループしてフレーム1に切り替わる

さらにこれはMovieClipには無い機能ですがFrameSpriteはrepeatStop()を実行することによって最終フレームで再生が停止されるようになります。いわばMovieClipの最終フレームにstop()というフレームアクションが設定されているのと同様の動作をします。デフォルト設定ではループ再生されるようになっています。

frame.repeatStop();    // ループ再生停止
frame.gotoAndPlay(2);    // フレーム2に移動
frame.animate();    // 最終フレームだったのでループ再生せず表示に変化は無い

再びループ再生させるように設定するにはrepeatPlay()を実行します。
そしてFrameSpriteはMovieClipと同様にgotoAndStop()やstop()を実行することによってアニメーションしないよう設定できます。この設定を行うとanimate()を実行してもアニメーションしません。

frame.gotoAndStop(1);    // フレーム1に移動
frame.animate();    // アニメーションせず、表示に変化は無い


FrameSpriteはMovieClipと同様にcurrentFrameで表示中のフレーム番号を、currentLabelで表示中のフレームラベルを取得できます。また、lengthで登録されているフレームの個数を、currentObjectで表示中のディスプレイオブジェクトを取得することができます。

frame.gotoAndStop(2);    // フレーム2に移動
trace(frame.currentFrame);    // 出力: 2
trace(frame.currentLabel);    // 出力: sikaku
trace(frame.length);          // 出力: 2
trace(frame.currentObject);   // 出力は■が描画されたShape


FrameSpriteはMovieClipと同様にフレームアクションを設定することができます。例えば以下のようなメソッドを作ります。

private function init():void
{
    frame.gotoAndStop(1);
}

次にフレームアクションの登録を行います。登録にはsetFrameAction()を実行します。第1引数にフレームアクションとするメソッドを、第2引数に登録するフレーム番号を渡します。

frame.setFrameAction(init, 2);    // フレーム2にinitメソッドを登録

これでフレーム2が再生される度にinit()が実行されるようになります。


主な機能はこれぐらいでしょうか。一応僕が実際にゲームで使っている範囲では異常は無いようです。少々ややこしいことをしているので、また何か不具合等あればご報告ください。