diff --git a/data/system/assets/characters/santa.svg b/data/system/assets/characters/santa.svg new file mode 100644 index 0000000000..81df290b6d --- /dev/null +++ b/data/system/assets/characters/santa.svg @@ -0,0 +1,961 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/experiment/santa.svg b/experiment/santa.svg new file mode 100644 index 0000000000..b7053cb514 --- /dev/null +++ b/experiment/santa.svg @@ -0,0 +1,621 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/experiment/santa2.svg b/experiment/santa2.svg new file mode 100644 index 0000000000..81df290b6d --- /dev/null +++ b/experiment/santa2.svg @@ -0,0 +1,961 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/experiment/src/controls.rs b/experiment/src/controls.rs index 0bd1937806..c4e3ad2d9d 100644 --- a/experiment/src/controls.rs +++ b/experiment/src/controls.rs @@ -1,82 +1,61 @@ -use geom::{Angle, Pt2D, Speed}; +use geom::{Angle, Speed}; use widgetry::{EventCtx, Key}; // TODO The timestep accumulation seems fine. What's wrong? Clamping errors repeated? const HACK: f64 = 5.0; -pub trait Controller { - fn displacement(&mut self, ctx: &mut EventCtx, speed: Speed) -> (f64, f64); +pub struct InstantController { + /// Which of the 8 directions are we facing, based on the last set of keys pressed down? + pub facing: Angle, } -pub struct InstantController; - impl InstantController { pub fn new() -> InstantController { - InstantController + InstantController { + facing: Angle::ZERO, + } } -} -impl Controller for InstantController { - fn displacement(&mut self, ctx: &mut EventCtx, speed: Speed) -> (f64, f64) { + pub fn displacement(&mut self, ctx: &mut EventCtx, speed: Speed) -> (f64, f64) { let mut dx = 0.0; let mut dy = 0.0; if let Some(dt) = ctx.input.nonblocking_is_update_event() { let dist = (dt * HACK * speed).inner_meters(); + let mut x = 0; + let mut y = 0; + // The x direction is inverted; somehow the usual Y inversion did this? Oh well, + // it's isolated here nicely. if ctx.is_key_down(Key::LeftArrow) { dx -= dist; + x = 1; } if ctx.is_key_down(Key::RightArrow) { dx += dist; + x = -1; } if ctx.is_key_down(Key::UpArrow) { dy -= dist; + y = -1; } if ctx.is_key_down(Key::DownArrow) { dy += dist; + y = 1; } - } - - (dx, dy) - } -} - -pub struct RotateController { - angle: Angle, -} - -impl RotateController { - #[allow(unused)] - pub fn new() -> RotateController { - RotateController { angle: Angle::ZERO } - } -} - -impl Controller for RotateController { - fn displacement(&mut self, ctx: &mut EventCtx, fwd_speed: Speed) -> (f64, f64) { - let rot_speed_degrees = 100.0; - - let mut dx = 0.0; - let mut dy = 0.0; - - if let Some(dt) = ctx.input.nonblocking_is_update_event() { - if ctx.is_key_down(Key::LeftArrow) { - self.angle = self - .angle - .rotate_degs(-rot_speed_degrees * dt.inner_seconds()); - } - if ctx.is_key_down(Key::RightArrow) { - self.angle = self - .angle - .rotate_degs(rot_speed_degrees * dt.inner_seconds()); - } - - if ctx.is_key_down(Key::UpArrow) { - let dist = dt * HACK * fwd_speed; - let pt = Pt2D::new(0.0, 0.0).project_away(dist, self.angle); - dx = pt.x(); - dy = pt.y(); - } + + // TODO Better way to do this; acos and asin? + self.facing = match (x, y) { + (-1, -1) => Angle::degrees(135.0), + (-1, 0) => Angle::degrees(180.0), + (-1, 1) => Angle::degrees(225.0), + (0, -1) => Angle::degrees(90.0), + (0, 1) => Angle::degrees(270.0), + (1, -1) => Angle::degrees(45.0), + (1, 0) => Angle::degrees(0.0), + (1, 1) => Angle::degrees(315.0), + (0, 0) => self.facing, + _ => unreachable!(), + }; } (dx, dy) diff --git a/experiment/src/game.rs b/experiment/src/game.rs index 56e031f3b4..21bb5615bc 100644 --- a/experiment/src/game.rs +++ b/experiment/src/game.rs @@ -13,14 +13,14 @@ use widgetry::{ }; use crate::animation::{Animator, SnowEffect}; -use crate::controls::{Controller, InstantController}; +use crate::controls::InstantController; use crate::levels::Config; const ZOOM: f64 = 10.0; pub struct Game { panel: Panel, - controls: Box, + controls: InstantController, minimap: SimpleMinimap, animator: Animator, snow: SnowEffect, @@ -69,7 +69,7 @@ impl Game { let with_zorder = false; let mut game = Game { panel, - controls: Box::new(InstantController::new()), + controls: InstantController::new(), minimap: SimpleMinimap::new(ctx, app, with_zorder), animator: Animator::new(ctx), snow: SnowEffect::new(ctx), @@ -266,10 +266,12 @@ impl State for Game { if !self.state.has_energy() { g.redraw(&self.state.draw_all_depots); } - g.draw_polygon( - Color::RED, - Circle::new(self.sleigh, Distance::meters(5.0)).to_polygon(), - ); + + GeomBatch::load_svg(g.prerender, "system/assets/characters/santa.svg") + .scale(0.1) + .centered_on(self.sleigh) + .rotate_around_batch_center(self.controls.facing) + .draw(g); self.snow.draw(g); self.animator.draw(g); if let Some(ref arrow) = self.state.energyless_arrow { diff --git a/experiment/src/levels.rs b/experiment/src/levels.rs index a551bb2137..9dcc21ac25 100644 --- a/experiment/src/levels.rs +++ b/experiment/src/levels.rs @@ -1,6 +1,6 @@ use abstutil::MapName; use geom::{Duration, Speed}; -use map_gui::tools::PopupMsg; +use map_gui::tools::{open_browser, PopupMsg}; use map_gui::SimpleApp; use map_model::osm; use widgetry::{ @@ -70,6 +70,11 @@ impl TitleScreen { txt.add(Line("An experiment")); txt.draw(ctx).centered_horiz() }, + Btn::text_fg("Santa character created by @parallaxcreativedesign").build( + ctx, + "open https://www.instagram.com/parallaxcreativedesign/", + None, + ), Btn::text_bg2("Instructions").build_def(ctx, None), Widget::row( levels @@ -127,6 +132,11 @@ impl State for TitleScreen { )); } x => { + if let Some(url) = x.strip_prefix("open ") { + open_browser(url.to_string()); + return Transition::Keep; + } + for lvl in all_levels() { if x == lvl.title { return Transition::Push(crate::game::Game::new(ctx, app, lvl));