↑ Return to Javascript

Physics Synthesizer

このエントリーを含むはてなブックマークはてなブックマーク - Physics Synthesizer Googleブックマークに追加 このエントリをつぶやくこのWebページのtweets

Web Creator’s Contest Q the 2nd Vol.3 GOLD受賞作品

これのJavaScriptバージョン
クリックでボール出現
右クリックでボール全消し

var ctx;
var balls = [], fixedBalls = [], effectCircles = [];
var BALL = 16, R = 3, W=465, H=465;
var colorAry = [16711680,16712704,16713728,16715008,16716032,16717056,16718080,16719360,16720384,16721408,16722432,16723712,16724736,16725760,16727040,16728064,16729088,16730112,16731392,16732416,16733440,16734464,16735744,16736768,16737792,16738816,16740096,16741120,16742144,16743168,16744448,16745472,16746496,16747520,16748800,16749824,16750848,16751872,16753152,16754176,16755200,16756224,16757504,16758528,16759552,16760576,16761856,16762880,16763904,16764928,16766208,16767232,16768256,16769280,16770560,16771584,16772608,16773632,16774912,16775936,16776960,16514816,16187136,15924992,15662848,15400704,15073024,14810880,14548736,14286592,13958912,13696768,13434624,13172480,12844800,12582656,12320512,12058368,11796224,11468544,11206400,10944256,10682112,10354432,10092288,9830144,9568000,9240320,8978176,8716032,8453888,8126208,7864064,7601920,7339776,7012096,6749952,6487808,6225664,5897984,5635840,5373696,5111552,4783872,4521728,4259584,3997440,3669760,3407616,3145472,2883328,2555648,2293504,2031360,1769216,1441536,1179392,917248,655104,327424,65280,65284,65288,65293,65297,65301,65306,65310,65314,65318,65322,65327,65331,65335,65340,65344,65348,65352,65356,65361,65365,65369,65374,65378,65382,65386,65390,65395,65399,65403,65408,65412,65416,65420,65425,65429,65433,65437,65442,65446,65450,65454,65459,65463,65467,65471,65475,65480,65484,65488,65493,65497,65501,65505,65509,65514,65518,65522,65527,65531,65535,64511,63487,62207,61183,60159,58879,57855,56831,55807,54783,53503,52479,51455,50175,49151,48127,47103,46079,44799,43775,42751,41727,40447,39423,38399,37375,36095,35071,34047,33023,31743,30719,29695,28415,27391,26367,25343,24319,23039,22015,20991,19711,18687,17663,16639,15615,14335,13311,12287,11007,9983,8959,7935,6911,5631,4607,3583,2303,1279,255,262399,524543,852223,1114367,1376511,1638655,1966335,2228479,2490623,2818303,3080447,3342591,3604735,3932415,4194559,4456703,4718847,4980991,5308671,5570815,5832959,6095103,6422783,6684927,6947071,7274751,7536895,7799039,8061183,8388863,8651007,8913151,9175295,9437439,9765119,10027263,10289407,10617087,10879231,11141375,11403519,11731199,11993343,12255487,12517631,12779775,13107455,13369599,13631743,13893887,14221567,14483711,14745855,15073535,15335679,15597823,15859967,16187647,16449791,16711935,16711931,16711927,16711922,16711918,16711914,16711910,16711905,16711901,16711897,16711892,16711888,16711884,16711880,16711875,16711871,16711867,16711863,16711859,16711854,16711850,16711846,16711842,16711837,16711833,16711829,16711824,16711820,16711816,16711812,16711808,16711803,16711799,16711795,16711791,16711786,16711782,16711778,16711773,16711769,16711765,16711761,16711756,16711752,16711748,16711744,16711740,16711735,16711731,16711727,16711723,16711718,16711714,16711710,16711705,16711701,16711697,16711693,16711688,16711684];

var sounds = [];

var world;
var stage;
var beatCount = 0;

function init(){
    var canvas = document.getElementById("canvas");
    ctx = canvas.getContext("2d");
    canvas.addEventListener("click", click);
    canvas.addEventListener("contextmenu", function(e){e.preventDefault(); clear();});
    ctx.globalCompositeOperation = "source-over";

    stage = new createjs.Stage(canvas);

    world = createWorld();

    for(var i = 0; i < 16; i++){
        sounds[i] = [];
        for(var j = 0; j < 3; j++){
            sounds[i][j] = j$("audio.a"+ (i+1).toString()+":eq("+ j.toString()+")").get(0);
        }
    }

    for(var i = 0; i < BALL; i++){
        for(var j = 0; j < BALL; j++){
            //固定ボールの生成
            var xx = (i+0.5*j+0.25)*W/BALL, yy = (j+0.25)*H/BALL;
            if(xx > W) xx=xx-W;
            var ball = createFixedBall(world, xx, yy, R), color = colorAry[Math.floor(360/BALL)*j];
            var r = (color >> 16) & 0xFF, g = (color >> 8) & 0xFF, b = color & 0xFF;
            fixedBalls.push(ball);
            //描画
            var shape = new createjs.Shape();
            shape.graphics.beginRadialGradientFill(["rgba(" + r.toString() + ", " + g.toString() + ", " + b.toString() + ", 0.5)", "rgba(" + r.toString() + ", " + g.toString() + ", " + b.toString() + ", 0)"], [0.3, 1], 0, 0, 0, 0, 0, R*5).drawCircle(0, 0, R*5).endFill()
            shape.graphics.setStrokeStyle(3).beginStroke("rgba(255,255,255,1)").drawCircle(0,0,R).endStroke();
            stage.addChild(shape);
            shape.x = xx;
            shape.y = yy;
            shape.alpha = 0.5;
            shape.cache(-R*5, -R*5, R*10, R*10);
            ball.shape = shape;
            shape.type = "fixed";
            shape.on = false;
            shape.color = {r:r, g:g, b:b};

            //衝突エフェクトに使用するShapeの生成
            var eshape = new createjs.Shape();
            eshape.graphics.setStrokeStyle(2).beginStroke("rgb(" + r.toString() + ", " + g.toString() + ", " + b.toString()+")").drawCircle(0,0,15).endStroke();
            var filter = new createjs.BoxBlurFilter(1,1,1);
            eshape.filters = [filter];
            var margins = filter.getBounds();
            eshape.cache(-15+margins.x-7, -15+margins.y-7, 15*2+margins.width+14, 15*2+margins.height+14);
            stage.addChild(eshape);
            eshape.visible = false;
            eshape.x = xx;
            eshape.y = yy;

            shape.effectShape = eshape;
            shape.sound = j;
        }
    }
    stage.update();
    onEnterFrame();
    beat();
}

