diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 0000000..55ba1f2 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,2 @@ +tab_spaces = 2 +reorder_imports = true diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..0dbe449 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,357 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fontdue" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a62391ecb864cf12ed06b2af4eda2e609b97657950d6a8f06841b17726ab253" +dependencies = [ + "hashbrown", + "ttf-parser", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glam" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815" + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] + +[[package]] +name = "image" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b7ea949b537b0fd0af141fff8c77690f2ce96f4f41f042ccb6c69c6c965945" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-rational", + "num-traits", + "png", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "macroquad" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3790f7fd2e4c480108cbfc86488f023b72e1e0bb6ffd5c6cba38049c7e2fbfc" +dependencies = [ + "bumpalo", + "fontdue", + "glam", + "image", + "macroquad_macro", + "miniquad", + "quad-rand", +] + +[[package]] +name = "macroquad_macro" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5cecfede1e530599c8686f7f2d609489101d3d63741a6dc423afc997ce3fcc8" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "miniquad" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46381fe09fbf91bfa402a3e4fc26a104c9130562d51f89964c46adbc00591496" +dependencies = [ + "libc", + "ndk-sys", + "objc", + "winapi", +] + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "ndk-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "planets" +version = "0.1.0" +dependencies = [ + "itertools", + "macroquad", + "rand", +] + +[[package]] +name = "png" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" +dependencies = [ + "bitflags", + "crc32fast", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "quad-rand" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658fa1faf7a4cc5f057c9ee5ef560f717ad9d8dc66d975267f709624d6e1ab88" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "ttf-parser" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..2d14731 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "planets" +version = "0.1.0" +edition = "2021" +authors = ["Sergei Parshukov "] +license = "MIT" +publish = false + +[dependencies] +itertools = "0.10.5" +macroquad = { version = "0.3.25", default-features = false } +rand = "0.8.5" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f0aa226 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Sergei Parshukov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/cspell.json b/cspell.json new file mode 100644 index 0000000..23b7990 --- /dev/null +++ b/cspell.json @@ -0,0 +1,7 @@ +{ + "version": "0.2", + "words": [ + "deque", + "itertools" + ] +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..c713f4f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,200 @@ +use ::rand::{self, Rng}; +use itertools::Itertools; +use macroquad::prelude::*; +use std::collections::VecDeque; + +const VIRTUAL_WIDTH: f32 = 1920.0; +const VIRTUAL_HEIGHT: f32 = 1080.0; + +const TRAIL_LENGTH: usize = 15000; + +const SCALE_FACTOR: f32 = 10e6; +const G: f32 = 6.674e-11 * SCALE_FACTOR; + +#[derive(Debug, Default, Clone)] +struct Planet { + pos: Vec2, + mass: f32, + velocity: Vec2, + color: Color, + + trail: VecDeque, +} + +impl Planet { + fn render(&self) { + let scale = screen_width() / VIRTUAL_WIDTH; + + let radius = self.mass.ln() * scale; + + draw_circle( + pos_x(self.pos.x, scale), + pos_y(self.pos.y, scale), + radius, + self.color, + ); + + let segments = Vec::from_iter(self.trail.iter().tuple_windows()); + let len = segments.len(); + for (i, (a, b)) in segments.iter().enumerate() { + let mut c = self.color; + c.a = (len - i) as f32 / len as f32; + draw_line( + pos_x(a.x, scale), + pos_y(a.y, scale), + pos_x(b.x, scale), + pos_y(b.y, scale), + 1.0, + c, + ); + } + } + + fn gravitate(&mut self, other: &Planet) { + let d = self.pos.distance_squared(other.pos); + + // both divided by self.mass + let f = G * other.mass / d; + let a = f; + + let dir = (other.pos - self.pos).normalize(); + + self.velocity += dir * a; + } + + fn apply_velocity(&mut self) { + const SCALE_FACTOR: f32 = 1.0; + + self.trail.push_front(self.pos); + self.trail.truncate(TRAIL_LENGTH); + + self.pos += self.velocity * SCALE_FACTOR; + } +} + +fn pos_x(x: f32, scale: f32) -> f32 { + screen_width() / 2.0 + x * scale +} + +fn pos_y(y: f32, scale: f32) -> f32 { + screen_height() / 2.0 + y * scale +} + +struct Star { + pos: Vec2, + magnitude: f32, +} + +impl Star { + fn new() -> Self { + let scale = screen_width() / VIRTUAL_WIDTH; + let mut rng = rand::thread_rng(); + + let w = VIRTUAL_WIDTH / 2.0; + let h = screen_height() / 2.0 / scale; + Star { + pos: Vec2 { + x: rng.gen_range(-w..w), + y: rng.gen_range(-h..h), + }, + magnitude: rng.gen_range(0.1..=1.1), + } + } + + fn render(&self) { + let scale = screen_width() / VIRTUAL_WIDTH; + let mut rng = rand::thread_rng(); + + if rng.gen_range(0.0..1.0) >= 0.05 { + draw_circle( + pos_x(self.pos.x, scale), + pos_y(self.pos.y, scale), + self.magnitude * scale, + WHITE, + ); + } + } +} + +fn velocity_for_circular_orbit(sat: &Planet, center: &Planet) -> Vec2 { + let dist = sat.pos.distance(center.pos); + let speed = (G * (center.mass + sat.mass) / dist).sqrt(); + let diff = sat.pos - center.pos; + let tan = Vec2 { + x: -diff.y, + y: diff.x, + } + .normalize(); + tan * speed + center.velocity +} + +#[macroquad::main("Planets")] +async fn main() { + request_new_screen_size(VIRTUAL_WIDTH, VIRTUAL_HEIGHT); + + let sun = Planet { + mass: 200000., + color: Color::from_rgba(249, 182, 17, 255), + ..Default::default() + }; + + let earth = Planet { + pos: Vec2 { x: 500.0, y: 0.0 }, + velocity: Vec2 { x: 0.1, y: 0.3 }, + mass: 999., + color: Color::from_rgba(129, 171, 84, 255), + ..Default::default() + }; + + let mut mun = Planet { + pos: Vec2 { + x: 450.0, + y: -450.0, + }, + mass: 35., + color: Color::from_rgba(75, 109, 119, 255), + ..Default::default() + }; + mun.velocity = velocity_for_circular_orbit(&mun, &sun); + + let mut mercury = Planet { + pos: Vec2 { x: 0.0, y: 300.0 }, + mass: 200., + color: Color::from_rgba(201, 55, 55, 255), + ..Default::default() + }; + mercury.velocity = velocity_for_circular_orbit(&mercury, &sun); + + let mut objects = vec![sun, earth, mun, mercury]; + + let stars = (0..500).map(|_| Star::new()).collect::>(); + + loop { + clear_background(BLACK); + + let copy = objects.clone(); + for (i, obj) in objects.iter_mut().enumerate() { + for (j, obj2) in copy.iter().enumerate() { + if i != j && !is_key_down(KeyCode::Space) { + obj.gravitate(obj2); + } + } + } + + if !is_key_down(KeyCode::Space) { + for obj in objects.iter_mut() { + obj.apply_velocity(); + } + } + + for obj in objects.iter() { + obj.render(); + } + + for s in stars.iter() { + s.render(); + } + + next_frame().await + } +}