2021-12-11 21:32:48 +01:00
|
|
|
#include "gravity.h"
|
2023-05-17 13:25:36 +02:00
|
|
|
|
2021-12-11 21:32:48 +01:00
|
|
|
#include "game.h"
|
2023-05-17 13:27:11 +02:00
|
|
|
#include "polygons.h"
|
2021-12-11 21:32:48 +01:00
|
|
|
|
2023-05-17 13:25:36 +02:00
|
|
|
#include <cmath>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <sstream>
|
|
|
|
#include <string>
|
|
|
|
|
2022-12-28 18:50:12 +01:00
|
|
|
static const double constant_field_increment = 1.0;
|
|
|
|
static const double newton_field_increment = 1000.0;
|
2021-12-12 00:36:07 +01:00
|
|
|
|
2022-12-28 18:50:12 +01:00
|
|
|
static vec2d g{.x = 0, .y = 20};
|
2021-12-12 00:36:07 +01:00
|
|
|
static double g_r = 50;
|
|
|
|
static double g_g = 10000000;
|
|
|
|
|
|
|
|
static int constant_field = 1;
|
2021-12-11 21:32:48 +01:00
|
|
|
|
2023-05-17 13:25:36 +02:00
|
|
|
void gravity_constant_field(double x, double y) {
|
2021-12-12 00:36:07 +01:00
|
|
|
constant_field = 1;
|
2022-06-01 11:09:35 +02:00
|
|
|
g.x = x;
|
|
|
|
g.y = y;
|
2021-12-12 00:36:07 +01:00
|
|
|
}
|
2021-12-12 11:54:43 +01:00
|
|
|
|
2023-05-17 13:25:36 +02:00
|
|
|
void gravity_newton_field(double r, double g) {
|
2021-12-12 00:36:07 +01:00
|
|
|
constant_field = 0;
|
|
|
|
g_r = r;
|
|
|
|
g_g = g;
|
|
|
|
}
|
|
|
|
|
2023-05-17 13:25:36 +02:00
|
|
|
void gravity_draw(cairo_t* cr) {
|
2021-12-12 00:36:07 +01:00
|
|
|
if (constant_field) {
|
2023-05-17 13:25:36 +02:00
|
|
|
cairo_save(cr);
|
|
|
|
cairo_new_path(cr);
|
|
|
|
cairo_move_to(cr, width / 2, height / 2);
|
|
|
|
cairo_line_to(cr, width / 2 + g.x, height / 2 + g.y);
|
|
|
|
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
|
|
|
cairo_set_line_width(cr, 1.0);
|
|
|
|
cairo_stroke(cr);
|
|
|
|
cairo_arc(cr, width / 2 + g.x, height / 2 + g.y, 3, 0, 2 * M_PI);
|
|
|
|
cairo_fill(cr);
|
|
|
|
cairo_restore(cr);
|
2022-12-28 18:50:12 +01:00
|
|
|
} else {
|
2023-05-17 13:25:36 +02:00
|
|
|
std::ostringstream output;
|
|
|
|
output << (g_g / 1000) << "K";
|
|
|
|
cairo_save(cr);
|
|
|
|
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
|
|
|
cairo_select_font_face(cr,
|
|
|
|
"sans-serif",
|
|
|
|
CAIRO_FONT_SLANT_NORMAL,
|
|
|
|
CAIRO_FONT_WEIGHT_NORMAL);
|
|
|
|
cairo_set_font_size(cr, 16);
|
|
|
|
std::string output_str = output.str();
|
|
|
|
cairo_text_extents_t extent;
|
|
|
|
cairo_text_extents(cr, output_str.c_str(), &extent);
|
|
|
|
cairo_move_to(
|
|
|
|
cr, width / 2 - extent.width / 2, height / 2 + extent.height / 2);
|
|
|
|
cairo_show_text(cr, output_str.c_str());
|
|
|
|
cairo_restore(cr);
|
2022-12-28 18:50:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-17 13:25:36 +02:00
|
|
|
void gravity_draw_visible_field(cairo_t* cr) {
|
2022-12-28 18:50:12 +01:00
|
|
|
if (!constant_field) {
|
2023-05-17 13:25:36 +02:00
|
|
|
cairo_save(cr);
|
|
|
|
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
|
|
|
cairo_new_path(cr);
|
|
|
|
cairo_arc(cr, width / 2, height / 2, g_r, 0, 2 * M_PI);
|
|
|
|
cairo_set_line_width(cr, 3.0);
|
|
|
|
cairo_stroke(cr);
|
|
|
|
cairo_restore(cr);
|
2021-12-11 21:32:48 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-17 13:25:36 +02:00
|
|
|
void gravity_change(double dx, double dy) {
|
2021-12-12 00:36:07 +01:00
|
|
|
if (constant_field) {
|
2023-05-17 13:25:36 +02:00
|
|
|
g.x += dx * constant_field_increment;
|
|
|
|
g.y += dy * constant_field_increment;
|
2021-12-12 00:36:07 +01:00
|
|
|
} else {
|
2023-05-17 13:25:36 +02:00
|
|
|
g_r += dx;
|
|
|
|
g_g -= dy * newton_field_increment;
|
2021-12-12 00:36:07 +01:00
|
|
|
}
|
2023-05-17 13:27:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
vec2d gravity_vector(const polygon* p) {
|
|
|
|
if (constant_field) {
|
|
|
|
return g;
|
|
|
|
} else {
|
|
|
|
vec2d b_c = vec2d{width / 2.0, height / 2.0} - p->centroid();
|
|
|
|
double r2 = vec2d::dot(b_c, b_c);
|
|
|
|
if (r2 < g_r * g_r)
|
|
|
|
return vec2d{0, 0};
|
|
|
|
else
|
|
|
|
return g_g / r2 / sqrt(r2) * b_c;
|
|
|
|
}
|
2021-12-12 00:36:07 +01:00
|
|
|
}
|
2021-12-11 21:32:48 +01:00
|
|
|
|
2023-05-17 13:25:36 +02:00
|
|
|
vec2d gravity_vector(const ball* b) {
|
2021-12-12 00:36:07 +01:00
|
|
|
if (constant_field) {
|
2023-05-17 13:25:36 +02:00
|
|
|
return g;
|
2021-12-12 00:36:07 +01:00
|
|
|
} else {
|
2023-05-17 13:25:36 +02:00
|
|
|
vec2d b_c = vec2d{width / 2.0, height / 2.0} - b->position;
|
|
|
|
double r2 = vec2d::dot(b_c, b_c);
|
|
|
|
if (r2 < g_r * g_r)
|
|
|
|
return vec2d{0, 0};
|
|
|
|
else
|
|
|
|
return g_g / r2 / sqrt(r2) * b_c;
|
2021-12-12 00:36:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-17 13:25:36 +02:00
|
|
|
void gravity_collisions(ball* begin, ball* end) {
|
2021-12-12 00:36:07 +01:00
|
|
|
if (constant_field)
|
2023-05-17 13:25:36 +02:00
|
|
|
return;
|
|
|
|
for (ball* b = begin; b != end; ++b) {
|
|
|
|
vec2d b_c = b->position - vec2d{width / 2.0, height / 2.0};
|
|
|
|
double d2 = vec2d::dot(b_c, b_c);
|
|
|
|
double r = b->radius + g_r;
|
|
|
|
if (d2 <= r * r) {
|
|
|
|
double d = sqrt(d2);
|
|
|
|
if (d <= b->radius)
|
|
|
|
b->position = vec2d{width / 2.0, height / 2.0 + r};
|
|
|
|
else
|
|
|
|
b->position += (r - d) / d * b_c;
|
|
|
|
double f = vec2d::dot(b->velocity, b_c);
|
|
|
|
if (f < 0) {
|
|
|
|
f /= d2;
|
|
|
|
b->velocity -= 2 * f * b_c;
|
|
|
|
}
|
|
|
|
}
|
2021-12-12 00:36:07 +01:00
|
|
|
}
|
|
|
|
}
|