function onEnterFrame(){
    world.Step(1/30, 1);

    ctx.fillStyle = "rgb(0, 0, 0)";
    ctx.fillRect(0, 0, W, H);
    
    var n = balls.length;
    for(var i = 0; i < n; i++){
        var ball = balls[i];
        //位置の更新
        ball.shape.x = ball.m_position.x;
        ball.shape.y = ball.m_position.y;
        //画面外に出たら反対側へ
        if(ball.m_position.x > W+10) ball.m_position.x = -10;
        else if(ball.m_position.x < -10) ball.m_position.x = W+10;
        if(ball.m_position.y > H+10) ball.m_position.y = -10;
        else if(ball.m_position.y < -10) ball.m_position.y = H+10;

        //衝突判定
        var contactObj = ball.GetContactList();
        if(contactObj){
            var v = ball.GetLinearVelocity();
            if(contactObj.other.shape.type == "fixed") changeSwitch(contactObj.other.shape)
        }
    }
    stage.update();
    setTimeout(onEnterFrame, 1/30);
}

//音を鳴らす
function beat(){
    var a = Math.floor(Math.random()*2);
    for(var i = beatCount*BALL+1+a; i < (beatCount+1)*BALL; i+=2){
        if(fixedBalls[i].shape.on == true){
            var id = fixedBalls[i].shape.sound;
            for(var j = 0; j < 3; j++){
                if(sounds[id][j].ended || sounds[id][j].currentTime == 0){
                    sounds[id][j].currentTime = 0;
                    sounds[id][j].play();
                    break;
                }
            }
            createjs.Tween.get(fixedBalls[i].shape).to({scaleX:2, scaleY:2}, 250, createjs.Ease.sineOut).to({scaleX:1, scaleY:1}, 250, createjs.Ease.sineIn);
        }
    }
    beatCount=(beatCount+1)%BALL;
    setTimeout(beat, 150);
}

//固定オブジェクトのOn, Off切り替え
function changeSwitch(shape){
    if(shape.effectShape.visible == false){
        if(shape.on){
            shape.on = false;
            shape.alpha = 0.5;
        }
        else{
            shape.on = true;
            shape.alpha = 1.0;
        }
        effectStart(shape.effectShape);
    }
}

//波紋エフェクト
function effectStart(shape){
    shape.alpha = 1;
    shape.visible = true;
    shape.scaleX = shape.scaleY = 0;
    createjs.Tween.get(shape).to({alpha:0, scaleX:2, scaleY:2}, 500).call(onComp, [shape]);
}

function onComp(shape){
    shape.visible = false;
}

//固定オブジェクトの生成
function createFixedBall(world, x, y, r) {
    var ballSd = new b2CircleDef();
    ballSd.radius = r;
    ballSd.friction = 0;
    var ballBd = new b2BodyDef();
    ballBd.AddShape(ballSd);
    ballBd.position.Set(x,y);
    return world.CreateBody(ballBd);
}

//動くボールの生成
function createBall(world, x, y, r){
    var ballSd = new b2CircleDef();
    ballSd.radius = r;
    ballSd.density = 1.0;
    ballSd.friction = 0;
    var ballBd = new b2BodyDef();
    ballBd.AddShape(ballSd);
    ballBd.position.Set(x,y);
    return world.CreateBody(ballBd);
}

function createWorld() {
    var worldAABB = new b2AABB();
    worldAABB.minVertex.Set(-1000, -1000);
    worldAABB.maxVertex.Set(1000, 1000);
    var gravity = new b2Vec2(0, 25);
    var doSleep = true;
    var world = new b2World(worldAABB, gravity, doSleep);
    return world;
}

//ボールを消す
function clear(){
    for(var i = 0; i < balls.length; i++){
        world.DestroyBody(balls[i]);
        stage.removeChild(balls[i].shape);
    }
    balls = [];
}

function click(e){
    var shape = new createjs.Shape();
    shape.graphics.beginRadialGradientFill(["rgba(255,255,255,0.5)", "rgba(255,255,255,0)"], [0.3, 1], 0, 0, 0, 0, 0, R*5).drawCircle(0, 0, R*5).endFill();
    shape.graphics.setStrokeStyle(3).beginStroke("rgba(255,255,255,1)").drawCircle(0,0,R).endStroke();
    stage.addChild(shape);
    shape.x = e.clientX;
    shape.y = e.clientY;
    shape.cache(-R*5, -R*5, R*10, R*10);
    shape.type = "ball";
    var ball = createBall(world, e.clientX, e.clientY, R+2);
    ball.shape = shape;
    balls.push(ball);
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次の HTMLタグおよび属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>