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

シャボン玉 / Soap bubble

クリックすると何かが起こるかも。
※つぶれなくなりました

・大きさや解像度を最適化。
・かなり高速化。よりつぶれにくく。
・輪郭を滑らかに。回転しにくく!←New!
/**
 * Copyright saharan ( http://wonderfl.net/user/saharan )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/pnIc
 */

/*
 * シャボン玉/Soap bubble
 *
 * クリックすると何かが起こるかも。
 * ※つぶれなくなりました
 *
 * ・大きさや解像度を最適化。
 * ・かなり高速化。よりつぶれにくく。
 * ・輪郭を滑らかに。回転しにくく!←New!
 */
package {
    import flash.filters.BlurFilter;
    import flash.geom.*;
    import flash.display.*;
    import flash.events.*;
    import flash.events.*;
    import flash.display.*;
    [SWF(frameRate = "60")]
    public class SorpBubble extends Sprite {
        private var bubbles:Vector.<Bubble>;
        private var press:Boolean;
        private var bitmap:BitmapData;
        public function SorpBubble() {
            initialize();
        }
        
        private function initialize():void {
            bubbles = new Vector.<Bubble>();
            for(var i:int = 0; i < 60; i++)
                bubbles[i] = new Bubble(50 + Math.random() * 365,
                    50 + Math.random() * 365, 10 + Math.random() * 30);
            bitmap = new BitmapData(465, 465, false, 0);
            addChild(new Bitmap(bitmap));
            addEventListener(Event.ENTER_FRAME, frame);
            stage.addEventListener(MouseEvent.MOUSE_DOWN, function():void { press = true; });
            stage.addEventListener(MouseEvent.MOUSE_UP, function():void { press = false; });
        }

        private function frame(e:Event):void {
            var b:Bubble;
            if(press) {
                for each(b in bubbles) {
                    b.collision(mouseX, mouseY);
                }
            }
            var sp:Sprite = new Sprite();
            for each(b in bubbles) {
                b.move();
                b.draw(sp.graphics);
            }
            bitmap.colorTransform(bitmap.rect, new ColorTransform(1, 1, 1, 0.85));
            bitmap.draw(sp);
        }
    }
}

import flash.display.*;

class Bubble {
    public var springs:Vector.<Spring>;
    public var vertices:Vector.<Vertex>;
    public var windAngle:Number;
    private var wind:Number;
    private var targetArea:Number;
    private var numVertices:int;
    public function Bubble(x:Number, y:Number, size:Number) {
        wind = 0;
        springs = new Vector.<Spring>();
        vertices = new Vector.<Vertex>();
        var i:int;
        var j:int;
        numVertices = size / 2 + 2;
        var ang:Number = 0;
        var dAng:Number = Math.PI * 2 / numVertices;
        for(i = 0; i < numVertices; i++) {
            vertices[i] = new Vertex(x + Math.cos(ang) * size, y + Math.sin(ang) * size);
            ang += dAng;
        }
        targetArea = calcArea();
        for(i = 0; i < numVertices; i++)
             springs[i] = new Spring(vertices[i], vertices[(i + 1) % numVertices]);
        windAngle = Math.random() * Math.PI * 2;
    }

    public function move():void {
        for each(var s:Spring in springs)
            s.move();
        var i:int;
        var v:Vertex;
        var outer:Number = 0; // 外周
        for(i = 0; i < numVertices; i++) {
            v = vertices[i];
            var next:Vertex = vertices[(i + 1) % numVertices];
            var dx:Number = next.x - v.x;
            var dy:Number = next.y - v.y;
            var invDistance:Number = Math.sqrt(dx * dx + dy * dy);
            outer += invDistance;
            invDistance = 1 / invDistance;
            v.nx = dy * invDistance; // 頂点法線ベクトルを計算
            v.ny = -dx * invDistance;
        }
        var k:Number = (targetArea - calcArea()) / outer * 2;
        for each(v in vertices) {
            v.vx += v.nx * k;
            v.vy += v.ny * k;
            v.vx += wind * Math.cos(windAngle) * 3;
            v.vy += wind * Math.sin(windAngle) * 3;
            v.move();
        }
        wind += Math.random() * 0.005 - 0.0025;
        wind *= 0.99;
        windAngle += Math.random() * 0.05 - 0.025;
    }

