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

post_submission

Get Adobe Flash player
by wexler 11 May 2011
/**
 * Copyright wexler ( http://wonderfl.net/user/wexler )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/8KUB
 */

// forked from wexler's submission
// forked from wexler's multiframe_buttons
package {
    import flash.ui.ContextMenuClipboardItems;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.*;
    import flash.utils.getTimer;
    import flash.text.*;
    import net.hires.debug.Stats;
    import com.bit101.components.*;
    
    [SWF(width = "900", height = "700", frameRate = "60", backgroundColor = "#7F7F7F")]

    public class main extends Sprite {
        
        private const _size:uint = 700;    // in [SWF... field, height should be _size
        private const _frame_rate:Number = 60;    // make sure that this is the same as in [SWF...]
        private const _n_lines:uint = 1000;
        private const _r_min:Number = 0.475;
        private const _r_max:Number = 0.95;
        private const _min_len:Number = 7;
        private const _max_len:Number = 14;
        private const _line_width:int = 3;
        private const _max_frames:uint = 53;        // this should be a prime number
        private const _fp_radius:uint = 4;
        private const _control_field:uint = 200;    // in [SWF... field, width should be _size + _control_field
        private const _button_margin:uint = 50;
        private const _button_spacing:uint = 20;
        private const _expl_button_size:uint = 60;
        
        private const _expl_size:int = 16;
        private const _explanation:String = ( <![CDATA[<p>Most observers perceive that the ring of lines rotates slowly, with brief jumps of much faster rotation in the opposite direction. <b>The very fast jumps are illusory.</b> The illusion usually gets stronger after one or two jumps, and seems to be enhanced by paying close attention to the lines in the ring.

The illusion is produced by completely re-randomizing the lines on every frame; this is done for one or more frames, and then the new configuration is set to turning once again. In other words, although a partial match between two lines before and after the 'jump' may be found at many different positions, chances are none of the neighboring lines will match. Technically, there is no peak in motion energy at the particlar backwards jumps that are seen.

This illusory motion seems to be a kind of motion aftereffect (MAE), but with two main differences. First of all, the illusory motion is extremely fast, certainly much faster than the slow, inducing motion. (In the typical MAE, the illusory motion is considerably slower than the inducer.) Second, many observers readily report the <i>amplitude</i> of the illusory jumps, in contrast to normal MAE where motion is perceived without any definite position change. This amplitude depends on the duration of the noise burst and varies from observer to observer, but is typically between 10 and 60 degrees. In fast, using these reports, I find that for brief noise bursts, the illusory motion is 10-100 faster than the inducer!

The "Reverse" button changes the direction of the slow rotation; the jumps are almost always seen in the opposite direction to the slow rotation. The speed of the inducing motion can also be changed ("Inducer speed"), but does not seem to have a strong effect on the illusory motion. Noise duration (number of random frames), however, does have an effect on illusory motion: at longer durations, the illusory motion seems to slow down.

The frequency of the noise bursts can also be changed. At the higher frequency, many people perceive a net rotation opposite the motion of the inducer. Thus, we get more (illusory) motion out than (real) motion we put in: a perceptual, perpetual motion machine!

It is known that brief probes yield larger aftereffects (Wolfe, <i>Vis. Res.</i>, 1984), and that noisy probes can also enhance some aspects of aftereffects (Hiris and Blake, <i>PNAS</i>, 1992) - but these techniques in isolation still yield aftereffects smaller in magnitude than the inducing stimuli. The combination of the two yields this striking and novel illusion, in which the illusory motion is many times faster than the inducing stimulus.
]]> ).toString();

        private var _lines:Array = new Array(_max_frames);
        private var _in_noise:Boolean = false;
        private var _frame:uint = 0;                // current frame, which just keeps counting up (the actual frame used is mod _max_frames)
        private var _noise_stop_t:uint;
        private var _noise_frames:uint = 3;
        private var _stats:* = undefined;
        private var _theta0:Number;
        private var _dir:int = +1;
        private var _speed:Number = 10.0;            // in deg/sec
        private var _last_velmod_t:uint;
        private var _last_velmod_ang:Number;
        private var _noise_period:uint = 5000;      // in msec; if 0, means no automatic noise
        private var _last_noise_t:uint;
        private var _state:String;
        private var _intro_display:*;
        private var _begin_button:*;
        private var _expl_but:* = undefined;
        private var _expl_text:*;
        private var _expl_prev_state:String;
        private var _randomize_all:Boolean = false;
        
        public function main()
        {
            Style.LABEL_TEXT = 0x202020;
            Style.BACKGROUND = 0xA0A0A0;
            
            randomize();
            _last_velmod_t = _last_noise_t = getTimer();
            _theta0 = _last_velmod_ang = 0;
            addEventListener(Event.ENTER_FRAME, update);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, mouse_listener);
            create_buttons();
            begin_intro();
        }
        
        public function begin_intro():void
        {
            _state = "intro";
            _intro_display = new TextField();
            _intro_display.text = "Fixate the red point you will see in the center\nwhile paying attention to the rotating ring\nof gray lines\n";
            var format:TextFormat = new TextFormat(); 
            format.color = 0x000000;
            format.size = 24;
            format.align = "center";
            _intro_display.setTextFormat(format);
            _intro_display.x = 0;
            _intro_display.y = 100;
            _intro_display.width = _size;
            _intro_display.height = 100;
            addChild(_intro_display);
            
            _begin_button = new PushButton(this, _size/2, _size/2, "BEGIN", begin);
            _begin_button.x -= _begin_button.width/2;
            _begin_button.y -= _begin_button.height/2;
        }
        
        public function end_intro():void
        {
            removeChild(_intro_display);
            removeChild(_begin_button);
        }
        
        public function begin(e:MouseEvent):void
        {
            end_intro();
            begin_display();
        }
        
        public function begin_display():void
        {
            _state = "display";
            _last_velmod_t = _last_noise_t = getTimer();
            _theta0 = _last_velmod_ang = 0;
        }
        
        public function end_display():void
        {
            graphics.clear();
        }

        public function create_buttons():void
        {
            var y:uint = 0;
            var rb:RadioButton;
            
            var rev_but:PushButton = new PushButton(this, _size + _button_margin, y, "REVERSE", reverse);
            y = 45;
            
            var freq_vbox:VBox = new VBox(this, _size + _button_margin, y);
            new Label(freq_vbox, 0, 0, "NOISE FREQUENCY");
            rb = new RadioButton(freq_vbox, 0, 0, "LOW",     true , set_noise_freq); rb.tag = 0; rb.groupName = "freq";
            rb = new RadioButton(freq_vbox, 0, 0, "HIGH",    false, set_noise_freq); rb.tag = 1; rb.groupName = "freq";
            rb = new RadioButton(freq_vbox, 0, 0, "MANUAL\n(CLICK ON STIMULUS)",
                                                             false, set_noise_freq); rb.tag = 2; rb.groupName = "freq";
            y = 145;
            
            var dur_vbox:VBox = new VBox(this, _size + _button_margin, y);
            new Label(dur_vbox, 0, 0, "NOISE DURATION");
            rb = new RadioButton(dur_vbox, 0, 0, "BRIEF",     false, set_noise_dur); rb.tag = 0; rb.groupName = "dur";
            rb = new RadioButton(dur_vbox, 0, 0, "MEDIUM",    true , set_noise_dur); rb.tag = 1; rb.groupName = "dur";
            rb = new RadioButton(dur_vbox, 0, 0, "LONG",      false, set_noise_dur); rb.tag = 2; rb.groupName = "dur";
            rb = new RadioButton(dur_vbox, 0, 0, "VERY LONG", false, set_noise_dur); rb.tag = 3; rb.groupName = "dur";
            y = 247;
            
            var speed_vbox:VBox = new VBox(this, _size + _button_margin, y);
            new Label(speed_vbox, 0, 0, "INDUCER SPEED");
            rb = new RadioButton(speed_vbox, 0, 0, "ZERO",      false, change_speed); rb.tag = 0; rb.groupName = "speed";
            rb = new RadioButton(speed_vbox, 0, 0, "VERY SLOW", false, change_speed); rb.tag = 1; rb.groupName = "speed";
            rb = new RadioButton(speed_vbox, 0, 0, "SLOW",      true , change_speed); rb.tag = 2; rb.groupName = "speed";
            rb = new RadioButton(speed_vbox, 0, 0, "MEDIUM",    false, change_speed); rb.tag = 3; rb.groupName = "speed";
            rb = new RadioButton(speed_vbox, 0, 0, "FAST",      false, change_speed); rb.tag = 4; rb.groupName = "speed";
            y = 361;
            
            var change_vbox:VBox = new VBox(this, _size + _button_margin, y);
            new Label(change_vbox, 0, 0, "CHANGE");
            rb = new RadioButton(change_vbox, 0, 0, "EVERYTHING",      true , set_change); rb.tag = 0; rb.groupName = "change";
            rb = new RadioButton(change_vbox, 0, 0, "BLACK <-> WHITE", false, set_change); rb.tag = 1; rb.groupName = "change";
           
            _expl_but = new PushButton(this, _size + _button_margin, 500 - _expl_button_size, "WHAT'S GOING ON?", toggle_explain);
            _expl_but.height = _expl_button_size;
        }
        
        public function reverse(e:MouseEvent):void
        {
            _last_velmod_t = _last_noise_t = getTimer();
            _last_velmod_ang = _theta0;
            _dir *= -1;
            _in_noise = false;
        }
        
        public function set_noise_freq(e:MouseEvent):void
        {
            switch(RadioButton(e.currentTarget).tag) {
                case 0:
                    _noise_period = 5000;
                    break;
                case 1:
                    _noise_period = 500;
                    break;
                case 2:
                    _noise_period = 0;
                    break;
            }
        }
        
        public function set_noise_dur(e:MouseEvent):void
        {
            switch(RadioButton(e.currentTarget).tag) {
                case 0:
                    _noise_frames = 1;
                    break;
                case 1:
                    _noise_frames = 3;
                    break;
                case 2:
                    _noise_frames = 6;
                    break;
                case 3:
                    _noise_frames = 30;
                    break;
            }
        }
         
        public function change_speed(e:MouseEvent):void
        {           
            _last_velmod_t = _last_noise_t = getTimer();
            _last_velmod_ang = _theta0;
            _in_noise = false;
            switch(RadioButton(e.currentTarget).tag) {
                case 0:
                    _speed = 0;
                    break;
                case 1:
                    _speed = 5;
                    break;
                case 2:
                    _speed = 10;
                    break;
                case 3:
                    _speed = 20;
                    break;
                 case 4:
                    _speed = 40;
                    break;
            }
        }
         
        public function set_change(e:MouseEvent):void
        {           
            switch(RadioButton(e.currentTarget).tag) {
                case 0:
                    _randomize_all = true;
                    break;
                case 1:
                    _randomize_all = false;
                    break;
            }
        }
         
        public function toggle_explain(e:MouseEvent):void
        {
            if(_state != "explain") {
                _expl_prev_state = _state;
                _state = "explain";
                if(_expl_prev_state == "intro")
                    end_intro();
                else if(_expl_prev_state == "display")
                    end_display();
                _expl_text = new TextField();
                _expl_text.multiline = true;
                _expl_text.wordWrap = true;
                
                var style:StyleSheet = new StyleSheet();
                var styleObj:Object = new Object();
                styleObj.fontSize = _expl_size;
                style.setStyle("p", styleObj); 
                _expl_text.styleSheet = style; 

                _expl_text.htmlText = _explanation;
                _expl_text.x = _intro_display.y = 0;
                _expl_text.width = _expl_text.height = _size;
                addChild(_expl_text);
                _expl_but.label = "GO BACK";
            }
            else {
                removeChild(_expl_text);
                _state = _expl_prev_state;
                if(_state == "intro")
                    begin_intro();
                else if(_state == "display")
                    begin_display();
                _expl_but.label = "WHAT'S GOING ON?";
           }
        }
  
        public function update(e:Event):void
        {
            if(_state == "display") {
                const t:uint = getTimer();
                _theta0 = _last_velmod_ang + (t - _last_velmod_t)*_dir*_speed*(Math.PI/180)/1000.0;
                if(_noise_period > 0) {            // check if we need to start noise
                    if(t > _last_noise_t + _noise_period) {
                        start_noise();
                        _last_noise_t = t;
                    }
                }
                if(_in_noise) {
                    //if(_frame < _last_noise_frame) {
                    if(t < _noise_stop_t) {
                        _frame++;
                    }
                    else {
                        _in_noise = false;
                    }
                }
                graphics.clear();
                for each(var z:line in _lines[_frame%_max_frames]) {
                    const a:Number = z.theta + _theta0;
                    const x:Number = (1 + z.r*Math.cos(a))*_size/2;
                    const y:Number = (1 - z.r*Math.sin(a))*_size/2;
                    const o:Number = z.orient - a;
                    const dx:Number = z.len*Math.cos(o);
                    const dy:Number = z.len*Math.sin(o);
                    graphics.lineStyle(_line_width, z.color)
                    graphics.moveTo(x - dx, y - dy);
                    graphics.lineTo(x + dx, y + dy);
                }
                
                graphics.lineStyle(NaN);
                graphics.beginFill(0xFF0000);
                graphics.drawCircle(_size/2, _size/2, _fp_radius);
                graphics.endFill();
            }
        }
       
        public function mouse_listener(e:MouseEvent):void
        {
            if(!e.shiftKey) {
                if(e.stageX < _size) {
                    start_noise();
                }
            }
            else {
                if(_stats) {
                    removeChild(_stats);
                    _stats = undefined;
                }
                else {
                    _stats = addChild(new Stats());
                }
            }
        }
        
        public function start_noise():void
        {
            if(!_in_noise) {
                if(_randomize_all) {
                    _in_noise = true;
                    _noise_stop_t = getTimer() + (0.5 + _noise_frames)*1000.0/_frame_rate;
                }
                else {
                    for(var i:uint = 0; i < _n_lines; i++) {
                        _lines[_frame][i].reverse_polarity();
                    }
                }
            }
        }

        private function randomize():void {
            const z:Number = Math.pow(_r_min/_r_max, 2);
            const u:Number = 1 - z;
            for(var f:uint = 0; f < _max_frames; f++) {
                _lines[f] = new Array(_n_lines);
                for(var i:uint = 0; i < _n_lines; i++) {
                    var r:Number = Math.sqrt(z + u*Math.random())*_r_max;
                    var th:Number = Math.random()*2*Math.PI;
                    var gray:uint = Math.random() < 0.5 ? 0 : 255;
                    var o:Number = Math.random()*2*Math.PI;
                    var l:Number = _min_len + (_max_len - _min_len)*Math.random();
                    _lines[f][i] = new line(r, th, gray + 256*gray + 65536*gray, o, l);
                }
            }
        }
    }
}

class line 
{ 
    public var r:Number;
    public var theta:Number;
    public var color:uint;
    public var orient:Number;
    public var len:Number;
    public function line(R:Number, Theta:Number, Color:uint, Orient:Number, Len:Number)
    {
        r = R;
        theta = Theta;
        color = Color;
        orient = Orient;
        len = Len;
    }
    
    public function reverse_polarity():void
    {
        color = ~color;
    }
}