nightshade-api 0.40.0

Procedural high level API for the nightshade game engine
Documentation
//! Screen text anchored to a corner or the center, and 3d labels.

use nightshade::prelude::*;

/// Where screen text sits. The engine anchors screen text by alignment, not
/// pixel position.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ScreenAnchor {
    TopLeft,
    TopRight,
    BottomLeft,
    BottomRight,
    Center,
}

/// Spawns screen text at the given anchor. Update it with [`set_text`].
pub fn spawn_text(world: &mut World, text: &str, anchor: ScreenAnchor) -> Entity {
    let (alignment, vertical_alignment) = match anchor {
        ScreenAnchor::TopLeft => (TextAlignment::Left, VerticalAlignment::Top),
        ScreenAnchor::TopRight => (TextAlignment::Right, VerticalAlignment::Top),
        ScreenAnchor::BottomLeft => (TextAlignment::Left, VerticalAlignment::Bottom),
        ScreenAnchor::BottomRight => (TextAlignment::Right, VerticalAlignment::Bottom),
        ScreenAnchor::Center => (TextAlignment::Center, VerticalAlignment::Middle),
    };
    spawn_ui_text_with_properties(
        world,
        text,
        Vec2::zeros(),
        TextProperties {
            font_size: 18.0,
            alignment,
            vertical_alignment,
            outline_width: 0.02,
            outline_color: Vec4::new(0.0, 0.0, 0.0, 1.0),
            ..Default::default()
        },
    )
}

/// Spawns 3d text at `position` that always faces the camera.
pub fn spawn_label(world: &mut World, text: &str, position: Vec3) -> Entity {
    spawn_3d_billboard_text_with_properties(
        world,
        text,
        position,
        TextProperties {
            font_size: 24.0,
            alignment: TextAlignment::Center,
            vertical_alignment: VerticalAlignment::Middle,
            ..Default::default()
        },
    )
}

/// Replaces the content of a text entity. Skips all work when the text is
/// unchanged, so calling it every frame with a formatted string is fine.
pub fn set_text(world: &mut World, entity: Entity, text: &str) {
    let Some(text_index) = world
        .core
        .get_text(entity)
        .map(|component| component.text_index)
    else {
        return;
    };
    if world.resources.text.cache.get_text(text_index) == Some(text) {
        return;
    }
    world.resources.text.cache.set_text(text_index, text);
    if let Some(component) = world.core.get_text_mut(entity) {
        component.dirty = true;
    }
}