Fixed orbit
This commit is contained in:
7 files changed
+107
-82
No files matched your search
@@ -24,6 +24,7 @@ add_executable(${PROJECT_NAME}
|
||||
mechanics.c
|
||||
vec_utils.c
|
||||
gravity.c
|
||||
magnetism.c
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
#ifndef CONSTS_H_
|
||||
#define CONSTS_H_
|
||||
#define TIMESTEP 10
|
||||
#define simx 2
|
||||
#define LOOP_TIMESTEP 1000000LL // Wall-clock nanoseconds between updates (1 kHz).
|
||||
#define PHYSICS_TIMESTEP 100.0f // Simulated seconds per update.
|
||||
#define WALL_COLLISIONS 0 // Enable for bounded collision tests.
|
||||
#define NEWTON_G 6.674e-11
|
||||
#define EARTH_MASS 5.9722e24 // Kilograms per simulation mass unit.
|
||||
#define UA 149.6E6
|
||||
#define RT 6378.14
|
||||
#define RT 6378.14 // Kilometers per simulation distance unit.
|
||||
#define DISTANCE_UNIT_METERS (RT * 1000.0)
|
||||
#define SIMULATION_G (NEWTON_G * EARTH_MASS / \
|
||||
(DISTANCE_UNIT_METERS * DISTANCE_UNIT_METERS * \
|
||||
DISTANCE_UNIT_METERS))
|
||||
|
||||
#endif // CONSTS_H_
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <raylib.h>
|
||||
|
||||
void gravity(universe_t *uni) {
|
||||
const float dt = 1.0f / simx;
|
||||
const float dt = PHYSICS_TIMESTEP;
|
||||
for (unsigned int i = 0; i < uni->num_bodies; i++) {
|
||||
mass_body_t *body_1 = &uni->bodies[i];
|
||||
for (unsigned int y = i + 1; y < uni->num_bodies; y++) {
|
||||
@@ -15,7 +15,7 @@ void gravity(universe_t *uni) {
|
||||
continue;
|
||||
}
|
||||
Vector2 direction = vec2_normalize(separation);
|
||||
float factor = NEWTON_G * dt / distance_squared;
|
||||
float factor = SIMULATION_G * dt / distance_squared;
|
||||
body_1->speed =
|
||||
vec2_sum(body_1->speed, vec2_scale(direction, factor * body_2->mass));
|
||||
body_2->speed = vec2_sum(body_2->speed,
|
||||
|
||||
+20
-12
@@ -6,19 +6,27 @@
|
||||
#define EPSILON 8.85418782E-12
|
||||
|
||||
void magnetism(universe_t* uni){
|
||||
mass_body_t body_1;
|
||||
mass_body_t body_2;
|
||||
Vector2 diff, force;
|
||||
for (unsigned int i = 0; i < uni->num_bodies-1; i++) {
|
||||
body_1 = uni->bodies[i];
|
||||
for (unsigned int i = 0; i < uni->num_bodies; i++) {
|
||||
mass_body_t *body_1 = &uni->bodies[i];
|
||||
for (unsigned int y = i + 1; y < uni->num_bodies; y++) {
|
||||
body_2 = uni->bodies[y];
|
||||
diff=vec2_diff(body_2.position,body_1.position);
|
||||
force = vec2_scale(diff,body_1.charge*body_2.charge/(4*PI*EPSILON*vec2_len(diff)));
|
||||
body_1.speed=vec2_sum(body_1.speed,vec2_scale(force,1/body_1.mass));
|
||||
body_2.speed=vec2_diff(body_2.speed,vec2_scale(force,1/body_2.mass));
|
||||
uni->bodies[y] = body_2;
|
||||
mass_body_t *body_2 = &uni->bodies[y];
|
||||
if (body_1->charge == 0 || body_2->charge == 0) {
|
||||
continue;
|
||||
}
|
||||
Vector2 diff = vec2_diff(body_2->position, body_1->position);
|
||||
float distance_squared = vec2_dot(diff, diff);
|
||||
if (distance_squared == 0) {
|
||||
continue;
|
||||
}
|
||||
// Charges are in coulombs; convert acceleration to Earth radii/s^2.
|
||||
float factor = PHYSICS_TIMESTEP * body_1->charge * body_2->charge /
|
||||
(4 * PI * EPSILON * EARTH_MASS * DISTANCE_UNIT_METERS *
|
||||
DISTANCE_UNIT_METERS * DISTANCE_UNIT_METERS * distance_squared);
|
||||
Vector2 impulse = vec2_scale(vec2_normalize(diff), factor);
|
||||
body_1->speed = vec2_diff(body_1->speed,
|
||||
vec2_scale(impulse, 1 / body_1->mass));
|
||||
body_2->speed = vec2_sum(body_2->speed,
|
||||
vec2_scale(impulse, 1 / body_2->mass));
|
||||
}
|
||||
uni->bodies[i] = body_1;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "consts.h"
|
||||
#include "gravity.h"
|
||||
#include "mechanics.h"
|
||||
#include "magnetism.h"
|
||||
#include "mechanics.h"
|
||||
#include "objects.h"
|
||||
#include "vec_utils.h"
|
||||
#include <bits/time.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <raylib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <threads.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -23,33 +22,31 @@ static inline int center_y_text(int height, int size) {
|
||||
return (height - size) / 2;
|
||||
}
|
||||
|
||||
long long timespec_diff_ns(struct timespec end, struct timespec start) {
|
||||
return (end.tv_sec - start.tv_sec) * 1000000000LL +
|
||||
(end.tv_nsec - start.tv_nsec);
|
||||
}
|
||||
|
||||
void *physics(void *args) {
|
||||
universe_t *uni = (universe_t *)args;
|
||||
struct timespec ot, ct;
|
||||
struct timespec next_step;
|
||||
clock_gettime(CLOCK_MONOTONIC, &next_step);
|
||||
while (true) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &ct);
|
||||
gravity(uni);
|
||||
mechanics(uni);
|
||||
magnetism(uni);
|
||||
ot = ct;
|
||||
long long elapsed = timespec_diff_ns(ct, ot);
|
||||
long long remaining = TIMESTEP / simx - elapsed;
|
||||
|
||||
if (remaining > 0) {
|
||||
long long sleep_time = remaining * 9 / 10;
|
||||
|
||||
struct timespec sleep_time_spec = {0, sleep_time};
|
||||
thrd_sleep(&sleep_time_spec, NULL);
|
||||
next_step.tv_sec += LOOP_TIMESTEP / 1000000000LL;
|
||||
next_step.tv_nsec += LOOP_TIMESTEP % 1000000000LL;
|
||||
if (next_step.tv_nsec >= 1000000000L) {
|
||||
next_step.tv_nsec -= 1000000000L;
|
||||
next_step.tv_sec++;
|
||||
}
|
||||
gravity(uni);
|
||||
magnetism(uni);
|
||||
mechanics(uni);
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
if (now.tv_sec > next_step.tv_sec ||
|
||||
(now.tv_sec == next_step.tv_sec && now.tv_nsec > next_step.tv_nsec)) {
|
||||
next_step =
|
||||
now; // An overrun starts a fresh schedule, without catch-up steps.
|
||||
}
|
||||
// Sleep only until the deadline; processing time is already included.
|
||||
while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_step, NULL) ==
|
||||
EINTR) {
|
||||
}
|
||||
|
||||
do {
|
||||
clock_gettime(CLOCK_MONOTONIC, &ct);
|
||||
} while (timespec_diff_ns(ct, ot) < TIMESTEP / simx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,22 +57,27 @@ int main(void) {
|
||||
const char *welcome_text = "Welcome to Fucked Physics!";
|
||||
universe_t universe = {0, NULL};
|
||||
universe.bodies = malloc(1024 * sizeof(mass_body_t));
|
||||
universe.num_bodies = 5;
|
||||
universe.num_bodies = 7;
|
||||
|
||||
universe.bodies[0] =
|
||||
(mass_body_t){330432.0f, 696, {-0, 0}, {0, 0}, 696};
|
||||
universe.bodies[1] =
|
||||
(mass_body_t){0.055f, 2.439, {0.387*UA/RT, 0}, {0, -38.86/RT}, 50};
|
||||
universe.bodies[2] =
|
||||
(mass_body_t){0.815f, 0.1, {0.723*UA/RT, 0}, {0, -34.79/RT}, 50};
|
||||
universe.bodies[3] =
|
||||
(mass_body_t){1.0f, 0.1, {1*UA/RT, 0}, {0, -29.29/RT}, 50};
|
||||
universe.bodies[4] =
|
||||
(mass_body_t){0.107f, 200, {1.524*UA/RT, 0}, {0, -21.97/RT}, 200};
|
||||
universe.bodies[5] =
|
||||
(mass_body_t){317.83f, 0.1, {5.203*UA/RT, 0}, {0, -12.43/RT}, 50};
|
||||
universe.bodies[6] =
|
||||
(mass_body_t){95.159f, 200, {9.582*UA/RT, 0}, {0, -9.11/RT}, 200};
|
||||
(mass_body_t){330432.0f, 696340 / RT, {0, 0}, {0, 0}, 600, 0, "Sun"};
|
||||
universe.bodies[1] = (mass_body_t){
|
||||
0.055f, 2439.7 / RT, {0.387 * UA / RT, 0}, {0, -38.86 / RT}, 80,
|
||||
0, "Mercury"};
|
||||
universe.bodies[2] = (mass_body_t){
|
||||
0.815f, 6051.8 / RT, {0.723 * UA / RT, 0}, {0, -34.79 / RT}, 190,
|
||||
0, "Venus"};
|
||||
universe.bodies[3] = (mass_body_t){
|
||||
1.0f, 1.0f, {1 * UA / RT, 0}, {0, -29.29 / RT}, 200, 0, "Earth"};
|
||||
universe.bodies[4] = (mass_body_t){
|
||||
0.107f, 3389.5 / RT, {1.524 * UA / RT, 0}, {0, -21.97 / RT}, 106,
|
||||
0, "Mars"};
|
||||
universe.bodies[5] = (mass_body_t){
|
||||
317.83f, 69911 / RT, {5.203 * UA / RT, 0}, {0, -12.43 / RT}, 400,
|
||||
0, "Jupiter"};
|
||||
universe.bodies[6] = (mass_body_t){
|
||||
95.159f, 58232 / RT, {9.582 * UA / RT, 0}, {0, -9.11 / RT}, 300,
|
||||
0, "Saturn"};
|
||||
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
||||
InitWindow(800, 450, "Fucked Physics");
|
||||
SetTargetFPS(120);
|
||||
@@ -116,14 +118,18 @@ int main(void) {
|
||||
}
|
||||
} while (key_pressed != 0);
|
||||
|
||||
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) ||
|
||||
IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) {
|
||||
if (universe.num_bodies < 1024 &&
|
||||
(IsMouseButtonPressed(MOUSE_LEFT_BUTTON) ||
|
||||
IsMouseButtonDown(MOUSE_RIGHT_BUTTON))) {
|
||||
Vector2 mouse_pos = vec2_scale(
|
||||
transform_to_center(vec2_scale(GetMousePosition(), -1)), -1);
|
||||
mouse_pos = vec2_scale(mouse_pos, 1 / v_scale);
|
||||
|
||||
universe.bodies[universe.num_bodies] =
|
||||
(mass_body_t){100000.0f, 0.1, mouse_pos, {0, 0}, 10};
|
||||
(mass_body_t){100000.0f, 0.1, mouse_pos, {0, 0}, 10, 0, ""};
|
||||
snprintf(universe.bodies[universe.num_bodies].name,
|
||||
sizeof(universe.bodies[universe.num_bodies].name), "Body %u",
|
||||
universe.num_bodies + 1);
|
||||
universe.num_bodies++;
|
||||
}
|
||||
|
||||
@@ -153,10 +159,15 @@ int main(void) {
|
||||
Vector2 scaled_offset = vec2_scale(canvas_offset, v_scale);
|
||||
Vector2 body_position = vec2_scale(universe.bodies[i].position, v_scale);
|
||||
body_position = vec2_sum(body_position, scaled_offset);
|
||||
DrawCircleV(transform_to_center(body_position),
|
||||
universe.bodies[i].draw_radius * v_scale,
|
||||
body_position = transform_to_center(body_position);
|
||||
float draw_radius = universe.bodies[i].draw_radius * v_scale;
|
||||
DrawCircleV(body_position, draw_radius,
|
||||
(Color){((256 / universe.num_bodies) * i) % 256 / 2,
|
||||
255 * (i % 2) / 2, 255 * (i % 2) * (i % 3) / 2, 255});
|
||||
// Keep labels readable at every zoom level.
|
||||
DrawText(universe.bodies[i].name,
|
||||
(int)(body_position.x + draw_radius + 6),
|
||||
(int)(body_position.y - 8), 16, BLACK);
|
||||
}
|
||||
|
||||
DrawText(welcome_text, center_x_text(welcome_text, GetRenderWidth(), 20),
|
||||
|
||||
+13
-15
@@ -73,25 +73,23 @@ void collide_rigid(mass_body_t *a, float restitution) {
|
||||
}
|
||||
|
||||
void mechanics(universe_t *uni) {
|
||||
mass_body_t body_1;
|
||||
mass_body_t body_2;
|
||||
Vector2 collision;
|
||||
Vector2 scaled_speed;
|
||||
// Advance every body to the same simulated time before checking contacts.
|
||||
for (unsigned int i = 0; i < uni->num_bodies; i++) {
|
||||
body_1 = uni->bodies[i];
|
||||
scaled_speed = vec2_scale(body_1.speed, 1.0 / simx);
|
||||
body_1.position = vec2_sum(body_1.position, scaled_speed);
|
||||
if (i < uni->num_bodies - 1) {
|
||||
mass_body_t *body = &uni->bodies[i];
|
||||
body->position = vec2_sum(body->position,
|
||||
vec2_scale(body->speed, PHYSICS_TIMESTEP));
|
||||
}
|
||||
for (unsigned int i = 0; i < uni->num_bodies; i++) {
|
||||
mass_body_t *body_1 = &uni->bodies[i];
|
||||
for (unsigned int y = i + 1; y < uni->num_bodies; y++) {
|
||||
body_2 = uni->bodies[y];
|
||||
collision = body_collision(&body_1, &body_2);
|
||||
mass_body_t *body_2 = &uni->bodies[y];
|
||||
Vector2 collision = body_collision(body_1, body_2);
|
||||
if (!vec2_is_null(collision)) {
|
||||
collide(&body_1, &body_2, collision, 0.99);
|
||||
}
|
||||
uni->bodies[y] = body_2;
|
||||
collide(body_1, body_2, collision, 0.99);
|
||||
}
|
||||
}
|
||||
collide_rigid(&body_1, 1.1);
|
||||
uni->bodies[i] = body_1;
|
||||
if (WALL_COLLISIONS) {
|
||||
collide_rigid(body_1, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,13 @@
|
||||
#include "vec_utils.h"
|
||||
|
||||
typedef struct {
|
||||
float mass;
|
||||
float radius;
|
||||
Vector2 position;
|
||||
Vector2 speed;
|
||||
float mass; // Earth masses.
|
||||
float radius; // Earth radii (physical collision radius).
|
||||
Vector2 position; // Earth radii.
|
||||
Vector2 speed; // Earth radii per simulated second.
|
||||
float draw_radius;
|
||||
float charge;
|
||||
float charge; // Coulombs.
|
||||
char name[32];
|
||||
} mass_body_t;
|
||||
|
||||
typedef struct universe {
|
||||
|
||||
Reference in new issue
Block a user