Анимированные частицы в форме (холст + кинетика)

Я использую KineticJS для выполнения волнового движения внутри фигуры.

Теперь я бы вставил в свои волны частицы, которые тоже движутся.

В настоящее время я делаю это: (JSFiddle)

введите описание изображения здесь

window.requestAnimFrame = (function() {
    return  window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function(callback) {
            window.setTimeout(callback, 1000 / 60);
        };
})();

// Wave functions

var w = 205;
var h = 100;

var osc1 = new osc(),
    osc2 = new osc(),
    osc3 = new osc(),
    horizon = h * 0.5;
count = 40,
    step = Math.ceil(w / count),
        buffer = new ArrayBuffer(count * 4),
            points = new Float32Array(buffer);

osc1.max = 20;

osc2.max = 20;
osc2.speed = 0.015;

function fill() {
    for(var i = 0; i < count; i++) {
        points[i] = mixer(osc1, osc2, osc3);
    }
}

fill();

function osc() {
    this.variation = 0.1;
    this.max = 30;
    this.speed = 0.030;
    var me = this,
        a = 0,
        max = getMax();
    this.getAmp = function() {
        a += this.speed;
        if (a >= 2.0) {
            a = 0;
            max = getMax();
        }
        return max * Math.sin(a * Math.PI);
    };
    function getMax() {
        return Math.random() * me.max * me.variation +
            me.max * (1 - me.variation);
    }
    return this;    
}

function mixer() {
    var d = arguments.length,
        i = d,
        sum = 0;
    if (d < 1) return 0;
    while(i--) sum += arguments[i].getAmp();
    return sum / d + horizon;
}

// End wave functions

// Particles functions

var inWave = [];
var particlesInWave = 15;
var cw = 200;
var ch = 200;

function createParticlesInWave() {
    for (var i = 0; i < particlesInWave; i++)
        inWave.push(new inParticle());
}

function updateParticlesInWave() {

    for (var i = 0; i < inWave.length - 1; i++) {
        inWave[i].x -= inWave[i].vx;
        inWave[i].y += inWave[i].vy;
        if (inWave[i].x > cw)
            inWave[i].x = 0;
        if (inWave[i].x < 0)
            inWave[i].x = cw;
        if (inWave[i].y < 0)
            inWave[i].y = ch;

        switch (inWave[i].oSwitch) {
            case true:
                inWave[i].opacity += 0.01;
                if (inWave[i].opacity >= 1)
                    inWave[i].oSwitch = false;
                break;

            case false:
                inWave[i].opacity -= 0.01;
                if (inWave[i].opacity <= 0)
                    inWave[i].oSwitch = true;
                break;
            default:
                break;
        }
    }
}

var inParticle = function() {
    this.x = Math.random() * cw;
    this.y = Math.random() * ch;
    this.radius = Math.random() * 2;
    this.vx = -2 + Math.random() * 4;
    this.vy = -4 + Math.random() * 2;
    this.opacity = Math.random();
    this.oSwitch = true;
};

function renderParticlesInWave() {
    for (var i = 0; i < inWave.length - 1; i++) {
        tp = inWave[i];
        if (inWave[i].y > 0 && inWave[i] != NaN || !inWave[i])
        {
            ctx.beginPath();
            ctx.fillStyle = 'blue';
            ctx.arc(tp.x, tp.y, tp.radius, 0, Math.PI * 2, false);
            ctx.fill();
            ctx.closePath();
        }
        ctx.restore();
    }

}

// End particles functions

var stage = new Kinetic.Stage({
    container: "myCanvas",
    width: 200,
    height: 200
});

var layer = new Kinetic.Layer();
var ctx = layer.getContext();

stage.add(layer);

var rect = new Kinetic.Rect({
    height: 200,
    width: 200,
    stroke: "#4679BD",
    fill: "#fff",
    strokeWidth: 3,
});

var wave = new Kinetic.Shape({
    drawFunc: function(context){
        context.clip();
        context.beginPath();
        context.moveTo(0, points[0]);
        for(i = 1; i < count; i++) {
            context.lineTo(i * step, points[i]);
        }
        context.lineTo(w, h);
        context.lineTo(0, h);
        context.closePath();
        context.fillStrokeShape(this);
        context.restore();
    },
    fill: "#4679BD",
    y: 50
});

