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

等角投エッシャー

----------------------------------------------------------------------------
* 等角投影オブジェクトでペンローズの階段をつくる。
* 
* [related link]
* css3 penrose stair
* http://jsdo.it/9re/penrose_stair
*
* AdvancED ActionScript 3.0 Animation (詳解 ActionScript 3.0アニメーション)
* http://www.friendsofed.com/book.html?isbn=9781430216087
* http://www.oreilly.co.jp/books/9784873114378/
* ----------------------------------------------------------------------------
Get Adobe Flash player
by o8que 08 Jul 2010
    Embed
/**
 * Copyright o8que ( http://wonderfl.net/user/o8que )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/dtQq
 */

/* ----------------------------------------------------------------------------
 * 等角投影オブジェクトでペンローズの階段をつくる。
 * 
 * [related link]
 * css3 penrose stair
 * http://jsdo.it/9re/penrose_stair
 *
 * AdvancED ActionScript 3.0 Animation (詳解 ActionScript 3.0アニメーション)
 * http://www.friendsofed.com/book.html?isbn=9781430216087
 * http://www.oreilly.co.jp/books/9784873114378/
 * ----------------------------------------------------------------------------
 */

package {
    import flash.display.Sprite;
    
    public class Main extends Sprite {
        private static const BOX_SIZE:int = 30;    // 箱ブロックのサイズ
        private static const BOX_COLS:int = 9;    // 上の列数
        private static const BOX_ROWS:int = 10;    // 右の行数
        private static const LINE_DEC:int = 4;    // 下の列数・左の行数の減分
        
        private var _boxList:Vector.<IsoBox>;
        
        public function Main() {
            graphics.beginFill(0x000000);
            graphics.drawRect(0, 0, 465, 465);
            graphics.endFill();
            
            _boxList = new Vector.<IsoBox>();
            
            var sprite:Sprite = addChild(new Sprite()) as Sprite;
            sprite.x = 187;
            sprite.y = 400;
            var height:Number = 200;
            
            var i:int;
            var heightIncrease:Number = (BOX_SIZE * LINE_DEC) / (2 * (BOX_COLS + BOX_ROWS - LINE_DEC) - 4) / IsometricPoint.Y_CORRECT;
            // 上
            for (i = 0; i < BOX_COLS; i++, height += heightIncrease) {
                _boxList.push(new IsoBox(i * BOX_SIZE, 0, BOX_SIZE, height));
            }
            // 右
            for (i = 1; i < BOX_ROWS; i++, height += heightIncrease) {
                _boxList.push(new IsoBox((BOX_COLS - 1) * BOX_SIZE, i * BOX_SIZE, BOX_SIZE, height));
            }
            // 下
            for (i = BOX_COLS - 2; i >= LINE_DEC; i--, height += heightIncrease) {
                _boxList.push(new IsoBox(i * BOX_SIZE, (BOX_ROWS - 1) * BOX_SIZE, BOX_SIZE, height));
            }
            // 左
            for (i = BOX_ROWS - 2; i >= LINE_DEC + 1; i--, height += heightIncrease) {
                _boxList.push(new IsoBox(LINE_DEC * BOX_SIZE, i * BOX_SIZE, BOX_SIZE, height));
            }
            
            // Zソートして表示
            _boxList.sort(IsoBox.compareDepth);
            for (i = 0; i < _boxList.length; i++) { sprite.addChild(_boxList[i]); }
        }
    }
}
//package {
    import flash.display.Sprite;
    
    //public 
    class IsoBox extends Sprite {
        private var _position:IsometricPoint;
        private var _height:Number;
        
        public function get topX():Number { return _position.x; }
        public function get topY():Number { return -_height; }
        public function get topZ():Number { return _position.z; }
        
        public function IsoBox(worldX:Number, worldZ:Number, size:int, height:Number) {
            _position = IsometricPoint.createFromWorldPos(worldX, 0, worldZ);
            x = _position.screenX;
            y = _position.screenY;
            
            _height = height;
            var h:Number = _height * IsometricPoint.Y_CORRECT;
            // 上面
            graphics.beginFill(0xffffff);
            graphics.lineStyle(0, 0x888888, 0.5);
            graphics.moveTo( -size, -h);
            graphics.lineTo(0, -size * 0.5 - h);
            graphics.lineTo(size, -h);
            graphics.lineTo(0, size * 0.5 - h);
            graphics.lineTo( -size, -h);
            graphics.endFill();
            // 左側面
            graphics.beginFill(0x888888);
            graphics.lineStyle();
            graphics.moveTo( -size, -h);
            graphics.lineTo(0, size * 0.5 - h);
            graphics.lineTo(0, size * 0.5);
            graphics.lineTo( -size, 0);
            graphics.lineTo( -size, -h);
            graphics.endFill();
            // 右側面
            graphics.beginFill(0xbbbbbb);
            graphics.lineStyle();
            graphics.moveTo(0, size * 0.5 - h);
            graphics.lineTo(size, -h);
            graphics.lineTo(size, 0);
            graphics.lineTo(0, size * 0.5);
            graphics.lineTo(0, size * 0.5 - h);
            graphics.endFill();
        }
        
        // Zソート用比較メソッド
        public static function compareDepth(a:IsoBox, b:IsoBox):Number {
            return IsometricPoint.compareDepth(a._position, b._position);
        }
    }