    public function draw(graphics:Graphics):void {
        for(var i:int = 0; i < numVertices; i++) {
            const v:Vertex = vertices[i];
            const prev:Vertex = vertices[(i + numVertices - 1) % numVertices];
            const next:Vertex = vertices[(i + 1) % numVertices];
            graphics.lineStyle(1, v.color);
            graphics.moveTo((prev.x + v.x) * 0.5, (prev.y + v.y) * 0.5);
            graphics.curveTo(v.x, v.y, (v.x + next.x) * 0.5, (v.y + next.y) * 0.5);
        }
    }

    public function collision(x:Number, y:Number):void {
        for each(var v:Vertex in vertices) {
            var dx:Number = x - v.x;
            var dy:Number = y - v.y;
            if(dx * dx + dy * dy < 10000) {
                var dist:Number = Math.sqrt(dx * dx + dy * dy);
                dx /= dist;
                dy /= dist;
                var overlap:Number = 100 - dist;
                v.vx -= dx * overlap * 0.0125;
                v.vy -= dy * overlap * 0.0125;
                v.x -= dx * overlap * 0.00625;
                v.y -= dy * overlap * 0.00625;
            }
        }
    }
    
    public function calcArea():Number { // 外積から大体の面積を求める
        var area:Number = 0;
        for(var i:int = 0; i < numVertices; i++) {
            var next:int = (i + 1) % numVertices;
            area += vertices[i].x * vertices[next].y - vertices[i].y * vertices[next].x;
        }
        area *= 0.5;
        return area;
    }

}

class Spring {
    public var v1:Vertex;
    public var v2:Vertex;
    public var targetDistance:Number;
    public function Spring(v1:Vertex, v2:Vertex) {
        this.v1 = v1;
        this.v2 = v2;
        targetDistance = calcDistance();
    }

    public function move():void {
        var dx:Number = v2.x - v1.x;
        var dy:Number = v2.y - v1.y;
        var rx:Number = v2.vx - v1.vx;
        var ry:Number = v2.vy - v1.vy;
        var distance:Number = calcDistance();
        var invDistance:Number = 1 / distance;
        dx *= invDistance;
        dy *= invDistance;
        var k:Number = (distance - targetDistance) * 0.5;
        var dot:Number = (dx * rx + dy * ry) * 0.125;
        dx *= k + dot;
        dy *= k + dot;
        v1.vx += dx;
        v1.vy += dy;
        v2.vx -= dx;
        v2.vy -= dy;
    }

    public function calcDistance():Number {
        const dx:Number = v2.x - v1.x;
        const dy:Number = v2.y - v1.y;
        return Math.sqrt(dx * dx + dy * dy);
    }
}

class Vertex {
    public var x:Number;
    public var y:Number;
    public var vx:Number;
    public var vy:Number;
    public var nx:Number; // 頂点法線ベクトル
    public var ny:Number;
    public var color:uint;
    public function Vertex(x:Number, y:Number) {
        this.x = x;
        this.y = y;
        vx = vy = 0;
        nx = ny = 0;
    }
    
    public function move():void {
        color = (Math.random() * 96 + 160) << 16 | (Math.random() * 96 + 160) << 8 | (Math.random() * 96 + 160);
        x += vx;
        y += vy;
        if(x < 10) vx += 10 - x;
        if(x > 455) vx += 455 - x;
        if(y < 10) vy += 10 - y;
        if(y > 455) vy += 455 - y;
        vx *= 0.95; // damping
        vy *= 0.95;
    }
}