#include #include #include // Window size const int screen_width = 512; const int screen_height = 360; const int pixel_width = 2; const int pixel_height = 2; const int sector_size = 16; // Random uint32_t rand_state = 0; uint32_t rnd(void); double rnd_double(double min, double max); int rnd_int(int min, int max); bool rnd_chance(int percentage); // Star System #define MAX_PLANETS 10 #define MAX_MOONS 4 #define NAME_LENGTH 8 // Including null terminator typedef struct Planet { double distance; double radius; Color color; double foliage; double minerals; double water; double gases; double temperature; int population; bool ring; double moons[MAX_MOONS]; int n_moons; char name[NAME_LENGTH]; } Planet; typedef struct StartSystem { bool exists_star; double star_radius; Color color; Planet planets[MAX_PLANETS]; int n_planets; } StartSystem; StartSystem star_system(uint32_t x, uint32_t y, bool generate_planets); Vector2 coordinates = {(float)UINT16_MAX / 2, (float)UINT16_MAX / 2}; Vector2 mouse = {0,0}; void on_update(void); void input(void); static inline int max(int a, int b){ return a >= b ? a : b; } static inline int abs(int n){ return n >= 0 ? n : -n; } char buffer[BUFSIZ]; int main(){ InitWindow(screen_width * pixel_width, screen_height * pixel_height, "Universe"); SetTargetFPS(144); while (!WindowShouldClose()){ BeginDrawing(); ClearBackground(BLACK); on_update(); EndDrawing(); } CloseWindow(); } uint32_t rnd(void){ rand_state += 0xe120fc15; uint64_t tmp; tmp = (uint64_t)rand_state * 0x4a39b70d; uint32_t m1 = (tmp >> 32) ^ tmp; tmp = (uint64_t)m1 * 0x12fad5c9; uint32_t m2 = (tmp >> 32) ^ tmp; return m2; } double rnd_double(double min, double max){ return ((double)rnd() / (double)(0x7FFFFFFF)) * (max - min) + min; } int rnd_int(int min, int max){ return (rnd() % (max - min)) + min; } bool rnd_chance(int percentage){ return rnd_int(0, 100) < percentage; } StartSystem star_system(uint32_t x, uint32_t y, bool generate_planets){ static short n_colors = 9; static Color colors[] = { BLUE, GREEN, RED, WHITE, YELLOW, ORANGE, PURPLE, LIME, BROWN }; rand_state = (x & 0xFFFF) << 16 | (y & 0xFFFF); StartSystem system; system.exists_star = rnd_int(0,15) == 1; if (!system.exists_star) return system; system.star_radius = rnd_double(10.0, 50.0); system.color = colors[rnd_int(0, n_colors)]; if (!generate_planets) return system; double distance = rnd_double(60.0, 200.0); if (system.star_radius >= 30.0) system.n_planets = rnd_int(0, MAX_PLANETS); else system.n_planets = max(0, rnd_int((int)(-30.0 + system.star_radius), MAX_PLANETS)); for (int i = 0; i < system.n_planets; i++){ Planet *p = &system.planets[i]; p->distance = distance; distance += rnd_double(20.0, 200.0); do { p->radius = rnd_double(4.0, 20.0); }while (p->radius >= system.star_radius); p->population = max(0, rnd_int(-5000000,20000000)); p->ring = rnd_chance(10); p->temperature = rnd_double(-200.0, 300.0); p->foliage = rnd_double(0.0, 1.0); p->minerals = rnd_double(0.0, 1.0); p->gases = rnd_double(0.0, 1.0); p->water = rnd_double(0.0, 1.0); double sum = 1.0 / (p->foliage + p->minerals + p->gases + p->water); p->foliage *= sum; p->minerals *= sum; p->gases *= sum; p->water *= sum; for (int i = 0; i < 3; i++) p->name[i] = (char)rnd_int('A', 'Z'); p->name[3] = '-'; for (int i = 4; i < NAME_LENGTH - 1; i++) p->name[i] = (char)rnd_int('0', '9'); p->name[NAME_LENGTH - 1] = '\0'; do { p->color = colors[rnd_int(0, n_colors)]; }while (p->color.r == system.color.r && p->color.b == system.color.b && p->color.g == system.color.g && p->color.a == system.color.a); p->n_moons = max(0, rnd_int(-4,MAX_MOONS)); // 50% probability of having at least one moon for (int j = 0; j < p->n_moons; j++) do { p->moons[j] = rnd_double(1.0, 5.0); }while (p->moons[j] >= p->radius); } return system; } void on_update(void){ input(); Vector2 mouse_sector = (Vector2) { .x = mouse.x / sector_size, .y = mouse.y / sector_size }; Vector2 mouse_scaled = {mouse.x * pixel_width, mouse.y * pixel_height}; static bool display_planet_menu = false; static Planet selected_planet; static bool is_selected = false; static Vector2 selected_pos = {0}; static StartSystem selected_system; int margin = 4; static Rectangle system_pane; static Rectangle planet_pane; if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)){ if (!is_selected // No planet selected || // or we clicked outside of pane (!CheckCollisionPointRec(mouse_scaled, system_pane) && // AND, also outside of planet pane (if it's being displayed) !CheckCollisionPointRec(mouse_scaled, planet_pane))){ StartSystem s = star_system((uint32_t)mouse_sector.x + (uint32_t)coordinates.x , (uint32_t)mouse_sector.y + (uint32_t)coordinates.y, false); if (s.exists_star){ is_selected = true; selected_system = star_system((uint32_t)mouse_sector.x + (uint32_t)coordinates.x , (uint32_t)mouse_sector.y + (uint32_t)coordinates.y, true); selected_pos = mouse_scaled; }else{ is_selected = false; selected_system = (StartSystem){0}; } } if (display_planet_menu && !CheckCollisionPointRec(mouse_scaled, planet_pane)){ display_planet_menu = false; planet_pane.height = 0; planet_pane.width = 0; } } Vector2 sector = {0,0}; for (sector.x = 0; sector.x < screen_width / sector_size; sector.x++){ for (sector.y = 0; sector.y < screen_height / sector_size; sector.y++){ StartSystem star = star_system((uint32_t)sector.x + (uint32_t)coordinates.x, (uint32_t)sector.y + (uint32_t)coordinates.y, false); if (star.exists_star){ Vector2 star_pos = { .x = (sector.x * sector_size + sector_size / 2) * pixel_width, .y = (sector.y * sector_size + sector_size / 2) * pixel_height }; double radius = star.star_radius / (sector_size / 2); DrawCircleV(star_pos, radius, star.color); if ((int)mouse_sector.x == (int)sector.x && (int)mouse_sector.y == (int)sector.y){ DrawCircleLines(star_pos.x, star_pos.y, radius + 4, YELLOW); } } } } if (is_selected){ system_pane = (Rectangle){ .x = margin, .y = selected_pos.y <= screen_height ? (screen_height * pixel_height / 2) : margin, .height = (screen_height - margin) * pixel_height / 2, .width = (screen_width - margin) * pixel_width }; DrawRectangleRec(system_pane, (Color){0,5,116,255}); // Dark blue /*DrawRectangle(margin, system_pane_y,//screen_height * pixel_height / 2, // middle of screen system_pane_width, system_pane_height, (Color){0,5,116,255});*/ DrawRectangleLines(system_pane.x, system_pane.y,//screen_height * pixel_height / 2, system_pane.width, system_pane.height, WHITE); Vector2 body = {margin * 2 + 4, system_pane.y + system_pane.height / 2}; body.x += selected_system.star_radius ; DrawCircleV(body, (int)(selected_system.star_radius ), selected_system.color); body.x += selected_system.star_radius + 5; for (int i = 0; i < selected_system.n_planets; i++){ Planet *p = &selected_system.planets[i]; body.x += p->radius; DrawCircleV(body, p->radius, p->color); Vector2 moon = body; moon.y += p->radius + 10; for (int j = 0; j < p->n_moons; j++){ moon.y += p->moons[j]; DrawCircleV(moon, p->moons[j], GRAY); moon.y += p->moons[j] + 10; } if (CheckCollisionPointCircle(mouse_scaled, body, p->radius)){ DrawCircleLines((int)body.x, (int)body.y, p->radius + 3, YELLOW); if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)){ display_planet_menu = true; selected_planet = *p; } } body.x += p->radius + 8; } if (display_planet_menu){ int m = margin * 2; planet_pane = (Rectangle){ .x = screen_width * pixel_width / 4, .y = m, .width = screen_width * pixel_width / 2, .height = (screen_height - 2*m) * pixel_height }; DrawRectangleRec(planet_pane, (Color){0,5,116,255}); // Dark blue DrawRectangleLines(planet_pane.x, planet_pane.y, planet_pane.width, planet_pane.height, WHITE); Vector2 pencil = {planet_pane.x + planet_pane.width / 2, planet_pane.y + selected_planet.radius * 3.5 + m}; DrawCircleV(pencil, selected_planet.radius * 3.5, selected_planet.color); pencil.x = planet_pane.x + m; pencil.y *= 2; sprintf(buffer, "Name: %s", selected_planet.name); DrawText(buffer, pencil.x, pencil.y, 30, RED); pencil.y += 30; sprintf(buffer, "Population: %d", selected_planet.population); DrawText(buffer, pencil.x, pencil.y, 30, RED); pencil.y += 30; sprintf(buffer, "Number of moons: %d", selected_planet.n_moons); DrawText(buffer, pencil.x, pencil.y, 30, RED); } } } void input(void){ if (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP)) coordinates.y -= 40.0f * GetFrameTime(); if (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN)) coordinates.y += 40.0f * GetFrameTime(); if (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT)) coordinates.x -= 40.0f * GetFrameTime(); if (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT)) coordinates.x += 40.0f * GetFrameTime(); mouse = GetMousePosition(); mouse.x /= pixel_width; mouse.y /= pixel_height; }