layer.add(rect);
layer.add(wave);

stage.add(layer);

createParticlesInWave();

var anim = new Kinetic.Animation(function(frame) {

    updateParticlesInWave();
    var i;
    for(i = 0; i < count - 1; i++) {
        points[i] = points[i + 1];
    }
    points[count - 1] = mixer(osc1, osc2, osc3);
    wave.setDrawFunc(function(context) {
        context.clip();
        context.beginPath();
        context.moveTo(0, points[0]);
        for(i = 1; i < count; i++) {
            context.lineTo(i * step, points[i]);
        }
        context.lineTo(200, 200);
        context.lineTo(0, 200);
        context.closePath();
        context.fillStrokeShape(this);
        context.restore();
    });

}, layer);

function loop() {
    renderParticlesInWave();
    requestAnimFrame( loop );
}

anim.start();   
loop();

Как я могу заставить частицы двигаться только в моей волне?

Спасибо большое за вашу помощь :)


person Antoine    schedule 08.11.2013    source источник
comment
Это тебе не поможет, но это так здорово! Я только что открыл для себя эту библиотеку!   -  person Romain Braun    schedule 08.11.2013


Ответы (1)


Для этого вам нужно проверить, касается ли пузырь воды, когда поднимается вверх.

        if (y < 50 + points[0 | (x / step)]) thisPart.y = ch;

http://jsfiddle.net/gamealchemist/2Y8KU/1/

function updateParticlesInWave() {
    var thisPart = null;
    for (var i = 0; i < inWave.length - 1; i++) {
        thisPart = inWave[i];
        thisPart.x -= thisPart.vx;
        thisPart.y += thisPart.vy;

        var x = thisPart.x,
            y = thisPart.y;

        if (y < 50 + points[0 | (x / step)]) thisPart.y = ch;

        if (x > cw) thisPart.x = 0;
        else if (x < 0) thisPart.x = cw;
        if (y < 0) thisPart.y = ch;

        if (thisPart.oSwitch) {
            thisPart.opacity += 0.01;
            if (thisPart.opacity >= 1) thisPart.oSwitch = false;
        } else {
            thisPart.opacity -= 0.01;
            if (thisPart.opacity <= 0) thisPart.oSwitch = true;
        }
    }
}

Для перформансов: 1) да, постарайтесь избегать использования как animationFrame, так и анимации Kinetics: установите пузыри в качестве другого слоя, и все это сделает Kinetics. 2) вы переопределяете renderParticlesInWave () каждый тик, что плохо для производительности: попробуйте определить его чистым раз и навсегда.

дайте мне знать, когда вы это сделали, и я буду следить за выступлениями.

я рисую функцию волны:

: context.lineTo (ш, 2 * ч); context.lineTo (0, 2 * h);

так что вам не нужно снова и снова устанавливать его в анимации.

ускорить также при рисовании пузырей: цвет не установлен. непрозрачность кажется неэффективной (?)

Вы забыли сохранить контекст перед обрезкой.

и некоторые ускоряются то тут, то там.

http://jsfiddle.net/gamealchemist/2Y8KU/5/

person GameAlchemist    schedule 08.11.2013
comment
Спасибо большое, это здорово! Поскольку против моей анимации немного запаздывает, я думаю, что наличие анимации KineticJS и другого requestAnimFrame есть что-то, что вы думаете? Я хотел поместить все в свою анимацию KineticJS, но не смог отобразить свои частицы ... В своих настройках я указываю частицы, которые я хочу, чтобы они были белыми, но они черные, вы знаете, где это может появиться? Еще раз спасибо за вашу помощь! - person Antoine; 08.11.2013
comment
Спасибо за ваши предложения :) Мне удалось разместить частицы в слое и изменить их цвета. Для производительности я всегда падаю FPS даже с анимацией Kinetic, как это улучшить? jsfiddle.net/2Y8KU/4 - person Antoine; 08.11.2013