奥行きのある地面の描画

(サンプル一覧を表示する)

FlashDevelop を使って、奥行きのある地面を描くテストをしてみました。

このサンプルは 1 フレームの処理内容が多くて負荷が高いので、
10 フレーム/秒で表示しています。
Flash の実行画面
奥行きのある地面の描画

Flashプレーヤーが入っていないか、JavaScriptが無効になっているようです。

Get Adobe Flash player

奥行きのある地面の描画

ソースコード

package 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.ColorTransform;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.ByteArray;
	
	/**
	 * 奥行きのある地面を描くサンプル
	 * @author Hikipuro
	 */
	public class Main extends Sprite 
	{
		/**
		 * 地面の画像
		 */
		[Embed(source='../image/test001.png')]
		private var image1:Class;
		
		/**
		 * 飛び跳ねるキャラクタの画像
		 */
		[Embed(source='../image/test002.png')]
		private var image2:Class;
		
		/**
		 * 飛び跳ねるキャラクタのビットマップ
		 */
		private var bitmap:Bitmap;
		
		/**
		 * 飛び跳ねるキャラクタの移動量
		 */
		private var y_amount:Number;
		
		/**
		 * 飛び跳ねるキャラクタのジャンプ量
		 */
		private var y_jump:Number;
		
		/**
		 * 地面描画用 BitmapData
		 */
		private var output:BitmapData;
		
		/**
		 * 地面の画像の横幅
		 */
		private var bitmapWidth:int;
		
		/**
		 * 地面の画像の縦幅
		 */
		private var bitmapHeight:int;
		
		/**
		 * 地面の画像のピクセル列
		 */
		private var pixels:Array;
		
		/**
		 * スクロール量
		 */
		private var scroll:Number;
		
		/**
		 * 視線の焦点
		 */
		private const FOCUS:Number = 500;
		
		/**
		 * コンストラクタ
		 */
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		/**
		 * 初期化メソッド
		 * @param	e
		 */
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
			
			// 変数の初期化
			scroll = -500;
			
			// 飛び跳ねるキャラクタの準備
			bitmap = Bitmap(new image2);
			bitmap.smoothing = true;
			bitmap.x = 160 - (bitmap.width / 2);
			bitmap.y = 160;
			y_amount = 0;
			y_jump = 5;
			
			// 地面の画像の準備
			// (ピクセル毎の色の値を入れた配列を作る)
			var bitmapData:BitmapData;
			bitmapData = Bitmap(new image1).bitmapData;
			bitmapWidth = bitmapData.width;
			bitmapHeight = bitmapData.height;
			
			var byteArray:ByteArray;
			byteArray = bitmapData.getPixels(bitmapData.rect);
			byteArray.position = 0;
			
			pixels = new Array;
			while (byteArray.position < byteArray.length) {
				var i:uint = byteArray.readUnsignedInt();
				pixels.push(i);
			}
			
			// 地面の出力先を準備
			// (空の部分を透明にする)
			output = new BitmapData(320, 240);
			for (var y:int = 0; y <= 120; y++)
			{
				for (var x:int = 0; x < 320; x++)
				{
					output.setPixel32(x, y, 0x00000000);
				}
			}
			
			// 空の画像の準備
			// (白黒の perlinNoise を描いて、黒い部分を空色にする)
			var bg:BitmapData;
			bg = new BitmapData(320, 121);
			bg.perlinNoise(320, 32, 10, 10, true, true, 7, true);
			
			var colorTransform:ColorTransform = new ColorTransform();
			colorTransform.blueOffset = 255;
			colorTransform.greenOffset = 146;
			colorTransform.redOffset = 47;
			bg.colorTransform(bg.rect, colorTransform);
			
			
			// ステージに画像の登録
			addChild(new Bitmap(bg));
			addChild(new Bitmap(output));
			addChild(bitmap);
			
			// イベントの登録
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
		
		/**
		 * フレーム開始イベント
		 * @param	event
		 */
		private function onEnterFrame(event:Event):void 
		{
			// 飛び跳ねるキャラクタの座標更新
			y_jump -= 0.5;
			y_amount += y_jump;
			if (y_amount < 0)
				y_jump = 5;
			bitmap.y = 160 - y_amount;
			
			// 画面のスクロール量設定
			scroll -= 10;
			
			// ループ前にピクセル値を保存する ByteArray を準備
			var byteArray:ByteArray;
			byteArray = new ByteArray();
			byteArray.length = 320 * 120 * 4;
			
			// 地面の描画
			for (var y:int = 120; y < 240; y++)
			{
				var sy:int;
				var ybase:int;
				var syfocus:Number;
				
				sy = (100 / (y - 100)) * FOCUS;
				ybase = (sy % bitmapHeight) * bitmapWidth;
				syfocus = sy / FOCUS;
				
				for (var x:int = -160; x < 160; x++)
				{
					var color:uint;
					var sx:int;
					
					sx = syfocus * x;
					
					sx += scroll;
					sx = sx % bitmapWidth;
					sx *= -1;
					
					color = pixels[ybase + sx];
					byteArray.writeUnsignedInt(color);
				}
			}
			
			// ByteArray に描いた画像を BitmapData に登録
			byteArray.position = 0;
			output.setPixels(new Rectangle(0, 120, 320, 120), byteArray);
		}
		
	}
	
}		

外部リンク