Bitmap直描きをしてみる

これまでアニメーションといえばFrameSpriteクラスを作って、
Flashのタイムラインでゲームを作る感覚でやってました。
このFrameSprite、実装は

Sprite
┣ Sprite
┃ ┣ Bitmap
┃ ┣ Bitmap
┃ ・
┃ ・
┃ ・
┃ 
┣ Sprite
┃ ┣ Bitmap
┃ ┣ Bitmap
┃ ・
┃ ・
┃ ・
・
・
・

という感じで、結構なボリュームを感じます。


冷静に考えると、アニメーションさせるために必要な情報は、
「現在の行動状態」と、「現在何フレーム目か」という、2つのだけでした。
これらの情報を見て、描画させる際に適切な画像データを描画すれば、
画像データは1セット、作成するキャラごとに上の2つの情報をもたせておけば、
それだけでうまくできるんじゃないかと。
だからといって、描画処理ごとにnew Bitmap()するのも、考えものなので、
最初に1枚Bitmapをつくっておいて、これにBitmapDataを描き込むことにしました。


この、最初に1枚作るBitmapのクラスを考えてみました。

package
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	/**
	 * ビットマップキャンバス
	 */
	public class BitmapCanvas
	{
		private var _canvas:Bitmap; // 描画対象ビットマップ
		
		/**
		 * コンストラクタ
		 * 
		 * @param width  キャンバスの横幅(ピクセル単位)
		 * @param height キャンバスの高さ(ピクセル単位)
		 */
		public function BitmapCanvas(width:uint, height:uint)
		{
			var bitmapData:BitmapData = new BitmapData(width, height);
			_canvas = new Bitmap(bitmapData, "auto", true);
			
			// 最初に画面内容を消去しておく
			clear();
		}
		
		/**
		 * キャンバスを描画リストに登録
		 * 
		 * @param stageSp キャンバスを登録するステージ
		 * 
		 * @throws Error すでに描画リストに登録されているキャンバスは登録できません。
		 */
		public function added(stageSp:Sprite):void
		{
			// すでに登録されているなら
			if (_canvas.parent != null)
			{
				// 例外
				throw new Error("すでに描画リストに登録されているキャンバスはリストに登録できません。");
			}
			
			stageSp.addChild(_canvas);
		}
		
		/**
		 * キャンバスを描画リストから削除
		 * 
		 * @throws Error 描画リストに登録されていないキャンバスをリストから削除できません。
		 */
		public function removed():void
		{
			// 登録されていないなら
			if (_canvas.parent == null)
			{
				// 例外
				throw new Error("描画リストに登録されていないキャンバスをリストから削除できません。");
			}
			
			_canvas.parent.removeChild(_canvas);
		}
		
		/**
		 * ビットマップデータ描画
		 * 
		 * @param bitmapData 描画するビットマップデータ
		 * @param destPoint  描画位置(描画範囲の左上)
		 */
		public function drawBitmapData(bitmapData:BitmapData, destPoint:Point):void
		{
			var rect:Rectangle = new Rectangle(0, 0, bitmapData.width, bitmapData.height);
			_canvas.bitmapData.copyPixels(bitmapData, rect, destPoint, null, null, true);
		}
		
		/**
		 * 描画内容の消去
		 */
		public function clear():void
		{
			var canvasData:BitmapData = _canvas.bitmapData;
			var rect:Rectangle = new Rectangle(0, 0, canvasData.width, canvasData.height);
			canvasData.fillRect(rect, 0x00FFFFFF);
		}
	}
}


使ってみる。

package
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	
	/**
	 * 動作確認
	 */
	public class TestClass extends Sprite
	{
		private var _canvas:BitmapCanvas;
		private var _loader:ImageLoader;
		
		/**
		 * コンストラクタ
		 */
		public function TestClass()
		{
			super();
			
			_canvas = new BitmapCanvas(500, 375);
			_canvas.added(this);
			
			_loader = new ImageLoader("mahoutukai.png");
			
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
		
		/**
		 * エンターフレームイベントリスナー
		 * 
		 * @param event イベント
		 */
		public function onEnterFrame(event:Event):void
		{
			if (_loader.completeFlg)
			{
				var data:BitmapData = Bitmap(_loader.data).bitmapData;
				
				_canvas.clear();
				_canvas.drawBitmapData(data, new Point(Math.random() * (500 - data.width), Math.random() * (375 - data.height)));
			}
		}
	}
}

途中出てくる妙なクラスは雰囲気で機能を察してください。


最初にBitmapを1枚作っておいて(BitmapCanvasクラス)、ステージに追加(addedメソッド)、
ループ処理で、前のループ時に描画されていたものを消去(clearメソッド)、
読み込んだBitmapDataを描画(drawBitmapDataメソッド)という流れです。
今回は適当にステージ中にランダムに描画させてみました。
うまくいっているようです。
これで何か作ってみることにします。


_canvas.clear();
を実行しない場合、素敵なことになりました。

ドドドドド...


ちょっと賢く修正しました。
BitmapCanvasクラスを少し賢くした - 書き物