//}
//package {

    //public 
    class IsometricPoint {
        public static const Y_CORRECT:Number = Math.cos( -30 * Math.PI / 180) * Math.SQRT2;
        
        // ワールド座標値
        private var _worldX:Number;
        private var _worldY:Number;
        private var _worldZ:Number;
        // 画面座標値
        private var _screenX:Number;
        private var _screenY:Number;
        private var _screenZ:Number;
        
        private var _isInvalidWorldPos:Boolean;        // ワールド座標値を更新する必要があるかどうか
        private var _isInvalidScreenPos:Boolean;    // 画面座標値を更新する必要があるかどうか
        
        // ワールド座標値からインスタンスを作成する
        public static function createFromWorldPos(x:Number = 0, y:Number = 0, z:Number = 0):IsometricPoint {
            return new IsometricPoint(true, x, y, z);
        }
        
        // 画面座標値からインスタンスを作成する
        public static function createFromScreenPos(x:Number = 0, y:Number = 0):IsometricPoint {
            return new IsometricPoint(false, x, y, 0);
        }
        
        public function IsometricPoint(isWorldPos:Boolean, x:Number, y:Number, z:Number) {
            if (isWorldPos) {
                _worldX = x;
                _worldY = y;
                _worldZ = z;
                updateScreenPos();
            }else {
                _screenX = x;
                _screenY = y;
                updateWorldPos();
            }
            
            _isInvalidWorldPos = false;
            _isInvalidScreenPos = false;
        }
        
        private static const COS30:Number = Math.cos( -30 * Math.PI / 180);
        private static const COS45:Number = Math.cos(45 * Math.PI / 180);
        
        private function updateWorldPos():void {
            _worldX = _screenY + _screenX * 0.5;
            _worldY = 0;
            _worldZ = _screenY + _screenZ * 0.5;
            _screenZ = (_worldX + _worldZ) * COS30;
        }
        
        private function updateScreenPos():void {
            _screenX = _worldX - _worldZ;
            _screenY = _worldY * IsometricPoint.Y_CORRECT + (_worldX + _worldZ) * 0.5;
            _screenZ = (_worldX + _worldZ) * COS30 - _worldY * COS45;
        }        
        
        // Zソート用比較メソッド
        public static function compareDepth(a:IsometricPoint, b:IsometricPoint):Number {
            a.validateWorldPos(); a.validateScreenPos();
            b.validateWorldPos(); b.validateScreenPos();
            if (a._screenZ < b._screenZ) { return -1; }
            if (a._screenZ > b._screenZ) { return 1; }
            return 0;
        }
        
        // ワールド座標値を有効にする
        private function validateWorldPos():void {
            if (_isInvalidWorldPos) {
                updateWorldPos();
                _isInvalidWorldPos = false;
            }
        }
        
        // 画面座標値を有効にする
        private function validateScreenPos():void {
            if (_isInvalidScreenPos) {
                updateScreenPos();
                _isInvalidScreenPos = false;
            }
        }
        
        public function get x():Number { validateWorldPos(); return _worldX; }
        public function get y():Number { validateWorldPos(); return _worldY; }
        public function get z():Number { validateWorldPos(); return _worldZ; }
        public function get screenX():Number { validateScreenPos(); return _screenX; }
        public function get screenY():Number { validateScreenPos(); return _screenY; }
        
        public function set x(value:Number):void { validateWorldPos(); _worldX = value; _isInvalidScreenPos = true; }
        public function set y(value:Number):void { validateWorldPos(); _worldY = value; _isInvalidScreenPos = true; }
        public function set z(value:Number):void { validateWorldPos(); _worldZ = value; _isInvalidScreenPos = true; }
        public function set screenX(value:Number):void { validateScreenPos(); _screenX = value; _isInvalidWorldPos = true; }
        public function set screenY(value:Number):void { validateScreenPos(); _screenY = value; _isInvalidWorldPos = true; }
    }
//}