diff options
Diffstat (limited to 'examples/solar_system/src')
-rw-r--r-- | examples/solar_system/src/main.rs | 227 |
1 files changed, 97 insertions, 130 deletions
diff --git a/examples/solar_system/src/main.rs b/examples/solar_system/src/main.rs index 4c239806..6a2de736 100644 --- a/examples/solar_system/src/main.rs +++ b/examples/solar_system/src/main.rs @@ -7,13 +7,14 @@ //! //! [1]: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations#An_animated_solar_system use iced::{ - canvas, executor, Application, Canvas, Color, Command, Container, Element, - Length, Point, Settings, Size, Subscription, Vector, + canvas::{self, Cursor, Path, Stroke}, + executor, time, window, Application, Canvas, Color, Command, Element, + Length, Point, Rectangle, Settings, Size, Subscription, Vector, }; use std::time::Instant; -pub fn main() { +pub fn main() -> iced::Result { SolarSystem::run(Settings { antialiasing: true, ..Settings::default() @@ -22,7 +23,6 @@ pub fn main() { struct SolarSystem { state: State, - solar_system: canvas::layer::Cache<State>, } #[derive(Debug, Clone, Copy)] @@ -33,12 +33,12 @@ enum Message { impl Application for SolarSystem { type Executor = executor::Default; type Message = Message; + type Flags = (); - fn new() -> (Self, Command<Message>) { + fn new(_flags: ()) -> (Self, Command<Message>) { ( SolarSystem { state: State::new(), - solar_system: canvas::layer::Cache::new(), }, Command::none(), ) @@ -52,7 +52,6 @@ impl Application for SolarSystem { match message { Message::Tick(instant) => { self.state.update(instant); - self.solar_system.clear(); } } @@ -65,24 +64,20 @@ impl Application for SolarSystem { } fn view(&mut self) -> Element<Message> { - let canvas = Canvas::new() + Canvas::new(&mut self.state) .width(Length::Fill) .height(Length::Fill) - .push(self.solar_system.with(&self.state)); - - Container::new(canvas) - .width(Length::Fill) - .height(Length::Fill) - .center_x() - .center_y() .into() } } #[derive(Debug)] struct State { + space_cache: canvas::Cache, + system_cache: canvas::Cache, + cursor_position: Point, start: Instant, - current: Instant, + now: Instant, stars: Vec<(Point, f32)>, } @@ -95,153 +90,125 @@ impl State { pub fn new() -> State { let now = Instant::now(); - let (width, height) = Settings::default().window.size; + let (width, height) = window::Settings::default().size; State { + space_cache: Default::default(), + system_cache: Default::default(), + cursor_position: Point::ORIGIN, start: now, - current: now, - stars: { - use rand::Rng; - - let mut rng = rand::thread_rng(); - - (0..100) - .map(|_| { - ( - Point::new( - rng.gen_range(0.0, width as f32), - rng.gen_range(0.0, height as f32), - ), - rng.gen_range(0.5, 1.0), - ) - }) - .collect() - }, + now, + stars: Self::generate_stars(width, height), } } pub fn update(&mut self, now: Instant) { - self.current = now; + self.now = now; + self.system_cache.clear(); + } + + fn generate_stars(width: u32, height: u32) -> Vec<(Point, f32)> { + use rand::Rng; + + let mut rng = rand::thread_rng(); + + (0..100) + .map(|_| { + ( + Point::new( + rng.gen_range( + -(width as f32) / 2.0, + width as f32 / 2.0, + ), + rng.gen_range( + -(height as f32) / 2.0, + height as f32 / 2.0, + ), + ), + rng.gen_range(0.5, 1.0), + ) + }) + .collect() } } -impl canvas::Drawable for State { - fn draw(&self, frame: &mut canvas::Frame) { - use canvas::{Fill, Path, Stroke}; +impl<Message> canvas::Program<Message> for State { + fn draw( + &self, + bounds: Rectangle, + _cursor: Cursor, + ) -> Vec<canvas::Geometry> { use std::f32::consts::PI; - let center = frame.center(); + let background = self.space_cache.draw(bounds.size(), |frame| { + let space = Path::rectangle(Point::new(0.0, 0.0), frame.size()); - let space = Path::new(|path| { - path.rectangle(Point::new(0.0, 0.0), frame.size()) - }); + let stars = Path::new(|path| { + for (p, size) in &self.stars { + path.rectangle(*p, Size::new(*size, *size)); + } + }); - let stars = Path::new(|path| { - for (p, size) in &self.stars { - path.rectangle(*p, Size::new(*size, *size)); - } + frame.fill(&space, Color::BLACK); + + frame.translate(frame.center() - Point::ORIGIN); + frame.fill(&stars, Color::WHITE); }); - let sun = Path::new(|path| path.circle(center, Self::SUN_RADIUS)); - let orbit = Path::new(|path| path.circle(center, Self::ORBIT_RADIUS)); - - frame.fill(&space, Fill::Color(Color::BLACK)); - frame.fill(&stars, Fill::Color(Color::WHITE)); - frame.fill(&sun, Fill::Color(Color::from_rgb8(0xF9, 0xD7, 0x1C))); - frame.stroke( - &orbit, - Stroke { - width: 1.0, - color: Color::from_rgba8(0, 153, 255, 0.1), - ..Stroke::default() - }, - ); + let system = self.system_cache.draw(bounds.size(), |frame| { + let center = frame.center(); - let elapsed = self.current - self.start; - let elapsed_seconds = elapsed.as_secs() as f32; - let elapsed_millis = elapsed.subsec_millis() as f32; + let sun = Path::circle(center, Self::SUN_RADIUS); + let orbit = Path::circle(center, Self::ORBIT_RADIUS); - frame.with_save(|frame| { - frame.translate(Vector::new(center.x, center.y)); - frame.rotate( - (2.0 * PI / 60.0) * elapsed_seconds - + (2.0 * PI / 60_000.0) * elapsed_millis, + frame.fill(&sun, Color::from_rgb8(0xF9, 0xD7, 0x1C)); + frame.stroke( + &orbit, + Stroke { + width: 1.0, + color: Color::from_rgba8(0, 153, 255, 0.1), + ..Stroke::default() + }, ); - frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0)); - let earth = Path::new(|path| { - path.circle(Point::ORIGIN, Self::EARTH_RADIUS) - }); + let elapsed = self.now - self.start; + let rotation = (2.0 * PI / 60.0) * elapsed.as_secs() as f32 + + (2.0 * PI / 60_000.0) * elapsed.subsec_millis() as f32; - let shadow = Path::new(|path| { - path.rectangle( + frame.with_save(|frame| { + frame.translate(Vector::new(center.x, center.y)); + frame.rotate(rotation); + frame.translate(Vector::new(Self::ORBIT_RADIUS, 0.0)); + + let earth = Path::circle(Point::ORIGIN, Self::EARTH_RADIUS); + let shadow = Path::rectangle( Point::new(0.0, -Self::EARTH_RADIUS), Size::new( Self::EARTH_RADIUS * 4.0, Self::EARTH_RADIUS * 2.0, ), - ) - }); + ); - frame.fill(&earth, Fill::Color(Color::from_rgb8(0x6B, 0x93, 0xD6))); + frame.fill(&earth, Color::from_rgb8(0x6B, 0x93, 0xD6)); - frame.with_save(|frame| { - frame.rotate( - ((2.0 * PI) / 6.0) * elapsed_seconds - + ((2.0 * PI) / 6_000.0) * elapsed_millis, - ); - frame.translate(Vector::new(0.0, Self::MOON_DISTANCE)); + frame.with_save(|frame| { + frame.rotate(rotation * 10.0); + frame.translate(Vector::new(0.0, Self::MOON_DISTANCE)); - let moon = Path::new(|path| { - path.circle(Point::ORIGIN, Self::MOON_RADIUS) + let moon = Path::circle(Point::ORIGIN, Self::MOON_RADIUS); + frame.fill(&moon, Color::WHITE); }); - frame.fill(&moon, Fill::Color(Color::WHITE)); + frame.fill( + &shadow, + Color { + a: 0.7, + ..Color::BLACK + }, + ); }); - - frame.fill( - &shadow, - Fill::Color(Color { - a: 0.7, - ..Color::BLACK - }), - ); }); - } -} - -mod time { - use iced::futures; - use std::time::Instant; - pub fn every(duration: std::time::Duration) -> iced::Subscription<Instant> { - iced::Subscription::from_recipe(Every(duration)) - } - - struct Every(std::time::Duration); - - impl<H, I> iced_native::subscription::Recipe<H, I> for Every - where - H: std::hash::Hasher, - { - type Output = Instant; - - fn hash(&self, state: &mut H) { - use std::hash::Hash; - - std::any::TypeId::of::<Self>().hash(state); - self.0.hash(state); - } - - fn stream( - self: Box<Self>, - _input: futures::stream::BoxStream<'static, I>, - ) -> futures::stream::BoxStream<'static, Self::Output> { - use futures::stream::StreamExt; - - async_std::stream::interval(self.0) - .map(|_| Instant::now()) - .boxed() - } + vec![background, system] } } |