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

Complementary Penrose Stairs Fractal

思わず自画自賛したくなる美しさ!
Get Adobe Flash player
by o8que 23 Apr 2011
/**
 * Copyright o8que ( http://wonderfl.net/user/o8que )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/atBv
 */

/* ------------------------------------------------------------------------------------------------
 * [階段シリーズ]
 * http://wonderfl.net/c/zQW4 hiyoko vs. unko (HVU)
 * http://wonderfl.net/c/2epI A
 * http://wonderfl.net/c/z1Fp Penrose Stairs Complex
 * http://wonderfl.net/c/lVRx Penrose Stairs Fractal
 * http://wonderfl.net/c/atBv Complementary Penrose Stairs Fractal
 * ------------------------------------------------------------------------------------------------
 */
package {
    import com.bit101.components.Label;
    import com.bit101.components.NumericStepper;
    import flash.display.Sprite;
    import flash.events.Event;
    
    [SWF(width="465",height="465",frameRate="30",backgroundColor="0x000000")]
    public class Main extends Sprite {
        private static const TILE_SIZE:Number = 82;
        
        public function Main() {
            graphics.beginFill(0x000000);
            graphics.drawRect(0, 0, 465, 465);
            graphics.endFill();
            
            var penroseStairs:IsoObject;
            var isoContainer:Sprite = new Sprite();
            isoContainer.x = 232.5 - TILE_SIZE / 4;
            isoContainer.y = 732;
            addChild(isoContainer);
            
            new Label(this, 10, 10, "level");
            var level:NumericStepper = new NumericStepper(this, 50, 10, function(event:Event):void {
                isoContainer.removeChild(penroseStairs);
                isoContainer.addChild(penroseStairs = new CPSF(level.value, TILE_SIZE, 0x0));
            });
            level.minimum = 1;
            level.maximum = 4;
            
            isoContainer.addChild(penroseStairs = new CPSF(1, TILE_SIZE, 0x0));
        }
    }
}
/* ------------------------------------------------------------------------------------------------
 * IsoObject
 * ------------------------------------------------------------------------------------------------
 */
//package {
    import flash.display.Sprite;
    import flash.geom.Point;
    import flash.geom.Vector3D;
    
    //public 
    class IsoObject extends Sprite {
        private var _world:Vector3D;
        private var _screen:Point;
        
        public function IsoObject() {
            _world = new Vector3D(0, 0, 0);
            _screen = new Point(0, 0);
        }
        
        public function update():void {
            x = _screen.x;
            y = _screen.y;
        }
        
        public function get wx():Number { return _world.x; }
        public function set wx(value:Number):void { _world.x = value; IsoUtils.isoToScreen(_world, _screen); update(); }
        public function get wy():Number { return _world.y; }
        public function set wy(value:Number):void { _world.y = value; IsoUtils.isoToScreen(_world, _screen); update(); }
        public function get wz():Number { return _world.z; }
        public function set wz(value:Number):void { _world.z = value; IsoUtils.isoToScreen(_world, _screen); update(); }
        public function get sx():Number { return _screen.x; }
        public function set sx(value:Number):void { _screen.x = value; IsoUtils.screenToIso(_screen, _world); update(); }
        public function get sy():Number { return _screen.y; }
        public function set sy(value:Number):void { _screen.y = value; IsoUtils.screenToIso(_screen, _world); update(); }
    }
//}
/* ------------------------------------------------------------------------------------------------
 * CPSF
 * ------------------------------------------------------------------------------------------------
 */
