Решил продолжить тему потрясающе простой и красивой флешки Pulsate, после того как AViktorov сделал её клон на Lua.
Идея данной флешки заключается в следующем: при клике мышкой на поле происходит добавление нового круга. Радиус круга начинает плавно увеличиваться, до столкновения с другим кругом. После столкновении происходит воспроизведение звукового сигнала в соответствии с радиусами кругов и радиусы обеих кругов начинают уменьшаться, до того пока не станут равны нулю или же круги не столкнутся с другими кругами. Таким образом можно сказать, что после столкновения радиусы кругов меняют способ роста на противоположный.
Математика для расчёта столкновений двух кругов подразумевает два варианта.
Первый — когда происходит внешнее столкновение двух кругов, и второй — при котором один круг находится внутри другого, то есть происходит внутреннее столкновение.
В первом варианте определить столкновение можно узнав расстояние d между центрами кругов и проверив является ли сумма радиуса большего круга R и радиуса меньшего круга r больше или равной расстояния d. То есть при столкновении L = 0.
Во втором варианте для того чтобы определить столкновение необходим предпринять следующее. Определив расстояние между центрами кругов d, и зная радиусы обеих кругов, нужно проверить является ли сумма d и r больше или равной R. В случае столкновения L = 0.
В ходе экспериментов задав интервалы радиусов и соответствующие им ноты, получаются очень атмосферные мелодии.
Исходный код основных методов столкновений представлен ниже:
Идея данной флешки заключается в следующем: при клике мышкой на поле происходит добавление нового круга. Радиус круга начинает плавно увеличиваться, до столкновения с другим кругом. После столкновении происходит воспроизведение звукового сигнала в соответствии с радиусами кругов и радиусы обеих кругов начинают уменьшаться, до того пока не станут равны нулю или же круги не столкнутся с другими кругами. Таким образом можно сказать, что после столкновения радиусы кругов меняют способ роста на противоположный.
Математика для расчёта столкновений двух кругов подразумевает два варианта.
Первый — когда происходит внешнее столкновение двух кругов, и второй — при котором один круг находится внутри другого, то есть происходит внутреннее столкновение.
В первом варианте определить столкновение можно узнав расстояние d между центрами кругов и проверив является ли сумма радиуса большего круга R и радиуса меньшего круга r больше или равной расстояния d. То есть при столкновении L = 0.
Для того чтобы определить находится ли один круг находится внутри другого 
нужно определить больший из двух кругов по радиусу и затем проверить 
меньше ли расстояние d между центрами кругов, чем радиус большего круга R. Если d < R, то один круг находится внутри другого.
Во втором варианте для того чтобы определить столкновение необходим предпринять следующее. Определив расстояние между центрами кругов d, и зная радиусы обеих кругов, нужно проверить является ли сумма d и r больше или равной R. В случае столкновения L = 0.
В ходе экспериментов задав интервалы радиусов и соответствующие им ноты, получаются очень атмосферные мелодии.
Добавив линии соединяющие центры всех кругов получается такой вот красивый рисунок:
Исходный код основных методов столкновений представлен ниже:
struct Circle {
    Circle(int x, int y) : x(x), y(y), radius(0), color(D3DCOLOR_RGBA(0,155,225,255)), is_grow(true) { }
    int x;
    int y;
    float radius;
    int color;
    bool is_grow;
};
const int MAX_CIRCLES_NUM = 32;
std::vector circles;
//-----------------------------------------------------------------------------
// Checks circles for intersection and update its sizes
//-----------------------------------------------------------------------------
void updateCircles() {
    for (int i = 0; i < circles.size(); i++) {
        for (int j = 0; j < circles.size(); j++) {
            // prevent checking with self
            if (i == j) continue; 
            // get the squared distances between centers of circles
            float
 distance_squared = (circles[i].x - circles[j].x) * (circles[i].x - 
circles[j].x) + (circles[i].y - circles[j].y) * (circles[i].y - 
circles[j].y);   
            // get radiuses and distance
            float max_radius = max(circles[i].radius, circles[j].radius);
            float min_radius = min(circles[i].radius, circles[j].radius);
            float distance = sqrt(distance_squared);
            float radius =  circles[i].radius + circles[j].radius;
            // circle inside another circle
            if (max_radius >= distance) {
                if (max_radius - (distance + min_radius) <= 0) {
                    // prevent overgrow
                    if (circles[i].radius > circles[j].radius) {
                        circles[i].radius = max_radius;
                        circles[j].radius = max_radius - distance;
                    }
                    circles[i].is_grow = !circles[i].is_grow;
                    circles[j].is_grow = !circles[j].is_grow;                               
           
                    playIntersectionSound(max_radius);
                }           
            } else {               
                // circles outside
                if (distance - radius <= 0) {
                    circles[i].is_grow = false;
                    circles[j].is_grow = false;
                    playIntersectionSound(max_radius);
                }
            }
        }
        // update circles
        if (circles[i].is_grow) {
            circles[i].radius += grow_speed;
        } else {
            circles[i].radius -= grow_speed;
        }
        if (circles[i].radius <= 0) {
            circles[i].radius = 0;
            circles[i].is_grow = true;
        }
    }
}
//-----------------------------------------------------------------------------
// Update Game
//-----------------------------------------------------------------------------
void updateGame() {     // add one more circle
    if (mouse_lbutton_clicked) {
        if (circles.size() < MAX_CIRCLES_NUM) {
            circles.push_back(Circle(mouse_lbutton_down.x,mouse_lbutton_down.y));
        }
    }
    // crear circles
    if (rbutton_clicked) {
        circles.clear();
    }
    // draw circles
    for (int i = 0; i < circles.size(); i++) {
        primitive->setPenColor(circles[i].color);
        primitive->drawCircle(circles[i].x,circles[i].y,circles[i].radius,50); // 50 sections
    }
    // check for intersections and update circles sizes
    updateCircles();
} 
* This source code was highlighted with Source Code Highlighter.





No comments:
Post a Comment