Merge branch 'inelastic-collisions' into c++-port
This commit is contained in:
commit
6078f57647
111
balls.cc
111
balls.cc
@ -18,6 +18,55 @@ unsigned int v_angle_max = 100;
|
||||
ball * balls = nullptr;
|
||||
unsigned int n_balls = 50;
|
||||
|
||||
// Coefficient of restitution:
|
||||
// C_r == 1.0 ==> perfectly elastic collisions
|
||||
// C_r == 0.0 ==> perfectly inelastic collisions
|
||||
//
|
||||
static double C_r = 1.0;
|
||||
static int c_r_display_countdown = 0;
|
||||
static int c_r_display_init = 300;
|
||||
|
||||
void restitution_coefficient_set (double c) {
|
||||
C_r = c;
|
||||
if (C_r > 1.0)
|
||||
C_r = 1.0;
|
||||
else if (C_r < 0.0)
|
||||
C_r = 0.0;
|
||||
}
|
||||
|
||||
double restitution_coefficient_get () {
|
||||
return C_r;
|
||||
}
|
||||
|
||||
void restitution_coefficient_change (double d) {
|
||||
C_r += d;
|
||||
if (C_r > 1.0)
|
||||
C_r = 1.0;
|
||||
else if (C_r < 0.0)
|
||||
C_r = 0.0;
|
||||
restitution_coefficient_show ();
|
||||
}
|
||||
|
||||
void restitution_coefficient_show () {
|
||||
c_r_display_countdown = c_r_display_init;
|
||||
};
|
||||
|
||||
void restitution_coefficient_draw (cairo_t * cr) {
|
||||
static const double margin = 20;
|
||||
if (c_r_display_countdown != 0) {
|
||||
cairo_save(cr);
|
||||
cairo_new_path(cr);
|
||||
cairo_move_to(cr, margin, margin);
|
||||
cairo_line_to(cr, margin + (width - 2*margin)*C_r, margin);
|
||||
cairo_set_source_rgb(cr, 1.0, 1.0, 0.0);
|
||||
cairo_set_line_width(cr, margin/2);
|
||||
cairo_stroke(cr);
|
||||
if (c_r_display_countdown > 0)
|
||||
--c_r_display_countdown;
|
||||
cairo_restore(cr);
|
||||
}
|
||||
}
|
||||
|
||||
static vec2d random_velocity() {
|
||||
double r2;
|
||||
vec2d v;
|
||||
@ -49,43 +98,45 @@ void balls_init_state () {
|
||||
}
|
||||
}
|
||||
|
||||
void ball_walls_collision (ball * p) {
|
||||
if (p->position.x + p->radius > width) { /* right wall */
|
||||
if (p->velocity.x > 0) {
|
||||
p->position.x -= p->position.x + p->radius - width;
|
||||
p->velocity.x = -C_r*p->velocity.x;
|
||||
}
|
||||
} else if (p->position.x < p->radius) { /* left wall */
|
||||
if (p->velocity.x < 0) {
|
||||
p->position.x += p->radius - p->position.x;
|
||||
p->velocity.x = -C_r*p->velocity.x;
|
||||
}
|
||||
}
|
||||
if (p->position.y + p->radius > height) { /* bottom wall */
|
||||
if (p->velocity.y > 0) {
|
||||
p->position.y -= p->position.y + p->radius - height;
|
||||
p->velocity.y = -C_r*p->velocity.y;
|
||||
}
|
||||
} else if (p->position.y < p->radius) { /* top wall */
|
||||
if (p->velocity.y < 0) {
|
||||
p->position.y += p->radius - p->position.y;
|
||||
p->velocity.y = -C_r*p->velocity.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ball_update_state (ball * p) {
|
||||
vec2d g = gravity_vector (p);
|
||||
|
||||
p->position += delta*p->velocity + delta*delta*g/2.0;
|
||||
p->velocity += delta*g;
|
||||
|
||||
if (p->position.x + p->radius > width) { /* right wall */
|
||||
if (p->velocity.x > 0) {
|
||||
p->position.x -= p->position.x + p->radius - width;
|
||||
p->velocity.x = -p->velocity.x;
|
||||
}
|
||||
} else if (p->position.x < p->radius) { /* left wall */
|
||||
if (p->velocity.x < 0) {
|
||||
p->position.x += p->radius - p->position.x;
|
||||
p->velocity.x = -p->velocity.x;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->position.y + p->radius > height) { /* bottom wall */
|
||||
if (p->velocity.y > 0) {
|
||||
p->position.y -= p->position.y + p->radius - height;
|
||||
p->velocity.y = -p->velocity.y;
|
||||
}
|
||||
} else if (p->position.y < p->radius) { /* top wall */
|
||||
if (p->velocity.y < 0) {
|
||||
p->position.y += p->radius - p->position.y;
|
||||
p->velocity.y = -p->velocity.y;
|
||||
}
|
||||
}
|
||||
p->angle += delta*p->v_angle;
|
||||
while (p->angle >= 2*M_PI)
|
||||
p->angle -= 2*M_PI;
|
||||
while (p->angle < 0)
|
||||
p->angle += 2*M_PI;
|
||||
ball_walls_collision (p);
|
||||
}
|
||||
|
||||
void ball_elastic_collision (ball * p, ball * q) {
|
||||
void ball_ball_collision (ball * p, ball * q) {
|
||||
vec2d pq = q->position - p->position;
|
||||
double d2 = vec2d::dot(pq,pq);
|
||||
double r = p->radius + q->radius;
|
||||
@ -94,13 +145,19 @@ void ball_elastic_collision (ball * p, ball * q) {
|
||||
|
||||
double mp = p->radius * p->radius;
|
||||
double mq = q->radius * q->radius;
|
||||
double m_total = mp + mp;
|
||||
|
||||
double d = sqrt(d2);
|
||||
vec2d pq_overlap = (r - d)/d*pq;
|
||||
p->position -= pq_overlap*mq/m_total;
|
||||
q->position += pq_overlap*mp/m_total;
|
||||
|
||||
double f = vec2d::dot(pq_v, pq);
|
||||
|
||||
if (f < 0) {
|
||||
f /= d2*(mp + mq);
|
||||
p->velocity += 2*mq*f*pq;
|
||||
q->velocity -= 2*mp*f*pq;
|
||||
p->velocity += 2*C_r*mq*f*pq;
|
||||
q->velocity -= 2*C_r*mp*f*pq;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
8
balls.h
8
balls.h
@ -39,8 +39,14 @@ extern int face_rotation;
|
||||
extern void balls_init ();
|
||||
extern void balls_destroy ();
|
||||
extern void ball_update_state (ball * p);
|
||||
extern void ball_elastic_collision (ball * p, ball * q);
|
||||
extern void ball_ball_collision (ball * p, ball * q);
|
||||
extern void ball_reposition (ball * b);
|
||||
extern void balls_draw (cairo_t * cr);
|
||||
|
||||
extern void restitution_coefficient_show ();
|
||||
extern void restitution_coefficient_draw (cairo_t * cr);
|
||||
extern void restitution_coefficient_set (double c);
|
||||
extern double restitution_coefficient_get ();
|
||||
extern void restitution_coefficient_change (double d);
|
||||
|
||||
#endif
|
||||
|
@ -91,6 +91,11 @@ void gravity_collisions (ball * begin, ball * end) {
|
||||
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;
|
||||
|
21
main.cc
21
main.cc
@ -21,18 +21,18 @@
|
||||
void check_collisions_simple () {
|
||||
for(unsigned int i = 0; i < n_balls; ++i)
|
||||
for(unsigned int j = i + 1; j < n_balls; ++j)
|
||||
ball_elastic_collision(balls + i, balls + j);
|
||||
ball_ball_collision(balls + i, balls + j);
|
||||
for(unsigned int j = 0; j < n_balls; ++j)
|
||||
ball_elastic_collision(&spaceship, balls + j);
|
||||
ball_ball_collision(&spaceship, balls + j);
|
||||
gravity_collisions (balls, balls + n_balls);
|
||||
gravity_collisions (&spaceship, &spaceship + 1);
|
||||
}
|
||||
|
||||
void check_collisions_with_index () {
|
||||
c_index_build();
|
||||
c_index_check_collisions(ball_elastic_collision);
|
||||
c_index_check_collisions(ball_ball_collision);
|
||||
for(unsigned int j = 0; j < n_balls; ++j)
|
||||
ball_elastic_collision(&spaceship, balls + j);
|
||||
ball_ball_collision(&spaceship, balls + j);
|
||||
gravity_collisions (balls, balls + n_balls);
|
||||
gravity_collisions (&spaceship, &spaceship + 1);
|
||||
}
|
||||
@ -66,6 +66,7 @@ gboolean draw_frame (GtkWidget * widget, cairo_t *cr, gpointer data) {
|
||||
cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
|
||||
cairo_paint(cr);
|
||||
gravity_draw (cr);
|
||||
restitution_coefficient_draw (cr);
|
||||
balls_draw (cr);
|
||||
spaceship_draw (cr);
|
||||
return FALSE;
|
||||
@ -100,6 +101,12 @@ gint keyboard_input (GtkWidget *widget, GdkEventKey *event) {
|
||||
case GDK_KEY_Right:
|
||||
gravity_change (10, 0);
|
||||
break;
|
||||
case GDK_KEY_R:
|
||||
restitution_coefficient_change (0.01);
|
||||
break;
|
||||
case GDK_KEY_r:
|
||||
restitution_coefficient_change (-0.01);
|
||||
break;
|
||||
case GDK_KEY_G:
|
||||
case GDK_KEY_g:
|
||||
gravity_show ();
|
||||
@ -150,6 +157,7 @@ void print_usage (const char * progname) {
|
||||
"\tface=<filename>\n"
|
||||
"\tstats=<sample-count> :: rendering timing statitstics (0=disabled, default)\n"
|
||||
"\tcollisions=<C> :: n=no collisions, s=simple, i=index\n"
|
||||
"\trestitution=<C_r> :: restitution coefficient C_r\n"
|
||||
"\t-r :: activate face rotation\n",
|
||||
progname);
|
||||
}
|
||||
@ -247,6 +255,11 @@ int main (int argc, const char *argv[]) {
|
||||
face_rotation = 1;
|
||||
continue;
|
||||
}
|
||||
double c_r;
|
||||
if (sscanf(argv[i], "restitution=%lf", &c_r) == 1) {
|
||||
restitution_coefficient_set (c_r);
|
||||
continue;
|
||||
}
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user