forked from: TINYRACEGAME(的な疑似3D)

by hacker_qus3vzf3 forked from TINYRACEGAME(的な疑似3D) (diff: 1)
アウトランとかファイナルラップとかの疑似3D的な
 スペースキーで進みます(離すと止まる)
 っていうかここまでやったらちゃんとゲームにしろよと
 もうちょっとタイニーな見た目にしたかったのに中途半端。
 ドット感ある感じにしたいです。
 参考:
 http://hakuhin.jp/as/raster_efc.html#RASTER_EFC_04

@author fumix
♥0 | Line 186 | Modified 2010-12-21 23:24:30 | MIT License
play

ActionScript3 source code

/**
 * Copyright hacker_qus3vzf3 ( http://wonderfl.net/user/hacker_qus3vzf3 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/x4fH
 */

// 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 _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;
            
            //グランド部分
            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 = 2.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;
            roadSprite.graphics.clear();
            do {
                ro.z -= _velocity;
                if(ro.z < 0)  ro.z += 40;
            }
            while (ro = ro.next);
        }

        
        /**
         * アップデート(描画処理)
         */
        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.5) / ro.z * FOV * HEIGHT;
                var h1 : Number = (ro.y+_velocity*0.5) / (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 {
                var next : RoadObject;
                if(ro.next != null) {
                    next = ro.next;
                } else {
                    next = _firstSp;
                }
                //スクリーン上のx座標 = 3次元のx座標 / 3次元のz座標 * fov * width;
                //スクリーン上のy座標 = 3次元のy座標 / 3次元のz座標 * fov * height;            
                var y0 : Number = (ro.y+_velocity*0.5) / ro.z * FOV * HEIGHT + offset + 11;
                var x00 : Number = (ro.x - ro.width / 2) / ro.z * FOV * WIDTH + SCREEN_WIDTH / 2;
                var x01 : Number = (ro.x + ro.width / 2) / ro.z * FOV * WIDTH + SCREEN_WIDTH / 2;
                var y1 : Number = (next.y+_velocity*0.5) / next.z * FOV * HEIGHT + offset + 11;
                var x10 : Number = (next.x - next.width / 2) / next.z * FOV * WIDTH + SCREEN_WIDTH / 2;
                var x11 : Number = (next.x + next.width / 2) / next.z * FOV * WIDTH + SCREEN_WIDTH / 2;                    

                var x20 : Number = (ro.x - ro.width / 2 - 0.1) / ro.z * FOV * WIDTH + SCREEN_WIDTH / 2;
                var x21 : Number = (ro.x + ro.width / 2 + 0.1) / ro.z * FOV * WIDTH + SCREEN_WIDTH / 2;
                var x30 : Number = (next.x - next.width / 2 - 0.1) / next.z * FOV * WIDTH + SCREEN_WIDTH / 2;
                var x31 : Number = (next.x + next.width / 2 + 0.1) / 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;
    }
}