Решил продолжить тему потрясающе простой и красивой флешки 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