Beautifl - Flash Gallery

Thumbnail : School of Musical Notes
School of Musical Notes
naraba 2012-02-11 MIT License

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

package {
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import org.si.sion.*;
    import org.si.sion.utils.SiONPresetVoice;
    
    public class SoundBoid extends MovieClip
    {
        private const DIST_OF_VIEW:int = 50;
        private const DIST_OF_AT:int = 30;
        private const MAX_VELOCITY:int = 4;
        private const TADPOLE_HEAD:int = 5;
        private const TADPOLE_TAIL:int = 30;
        private const TADPOLE_FLG1:int = 5;
        private const TADPOLE_ARG1:Number = -Math.PI / 4;
        private const TADPOLE_FLG2:int = 2;
        private const TADPOLE_ARG2:Number = TADPOLE_ARG1 - Math.PI / 30;
        private const TADPOLE_VALUES:Array = [1, 2, 4, 8];
        private const UNIT_VALUE:int = 8;
        private const BASE_PITCH:int = 48;
        private const LINES_PITCH:Array = [10, 7, 5, 3, 0];
        
        private var school:Array;
        private var lines:Array;
        private var driver:SiONDriver;
        private var voice:SiONVoice;
        
        public function SoundBoid()
        {
            driver = new SiONDriver();
            var preset:SiONPresetVoice = new SiONPresetVoice();
            voice = preset["valsound.guitar1"];
            driver.play();
            
            init();
            addEventListener(Event.ENTER_FRAME, update);
            stage.addEventListener(MouseEvent.MOUSE_UP, add);
        }
        
        private function init():void
        {
            school = new Array();
            lines = new Array();
            for (var j:int = 1; j <= LINES_PITCH.length; j++) {
                lines.push(stage.stageHeight / LINES_PITCH.length * (j - 0.5));
            }
        }
        
        private function add(e:MouseEvent):void
        {
            var t:Tadpole = new Tadpole();
            t.px = t.x = e.stageX;
            t.py = t.y = e.stageY;
            t.vx = Math.sqrt(MAX_VELOCITY) * (Math.random() * 2 - 1);
            t.vy = Math.sqrt(MAX_VELOCITY) * (Math.random() * 2 - 1);
            t.nv = TADPOLE_VALUES[Math.floor(Math.random() * TADPOLE_VALUES.length)];
            t.hit = 0x000000;
            school.push(t);    
        }
        
        private function update(e:Event):void
        {
            var tmpn:Number;
            var tmpx:Number;
            var tmpy:Number;
            var o:Tadpole;
            
            for each (var t:Tadpole in school) {
                // separation
                var svx:Number = 0;
                var svy:Number = 0;
                for each (o in school) {
                    if (t != o && distance(t.x, t.y, o.x, o.y) < DIST_OF_AT) {
                        svx -= (o.x - t.x);
                        svy -= (o.y - t.y);
                    }
                }
                
                // alignment
                var avx:Number = 0;
                var avy:Number = 0;
                tmpx = 0;
                tmpy = 0;
                tmpn = 0;
                for each (o in school) {
                    if (t != o && distance(t.x, t.y, o.x, o.y) < DIST_OF_VIEW) {
                        tmpx += o.vx;
                        tmpy += o.vy;
                        tmpn++;
                    }
                }
                if (tmpn > 0) {
                    cvx = tmpx / tmpn - t.x;
                    cvy = tmpy / tmpn - t.y;
                }
                
                // cohesion
                var cvx:Number = 0;
                var cvy:Number = 0;
                tmpx = 0;
                tmpy = 0;
                tmpn = 0;
                for each (o in school) {
                    if (t != o && distance(t.x, t.y, o.x, o.y) < DIST_OF_VIEW) {
                        tmpx += o.x;
                        tmpy += o.y;
                        tmpn++;
                    }
                }
                if (tmpn > 0) {
                    cvx = tmpx / tmpn - t.x;
                    cvy = tmpy / tmpn - t.y;
                }
                
                // update and play
                tmpx = t.vx + svx / 100 + avx + cvx / 100;
                tmpy = t.vy + svy / 100 + avy + cvy / 100;
                var v:Number = distance(tmpx, tmpy, 0, 0);
                if (v > MAX_VELOCITY) {
                    tmpx = (tmpx / v) * MAX_VELOCITY;
                    tmpy = (tmpy / v) * MAX_VELOCITY;
                }
                t.vx = tmpx;
                t.vy = tmpy;
                t.px = t.x;
                t.py = t.y;
                t.x += t.vx;
                t.y += t.vy;
                if (t.x < TADPOLE_HEAD && t.vx < 0) t.vx = -t.vx;
                if (t.x > stage.stageWidth - TADPOLE_HEAD && t.vx > 0) t.vx = -t.vx;
                if (t.y < TADPOLE_HEAD && t.vy < 0) t.vy = -t.vy;
                if (t.y > stage.stageHeight - TADPOLE_HEAD && t.vy > 0) t.vy = -t.vy;
                playNote(t);
            }
            draw();
        }
        
        private function distance(x1:Number, y1:Number, x2:Number, y2:Number):Number
        {
            return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
        }
        
        private function doNoteOn(py:Number, cy:Number, ly:Number):Boolean {
            return (py > ly && ly > cy) || (py < ly && ly < cy);
        }
        
        private function playNote(t:Tadpole):void 
        {
            for (var i:int = 0; i < lines.length; i++) {
                if (doNoteOn(t.py, t.y, lines[i])) {
                    driver.noteOn(BASE_PITCH + LINES_PITCH[i], voice, UNIT_VALUE / t.nv);
                    t.hit = 0xFFFF00;
                }
            }
        }
        
        private function draw():void
        {
            var arg:Number;
            var fillcol:uint;
            
            graphics.clear();
            graphics.beginFill(0xFFFFFF);
            graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
            graphics.endFill();
            
            graphics.lineStyle(2, 0x008888);
            for each (var ly:int in lines) {                
                graphics.moveTo(0, ly);
                graphics.lineTo(stage.stageWidth, ly);
            }
            
            graphics.lineStyle(2, 0x000000);
            for each (var t:Tadpole in school) {
                if (t.hit > 0x222200) {
                    graphics.beginFill(t.hit, 0.5);
                    t.hit -= 0x222200
                } else if (t.nv == 1 || t.nv == 2) {
                    graphics.beginFill(0xFFFFFF, 0);
                } else {
                    graphics.beginFill(0x000000, 1);
                }
                graphics.drawCircle(t.x, t.y, TADPOLE_HEAD);
                graphics.endFill();
                if (t.nv != 1) {
                    arg = Math.atan2(t.vy, t.vx);
                    graphics.moveTo(t.x + TADPOLE_HEAD * Math.sin(arg), t.y - TADPOLE_HEAD * Math.cos(arg));
                    graphics.lineTo(t.x + TADPOLE_HEAD * Math.sin(arg) - TADPOLE_TAIL * Math.cos(arg), 
                                    t.y - TADPOLE_HEAD * Math.cos(arg) - TADPOLE_TAIL * Math.sin(arg));
                    if (t.nv == 8) {
                        var f:Number = Math.sin(arg) < 0 ? 2 : 1
                        graphics.curveTo(t.x + TADPOLE_HEAD * TADPOLE_FLG1 * Math.sin(arg + f * TADPOLE_ARG1),
                                         t.y - TADPOLE_HEAD * TADPOLE_FLG1 * Math.cos(arg + f * TADPOLE_ARG1),
                                         t.x + TADPOLE_HEAD * TADPOLE_FLG2 * Math.sin(arg + f * TADPOLE_ARG2),
                                         t.y - TADPOLE_HEAD * TADPOLE_FLG2 * Math.cos(arg + f * TADPOLE_ARG2));
                    }
                }
            }
        }
    }
}

class Tadpole
{
    public var x:Number;
    public var y:Number;
    public var px:Number;
    public var py:Number;
    public var vx:Number;
    public var vy:Number;
    public var nv:Number;
    public var hit:uint;
}