From 477fc16a0ad186607ed190ea4bba547480b9f797 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Wed, 22 Dec 2021 12:57:57 -0700 Subject: [PATCH] you can choose a font for your text actor, now (#19) --- CHANGELOG.md | 3 +++ examples/text.rs | 37 +++++++++++++++++++++++-------------- src/game.rs | 39 ++++++++++++++++++++++++++++++++++++--- src/text_actor.rs | 8 +++++++- 4 files changed, 69 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff3396a..4d29444 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,9 @@ is the user-defined struct passed to `rusty_engine::init!()`, or `()` if nothing - `AudioManager::music_playing()` will return whether or not music is currently playing (accessible through `EngineState:audio_manager`) +- Custom fonts may now be set on a `TextActor` at creation time. +`EngineState::add_text_actor_with_font` was added for a convenience. The font specified should be +a `.ttf` or `.otf` file stored in `assets/fonts` - (meta) Improved CI times by using sccache together with GitHub Actions caching diff --git a/examples/text.rs b/examples/text.rs index 6f214d9..7f9ce80 100644 --- a/examples/text.rs +++ b/examples/text.rs @@ -8,23 +8,32 @@ rusty_engine::init!(GameState); fn main() { let mut game = Game::new(); - let fps = game.add_text_actor("fps", "FPS: "); + let fps = game.add_text_actor_with_font("fps", "FPS: ", "FiraMono-Medium.ttf"); fps.translation = Vec2::new(0.0, 250.0); fps.font_size = 60.0; - let mut msg = game.add_text_actor("msg", "Changing text and font size after creation is supported, but requires\nre-rendering the text image each time, so use it sparingly!\n\nChanging the text's translation, rotation*, and scale* is fast,\n so feel free to do that a lot."); + let zoom_msg = game.add_text_actor( + "zoom_msg", + "Changing font size re-renders the text smoothly at a different size,\nbut using this technique for animation is both jittery (character kerning) and expensive.", + ); + zoom_msg.font_size = 35.0; + zoom_msg.translation = Vec2::new(0.0, 150.0); + + let font_msg = game.add_text_actor_with_font( + "font_msg", + "You can choose a font at creation time by providing the filename of a font stored in assets/fonts.\n\"FiraSans-Bold.ttf\" is the default. \"FiraMono-Medium.ttf\" is also included in the asset pack.", + "FiraMono-Medium.ttf", + ); + font_msg.font_size = 20.0; + font_msg.translation.y = 0.0; + + let msg = game.add_text_actor("msg", "Changing the text's translation, rotation*, and scale* is fast,\n so feel free to do that a lot."); msg.font_size = 24.0; + msg.translation.y = -150.0; - let mut msg2 = game.add_text_actor("msg2", "*Changing rotation and scale will not work until Bevy 0.6 is released,\nbut changing the translation works great already!"); + let msg2 = game.add_text_actor("msg2", "*Changing rotation and scale will not work until Bevy 0.6 is released,\nbut changing the translation works great already!"); msg2.font_size = 20.0; - let mut msg3 = game.add_text_actor( - "msg3", - "Changing font size re-renders the text smoothly at a different size,\nbut using this technique for animation is both jittery (character kerning) and expensive.", - ); - msg3.font_size = 35.0; - msg3.translation = Vec2::new(0.0, 150.0); - let game_state = GameState { timer: Timer::from_seconds(0.2, true), }; @@ -39,10 +48,10 @@ fn game_logic(engine_state: &mut EngineState, game_state: &mut GameState) -> boo } let msg2 = engine_state.text_actors.get_mut("msg2").unwrap(); - msg2.translation.x = 75.0 * (engine_state.time_since_startup_f64 * 0.5).sin() as f32; - msg2.translation.y = 75.0 * (engine_state.time_since_startup_f64 * 0.5).cos() as f32 - 200.0; + msg2.translation.x = 50.0 * (engine_state.time_since_startup_f64 * 0.5).sin() as f32; + msg2.translation.y = 50.0 * (engine_state.time_since_startup_f64 * 0.5).cos() as f32 - 275.0; - let msg3 = engine_state.text_actors.get_mut("msg3").unwrap(); - msg3.font_size = 10.0 * (engine_state.time_since_startup_f64 * 0.5).cos() as f32 + 20.0; + let msg3 = engine_state.text_actors.get_mut("zoom_msg").unwrap(); + msg3.font_size = 10.0 * (engine_state.time_since_startup_f64 * 0.5).cos() as f32 + 25.0; true } diff --git a/src/game.rs b/src/game.rs index 18ebc27..06e6788 100644 --- a/src/game.rs +++ b/src/game.rs @@ -31,8 +31,10 @@ pub struct EngineState { /// SYNCED - The state of all actors this frame. To add an actor, use the /// [`add_actor`](EngineState::add_actor) method. Modify & remove text actors as you like. pub actors: HashMap, - /// SYNCED - The state of all text actors this frame. To add a text actor, use the - /// [`add_text_actor`](EngineState::add_text_actor) method. Modify & remove text actors as you like. + /// SYNCED - The state of all text actors this frame. For convenience adding text actor, use the + /// [`add_text_actor`](EngineState::add_text_actor) or + /// [`add_text_actor_with_font`](EngineState::add_text_actor_with_font) methods. Modify & remove + /// text actors as you like. pub text_actors: HashMap, /// INFO - All the collision events that occurred this frame. For collisions to be generated /// between actors, both actors must have [`Actor.collision`] set to `true`. Collision events @@ -123,6 +125,36 @@ impl EngineState { // Unwrap: Can't crash because we just inserted the actor self.text_actors.get_mut(&label).unwrap() } + + #[must_use] + /// Add a [`TextActor`]. Use the `&mut TextActor` that is returned to set the translation, + /// rotation, etc. Use a unique label for each text actor. Attempting to add two text actors + /// with the same label will crash. The `font` paramater should be the filename of a font + /// located in the assets/fonts directory. The default font is "FiraSans-Bold.ttf". + pub fn add_text_actor_with_font( + &mut self, + label: L, + text: T, + font: F, + ) -> &mut TextActor + where + L: Into, + T: Into, + F: Into, + { + let label = label.into(); + let text = text.into(); + let font = font.into(); + let text_actor = TextActor { + label: label.clone(), + text, + font, + ..Default::default() + }; + self.text_actors.insert(label.clone(), text_actor); + // Unwrap: Can't crash because we just inserted the actor + self.text_actors.get_mut(&label).unwrap() + } } // startup system - grab window settings, initialize all the starting actors @@ -172,6 +204,7 @@ pub fn add_text_actors( let transform = text_actor.bevy_transform(); let font_size = text_actor.font_size; let text = text_actor.text.clone(); + let font_path = format!("fonts/{}", text_actor.font); commands .spawn() .insert(text_actor) @@ -179,7 +212,7 @@ pub fn add_text_actors( text: Text::with_section( text, TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font: asset_server.load(font_path.as_str()), font_size, color: Color::WHITE, }, diff --git a/src/text_actor.rs b/src/text_actor.rs index edd6912..c2ed139 100644 --- a/src/text_actor.rs +++ b/src/text_actor.rs @@ -12,8 +12,13 @@ pub struct TextActor { pub label: String, /// SYNCED: The actual text you want to display. pub text: String, + /// CREATION: The font to use when creating this text actor. Should be a file name of an .otf or + /// .ttf font located within the assets/fonts folder. Defaults to "FiraSans-Bold.ttf" (included + /// in the default asset pack). + pub font: String, /// SYNCED: The font size of the text you want to display. WARNING: As font sizes get larger, - /// the sprites we generate for them get slower to create. Very large sizes will crash. + /// the sprites we generate for them get slower to create. Very large sizes will crash. The + /// default font size is `30.0`. pub font_size: f32, /// SYNCED: Where you are in 2D game space. Positive x is right. Positive y is up. (0.0, 0.0) is the /// center of the screen. @@ -36,6 +41,7 @@ impl Default for TextActor { Self { label: String::default(), text: String::default(), + font: "FiraSans-Bold.ttf".to_string(), font_size: TEXT_ACTOR_DEFAULT_FONT_SIZE, translation: Vec2::default(), layer: TEXT_ACTOR_DEFAULT_LAYER,