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

TINYRACEGAME(的な疑似3D)道なりにスクロール

アウトランとかファイナルラップとかの疑似3D的な
* スペースキーで進みます(離すと止まる)
* っていうかここまでやったらちゃんとゲームにしろよと
* もうちょっとタイニーな見た目にしたかったのに中途半端。
* ドット感ある感じにしたいです。
* 参考:
* http://hakuhin.jp/as/raster_efc.html#RASTER_EFC_04
* 変更:
* 道路を沿うように左右にスクロール
/**
 * Copyright fumix ( http://wonderfl.net/user/fumix )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/po6L
 */

// forked from fumix's TINYRACEGAME(的な疑似3D)
/**
*  アウトランとかファイナルラップとかの疑似3D的な
* スペースキーで進みます(離すと止まる)
* っていうかここまでやったらちゃんとゲームにしろよと
* もうちょっとタイニーな見た目にしたかったのに中途半端。
* ドット感ある感じにしたいです。
* 参考:
* http://hakuhin.jp/as/raster_efc.html#RASTER_EFC_04
* 変更:
* 道路を沿うように左右にスクロール
**/
package {
	import flash.ui.Keyboard;
	import flash.events.KeyboardEvent;

	import net.hires.debug.Stats;

	import flash.geom.Rectangle;
	import flash.display.Graphics;
	import flash.events.Event;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;

	/**
	 * @author fumix
	 */
	[SWF(backgroundColor="#FFFFFF", frameRate="31", width="465", height="465")]

	public class Road extends Sprite {
		//----------------------------------------
		//CLASS CONSTANTS
		private const SCREEN_WIDTH : int = 465;
		private const SCREEN_HEIGHT : int = 465;

		private const ANGLE : Number = 60;//1 ~ 180 くらいまでの好きな値;		// 視野角
		private const FOV : Number = 1 / Math.tan(ANGLE * 0.5 * Math.PI / 180);	// 視点からの距離
		private const WIDTH : Number = 465 * 0.5;//解像度の幅か高さの大きい方の数値 * 0.5;	// 
		private const HEIGHT : Number = WIDTH * 1.0;			// アスペクト比

		//----------------------------------------
		//VARIABLES
		private var buffer : BitmapData;
		private var roadObjectArray : Array;
		private var _first : RoadObject;
		private var roadSprite : Sprite;
		private var roadSpriteArray : Array;
		private var _firstSp : RoadObject;

		private var _acceleration : Number;
		private var _velocity : Number;
		private var _direction : Number;
		private var _keyDownFlag : Boolean;

		/**
		 * コンストラクタ
		 */
		public function Road() {
			//描画用bitmapdata準備
			buffer = new BitmapData(SCREEN_WIDTH, SCREEN_HEIGHT, false, 0x0099FF);
			addChild(new Bitmap(buffer));
			//道路描画用
			roadSprite = new Sprite();
			//パフォーマンスチェック用
			var stats : Stats = addChild(new Stats()) as Stats;
			stats.x = stage.stageWidth - 70;
			//初期化処理
			initialize();
			//エンターフレーム処理
			addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
			//キーイベント
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownHandler);
			stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUpHandler);
		}

		/**
		 * 初期化
		 */
		private function initialize() : void {
			var old : RoadObject,
				i : int,
				j : int = 0,
				id : int = 0,
				ro : RoadObject;
			//キーフラグ
			_keyDownFlag = false;
			//加速度
			_acceleration = 0.1;
			//速度
			_velocity = 0.0;
			//方向
			_direction = 0.0;
			//グランド部分
			roadObjectArray = new Array();
			for (i = 40;i >= 1;i -= 2) {
				ro = new RoadObject(id, 0, 0.5, i);
				id++;
				//リンクリスト
				if (_first == null) {
					old = _first = ro;
				} else {
					old.next = ro;
					old = ro;
				}			
				roadObjectArray.push(ro);
			}
			//道部分
			id = 0;
			roadSpriteArray = new Array();
			for (i = 40;i >= 1;i -= 1) {
				var dx : Number = 4.0 * Math.sin(2 * Math.PI * (id / 40));
				if(id % 2 == 0) {
					ro = new RoadObject(id, dx, 0.6, i, 2, 0xFF3333);
				} else {
					ro = new RoadObject(id, dx, 0.6, i, 2, 0xFFAAAA);					
				}
				id++;
				//リンクリスト
				if (_firstSp == null) {
					old = _firstSp = ro;
				} else {
					old.next = ro;
					old = ro;
				}			
				roadSpriteArray.push(ro);
			}
		}

		/**
		 * キーイベント
		 */
		private function onKeyDownHandler(event : KeyboardEvent) : void {
			if(event.keyCode == Keyboard.SPACE) {
				_keyDownFlag = true;
			}
		}

		/**
		 * キーイベント
		 */
		private function onKeyUpHandler(event : KeyboardEvent) : void {
			if(event.keyCode == Keyboard.SPACE) {
				_keyDownFlag = false;
			}
		}

		private function onEnterFrameHandler(event : Event) : void {
			interaction();
			update();
		}

		
		/**
		 * インタラクション
		 */
		private function interaction() : void {
			var ro : RoadObject = _first;
			//速度
			if(_keyDownFlag && _velocity < 0.7) {
				_velocity += 0.007;
				if(_velocity > 0.7) _velocity = 0.7;
			}
			if(!_keyDownFlag && _velocity > 0) {
				_velocity -= 0.01;
				if(_velocity < 0) _velocity = 0;
			}
			//グランド部分のZ軸アップデート
			do {
				ro.z -= _velocity;
				if(ro.z < 1)  ro.z += 40;
			}
			while (ro = ro.next);

			//道部分のZ軸アップデート
			ro = _firstSp;
			do {
				ro.z -= _velocity;
				if(ro.z < 1 && ro.z >= 0) {
					//trace(ro.id);
					//方向の更新
					var before : RoadObject;
					if(ro.id - 1 < 0) {
						before = roadSpriteArray[roadSpriteArray.length - 1];
					} else {
						before = roadSpriteArray[ro.id - 1];			
					}
					_direction = -(ro.x + (before.x - ro.x) * (1.0 - ro.z));
				}
				if(ro.z < 0) {
					ro.z += 40;
				}
			}
			while (ro = ro.next);
			//trace("------");
		}

		
		/**
		 * アップデート(描画処理)
		 */
		private function update() : void {
			var offset : Number = 220;
			var ro : RoadObject = _first;
			
			//描画
			buffer.lock();
			//画面リセット
			buffer.fillRect(buffer.rect, 0x0099FF);

			//グランド部分の描画
			do {
				var h0 : Number = (ro.y + _velocity * 0.4) / ro.z * FOV * HEIGHT;
				var h1 : Number = (ro.y + _velocity * 0.4) / (ro.z + 1.2) * FOV * HEIGHT;
				var r : Rectangle = new Rectangle(0, h0 + offset, SCREEN_WIDTH, h0 - h1);
				if(h0 - h1 >= 1) buffer.fillRect(r, 0x0066FF);
			}
			while (ro = ro.next);
			
			//道部分の描画
			ro = _firstSp;
			roadSprite.graphics.clear();
			do {
				if(ro.next != null) {
					var next : RoadObject = ro.next;
				} else {
					var next : RoadObject = _firstSp;
				}
				//スクリーン上のx座標 = 3次元のx座標 / 3次元のz座標 * fov * width;
				//スクリーン上のy座標 = 3次元のy座標 / 3次元のz座標 * fov * height;			
				var y0 : Number = (ro.y + _velocity * 0.4) / ro.z * FOV * HEIGHT + offset + 8;
				var x00 : Number = (ro.x - ro.width / 2 + _direction) / ro.z * FOV * WIDTH + SCREEN_WIDTH / 2;
				var x01 : Number = (ro.x + ro.width / 2 + _direction) / ro.z * FOV * WIDTH + SCREEN_WIDTH / 2;
				var y1 : Number = (next.y + _velocity * 0.4) / next.z * FOV * HEIGHT + offset + 8;
				var x10 : Number = (next.x - next.width / 2 + _direction) / next.z * FOV * WIDTH + SCREEN_WIDTH / 2;
				var x11 : Number = (next.x + next.width / 2 + _direction) / next.z * FOV * WIDTH + SCREEN_WIDTH / 2;					

				var x20 : Number = (ro.x - ro.width / 2 - 0.1 + _direction) / ro.z * FOV * WIDTH + SCREEN_WIDTH / 2;
				var x21 : Number = (ro.x + ro.width / 2 + 0.1 + _direction) / ro.z * FOV * WIDTH + SCREEN_WIDTH / 2;
				var x30 : Number = (next.x - next.width / 2 - 0.1 + _direction) / next.z * FOV * WIDTH + SCREEN_WIDTH / 2;
				var x31 : Number = (next.x + next.width / 2 + 0.1 + _direction) / next.z * FOV * WIDTH + SCREEN_WIDTH / 2;					

				if(y1 >= y0 && y0 < 465) {
					roadSprite.graphics.beginFill(ro.color);
					roadSprite.graphics.moveTo(x20, y0);
					roadSprite.graphics.lineTo(x21, y0);
					roadSprite.graphics.lineTo(x31, y1);
					roadSprite.graphics.lineTo(x30, y1);
					roadSprite.graphics.lineTo(x20, y0);
					roadSprite.graphics.endFill();

					roadSprite.graphics.beginFill(0xCCCCCC);
					roadSprite.graphics.moveTo(x00, y0);
					roadSprite.graphics.lineTo(x01, y0);
					roadSprite.graphics.lineTo(x11, y1);
					roadSprite.graphics.lineTo(x10, y1);
					roadSprite.graphics.lineTo(x00, y0);
					roadSprite.graphics.endFill();
				}	
			}
			while (ro = ro.next);

			buffer.draw(roadSprite);				
			buffer.unlock();
		}
	}
}


class RoadObject {
	public var x : Number;
	public var y : Number;
	public var z : Number;
	public var width : Number;
	public var next : RoadObject;
	public var id : int;
	public var color:uint;
	
	public function RoadObject(id : int,x : Number = 0,y : Number = 0,z : Number = 0,width : Number = 0,color:uint = 0xFFFFFF) {
		this.id = id;
		this.x = x;
		this.y = y;
		this.z = z;
		this.width = width;
		this.color = color;
	}
}