(gravity) added radial, Newtonian (1/r^2) force field
This commit is contained in:
parent
dc0e5be086
commit
53e71fa27d
11
balls.c
11
balls.c
@ -48,11 +48,14 @@ void balls_init_state () {
|
||||
}
|
||||
|
||||
void ball_update_state (struct ball * p) {
|
||||
p->x += delta*p->v_x + delta*delta*g_x/2.0;
|
||||
p->v_x += delta*g_x;
|
||||
struct gravity_vector g;
|
||||
gravity_get_vector (&g, p);
|
||||
|
||||
p->y += delta*p->v_y + delta*delta*g_y/2.0;
|
||||
p->v_y += delta*g_y;
|
||||
p->x += delta*p->v_x + delta*delta*g.x/2.0;
|
||||
p->v_x += delta*g.x;
|
||||
|
||||
p->y += delta*p->v_y + delta*delta*g.y/2.0;
|
||||
p->v_y += delta*g.y;
|
||||
|
||||
if (p->x + p->radius > width) { /* right wall */
|
||||
if (p->v_x > 0) {
|
||||
|
80
gravity.c
80
gravity.c
@ -4,13 +4,31 @@
|
||||
#include "gravity.h"
|
||||
#include "game.h"
|
||||
|
||||
double g_y = 20;
|
||||
double g_x = 0;
|
||||
static double g_y = 20;
|
||||
static double g_x = 0;
|
||||
|
||||
static double g_r = 50;
|
||||
static double g_g = 10000000;
|
||||
|
||||
static int constant_field = 1;
|
||||
|
||||
static int gravity_vector_countdown = 0;
|
||||
static int gravity_vector_init = 300;
|
||||
|
||||
void gravity_constant_field (double x, double y) {
|
||||
constant_field = 1;
|
||||
g_x = x;
|
||||
g_y = y;
|
||||
}
|
||||
|
||||
void gravity_newton_field (double r, double g) {
|
||||
constant_field = 0;
|
||||
g_r = r;
|
||||
g_g = g;
|
||||
}
|
||||
|
||||
void gravity_draw (cairo_t * cr) {
|
||||
if (constant_field) {
|
||||
if (gravity_vector_countdown != 0) {
|
||||
cairo_save(cr);
|
||||
cairo_new_path(cr);
|
||||
@ -25,15 +43,71 @@ void gravity_draw (cairo_t * cr) {
|
||||
--gravity_vector_countdown;
|
||||
cairo_restore(cr);
|
||||
}
|
||||
} else {
|
||||
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
||||
cairo_save (cr);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void gravity_show () {
|
||||
if (constant_field)
|
||||
gravity_vector_countdown = gravity_vector_init;
|
||||
};
|
||||
|
||||
void gravity_change (double dx, double dy) {
|
||||
if (constant_field) {
|
||||
g_x += dx;
|
||||
g_y += dy;
|
||||
gravity_show ();
|
||||
};
|
||||
} else {
|
||||
g_r += dx;
|
||||
g_g += dy;
|
||||
}
|
||||
}
|
||||
|
||||
void gravity_get_vector (struct gravity_vector * v, const struct ball * b) {
|
||||
if (constant_field) {
|
||||
v->x = g_x;
|
||||
v->y = g_y;
|
||||
} else {
|
||||
double dx = width/2 - b->x;
|
||||
double dy = height/2 - b->y;
|
||||
double r2 = dx*dx+dy*dy;
|
||||
if (r2 < g_r*g_r) {
|
||||
v->x = 0;
|
||||
v->y = 0;
|
||||
} else {
|
||||
double r = sqrt(r2);
|
||||
v->x = g_g/r2/r*dx;
|
||||
v->y = g_g/r2/r*dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gravity_collisions (struct ball * begin, struct ball * end) {
|
||||
if (constant_field)
|
||||
return;
|
||||
for (struct ball * b = begin; b != end; ++b) {
|
||||
double dx = b->x - width/2;
|
||||
double dy = b->y - height/2;
|
||||
double d2 = dx*dx + dy*dy;
|
||||
double r = b->radius + g_r;
|
||||
if (d2 <= r*r) {
|
||||
double dv_x = b->v_x;
|
||||
double dv_y = b->v_y;
|
||||
|
||||
double f = dv_x*dx + dv_y*dy;
|
||||
|
||||
if (f < 0) {
|
||||
f /= d2;
|
||||
b->v_x -= 2*f*dx;
|
||||
b->v_y -= 2*f*dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
15
gravity.h
15
gravity.h
@ -1,11 +1,22 @@
|
||||
#ifndef GRAVITY_H_INCLUDED
|
||||
#define GRAVITY_H_INCLUDED
|
||||
|
||||
extern double g_y;
|
||||
extern double g_x;
|
||||
#include "balls.h"
|
||||
|
||||
struct gravity_vector {
|
||||
double x;
|
||||
double y;
|
||||
};
|
||||
|
||||
extern void gravity_constant_field (double x, double y);
|
||||
extern void gravity_newton_field (double r, double g);
|
||||
|
||||
extern void gravity_get_vector (struct gravity_vector * v, const struct ball * b);
|
||||
|
||||
extern void gravity_draw (cairo_t * cr);
|
||||
extern void gravity_change (double dx, double dy);
|
||||
extern void gravity_show ();
|
||||
|
||||
extern void gravity_collisions (struct ball * begin, struct ball * end);
|
||||
|
||||
#endif
|
||||
|
16
main.c
16
main.c
@ -24,6 +24,8 @@ void check_collisions_simple () {
|
||||
ball_elastic_collision(balls + i, balls + j);
|
||||
for(int j = 0; j < n_balls; ++j)
|
||||
ball_elastic_collision(&spaceship, balls + j);
|
||||
gravity_collisions (balls, balls + n_balls);
|
||||
gravity_collisions (&spaceship, &spaceship + 1);
|
||||
}
|
||||
|
||||
void check_collisions_with_index () {
|
||||
@ -31,6 +33,8 @@ void check_collisions_with_index () {
|
||||
c_index_check_collisions(ball_elastic_collision);
|
||||
for(int j = 0; j < n_balls; ++j)
|
||||
ball_elastic_collision(&spaceship, balls + j);
|
||||
gravity_collisions (balls, balls + n_balls);
|
||||
gravity_collisions (&spaceship, &spaceship + 1);
|
||||
}
|
||||
|
||||
void (*check_collisions)() = 0;
|
||||
@ -137,7 +141,8 @@ void print_usage (const char * progname) {
|
||||
"options:\n"
|
||||
"\t<width>x<height>\n"
|
||||
"\tn=<number of balls>\n"
|
||||
"\tfx=<x-force>\n"
|
||||
"\tfconst=<x-force>,<y-force> :: constant force field\n"
|
||||
"\tfnewt=<radius>,<g> :: radial, Newtonian force field\n"
|
||||
"\tfy=<y-force>\n"
|
||||
"\tradius=<min-radius>-<max-radius>\n"
|
||||
"\tv=<min-velocity>-<max-velocity>\n"
|
||||
@ -193,16 +198,21 @@ gboolean timeout (gpointer user_data) {
|
||||
int main (int argc, const char *argv[]) {
|
||||
int w = DEFAULT_WIDTH;
|
||||
int h = DEFAULT_HEIGHT;
|
||||
double fa, fb;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (sscanf(argv[i], "%dx%d", &w, &h) == 2)
|
||||
continue;
|
||||
if (sscanf(argv[i], "n=%u", &n_balls) == 1)
|
||||
continue;
|
||||
if (sscanf(argv[i], "fx=%lf", &g_x) == 1)
|
||||
if (sscanf(argv[i], "fconst=%lf,%lf", &fa, &fb) == 2) {
|
||||
gravity_constant_field (fa,fb);
|
||||
continue;
|
||||
if (sscanf(argv[i], "fy=%lf", &g_y) == 1)
|
||||
}
|
||||
if (sscanf(argv[i], "fnewt=%lf,%lf", &fa, &fb) == 2) {
|
||||
gravity_newton_field (fa,fb);
|
||||
continue;
|
||||
}
|
||||
if (sscanf(argv[i], "radius=%u-%u", &radius_min, &radius_max) == 2)
|
||||
continue;
|
||||
if (sscanf(argv[i], "v=%u-%u", &v_min, &v_max) == 2)
|
||||
|
Loading…
Reference in New Issue
Block a user