//package {
    //public 
    class CPSF extends IsoObject {
        private var _children:Vector.<CPSF>;
        
        private var tr:uint;    // top-right pattern
        private var bl:uint;    // bottom-left pattern
        
        public function CPSF(level:int, size:Number, pattern:uint) {
            if (level == 1) {
                buildLv1(size, pattern);
            }else {
                _children = new Vector.<CPSF>(10, true);
                build(level, size, pattern);
            }
        }
        
        private function buildLv1(size:Number, pattern:uint):void {
            var type:uint = pattern & 0x1;
            var step:Array, tileX:Array, tileZ:Array;
            if (type == 0) {
                step = STEP0, tileX = TILEX0, tileZ = TILEZ0;
            }else {
                step = STEP1, tileX = TILEX1, tileZ = TILEZ1;
            }
            var riser:Number = -size / 10;
            for (var i:int = 0; i < 10; i++) {
                var tile:IsoObject = new IsoBox(size, 500);
                tile.wx = size * tileX[i];
                tile.wy = riser * step[i];
                tile.wz = size * tileZ[i];
                addChild(tile);
            }
            sx = ((type == 0) ? -1 : 1) * size / 4;
            sy = -size * 1.2;
            tr = bl = type;
        }
        
        private function build(level:int, size:Number, pattern:uint):void {
            var type:uint = pattern & 0x1;
            var step:Array, tileX:Array, tileZ:Array, determineTL:Function;
            if (type == 0) {
                step = STEP0, tileX = TILEX0, tileZ = TILEZ0, determineTL = determineTL0;
            }else {
                step = STEP1, tileX = TILEX1, tileZ = TILEZ1, determineTL = determineTL1;
            }
            var riser:Number = -size / 10;
            for (var i:int = 0; i < 10; i++) {
                var tile:CPSF = new CPSF(level - 1, size / 3.49, determineTL(i, pattern));
                tile.wx += size * tileX[i];
                tile.wy += riser * step[i];
                tile.wz += size * tileZ[i];
                addChild(tile);
                
                _children[i] = tile;
                switch(i) {
                    case 3: { tr = (_children[3].tr << 1) + type; break; }
                    case 6: { if (type == 1) bl = (_children[6].bl << 1) + type; break; }
                    case 7: { if (type == 0) bl = (_children[7].bl << 1) + type; break; }
                }
            }
            sx = ((type == 0) ? -1 : 1) * size / 4;
            sy = -size * 1.2;
        }
        
        private function determineTL0(index:int, pattern:uint):uint {
            switch(index) {
                case 0: { return pattern >> 1; }
                case 1: { return ~_children[0].tr; }
                case 2: { return ~_children[1].tr; }
                case 3: { return ~_children[2].tr; }
                case 4: { return ~_children[3].bl; }
                case 5: { return ~_children[0].bl; }
                case 6: { return ~_children[4].bl; }
                case 7: { return ~_children[5].bl; }
                case 8: { return ~_children[7].tr; }
                case 9: { return ~_children[8].tr; }
                default: { return 0x0; }
            }
        }
        
        private function determineTL1(index:int, pattern:uint):uint {
            switch(index) {
                case 0: { return pattern >> 1; }
                case 1: { return ~_children[0].bl; }
                case 2: { return ~_children[0].tr; }
                case 3: { return ~_children[2].tr; }
                case 4: { return ~_children[1].bl; }
                case 5: { return ~_children[3].bl; }
                case 6: { return ~_children[4].bl; }
                case 7: { return ~_children[6].tr; }
                case 8: { return ~_children[7].tr; }
                case 9: { return ~_children[8].tr; }
                default: { return 0x0; }
            }
        }
        
        private static const STEP0:Array = [0, 1, 2, 3, 4, 9, 5, 8, 7, 6];
        private static const STEP1:Array = [0, 1, 9, 8, 2, 7, 3, 4, 5, 6];
        private static const TILEX0:Array = [0, 1, 2, 3, 3, 1, 3, 1, 2, 3];
        private static const TILEX1:Array = [0, 0, 2, 3, 0, 3, 0, 1, 2, 3];
        private static const TILEZ0:Array = [0, 0, 0, 0, -1, -2, -2, -3, -3, -3];
        private static const TILEZ1:Array = [0, -1, -1, -1, -2, -2, -3, -3, -3, -3];
    }
//}
/* ------------------------------------------------------------------------------------------------
 * IsoBox
 * ------------------------------------------------------------------------------------------------
 */
//package {
    
    //public 
    class IsoBox extends IsoObject {
        private var _size:Number;
        private var _height:Number;
        
        public function IsoBox(size:Number, height:Number) {
            super();
            _size = size;
            _height = height;
            draw();
        }
        
        private function draw():void {
            var halfSize:Number = _size / 2;
            graphics.clear();
            graphics.moveTo(0, halfSize - _height);
            
            drawTopFace();
            drawLeftFace();
            drawRightFace();
            
            function drawTopFace():void {
                graphics.lineStyle(0, 0xC0C0C0);
                graphics.beginFill(0xFFFFFF);
                graphics.lineTo( -_size, -_height);
                graphics.lineTo(0, -halfSize - _height);
                graphics.lineTo(_size, -_height);
                graphics.lineTo(0, halfSize - _height);
                graphics.endFill();
            }
            
            function drawLeftFace():void {
                graphics.lineStyle();
                graphics.beginFill(0xC0C0C0);
                graphics.lineTo(0, halfSize);
                graphics.lineTo( -_size, 0);
                graphics.lineTo( -_size, -_height);
                graphics.lineTo(0, halfSize - _height);
                graphics.endFill();
            }
            
            function drawRightFace():void {
                graphics.lineStyle();
                graphics.beginFill(0x808080);
                graphics.lineTo(0, halfSize);
                graphics.lineTo(_size, 0);
                graphics.lineTo(_size, -_height);
                graphics.lineTo(0, halfSize - _height);
                graphics.endFill();
            }
        }
        
        override public function get height():Number { return _height; }
        override public function set height(value:Number):void { _height = value; draw(); }
    }
//}
/* ------------------------------------------------------------------------------------------------
 * IsoUtils
 * ------------------------------------------------------------------------------------------------
 */
//package {
    import flash.geom.Point;
    import flash.geom.Vector3D;
    
    //public 
    class IsoUtils {
        public static const TRUE_SCALE:Number = Math.cos( -30 * Math.PI / 180) * Math.SQRT2;
        
        public static function isoToScreen(iso:Vector3D, out:Point = null):Point {
            out ||= new Point(0, 0);
            out.x = iso.x + iso.z;
            out.y = (iso.x - iso.z) / 2 + iso.y;
            return out;
        }
        
        public static function screenToIso(screen:Point, out:Vector3D = null):Vector3D {
            out ||= new Vector3D(0, 0, 0);
            out.x = (screen.x / 2 + screen.y) - out.y;
            out.z = (screen.x / 2 - screen.y) + out.y;
            return out;
        }
        
        public static function compareDepth(a:Vector3D, b:Vector3D):Number {
            return (a.x - a.y - a.z) - (b.x - b.y - b.z);
        }
    }
//}