A nine slice/patch plugin for bevy ui nodes as single component using a fragment shader.

Overview

Bevy nine slice/patch Material Plugin

Quick and easy auto-scaling nine slice/patch material for bevy ui nodes implemented as Fragment Shader.

Features

  • Sprite sheet animation support
  • Wasm support
  • Blend colors / tinting
  • Color lookup gradients

Making hover effects a breeze.

cargo add bevy_nine_slice_ui

Usage

It's a single component.

The plugin as has a sync_rate_ms parameter, which is the minimum time between updates in milliseconds. This is to prevent the material from updating too often. The default is 100ms.

app.add_plugin(NineSliceUiPlugin::default());
fn spawn_ui(mut cmd: Commands, server: Res<AssetServer>) {
    commands.spawn(NineSliceUiMaterialBundle {
        style: Style {
            width: Val::Percent(100.),
            height: Val::Percent(50.),
            display: Display::Flex,
            ..default()
        },
        nine_slice_texture: NineSliceTexture::from_image(server.load("panel_atlas.png")),
        ..default()
    });
}

Using an atlas instead of a single image

Also added atlas capabilities. Instead of from_image, use from_slice method and pass the texture bounds.

nine_slice_texture: NineSliceTexture::from_slice(
    server.load("panel_atlas.png"),
    Rect::new(32., 0., 32. + 48., 48.),
),

Adding a material to an existing Bundle

You can also add a nine slice material to an existing bundle, like a button. Just beware, this might not always work. Just in the recent 12.1 update, the background color component broke the material. The background color component will now be removed from elements where the material is added.

.spawn(ButtonBundle {
    style: Style {
        width: Val::Px(150.),
        height: Val::Px(50.),
        display: Display::Flex,
        justify_content: JustifyContent::Center,
        align_items: AlignItems::Center,
        ..default()
    },
    ..default()
})
.insert(NineSliceTexture::from_slice(
    server.load("panel_atlas.png"),
    Rect::new(0., 0., 32., 32.),
));

Modify the texture component

You can modify the texture component to change the texture or the texture bounds. This enables simple sheet style animations.

// add a blend color
NineSliceTexture::from_image(server.load("panel_atlas.png"))
    .with_blend_color(Color::RED)
    .with_blend_mix(0.5);


// or why not a whole palatte gradient?
// A 1D texture to use as color lookup, the grayscale value of the original color is used as UV
// dark to light, left to right
NineSliceTexture::from_image(server.load("panel_atlas.png"))
    .with_lookup_gradient(server.load("4-color-palette.png"))
    .with_gradient_mix(1.0);

Check out the example, there is everything you need to know.

cargo run --example ui

result:

Example

Compatibility

  • Bevy 0.12
Comments
  • Updating an entity's NineSliceTexture doesn't update the material.

    Updating an entity's NineSliceTexture doesn't update the material.

    Here's a reproducer that can be dropped in the examples directory.

    Note that in the example below, I am only changing the texture, but this is also the case when switching between nine slices with the same texture but different bounds.

    I am expecting the button to change visually when hovered.

    use bevy::prelude::*;
    use bevy_nine_slice_ui::prelude::*;
    
    fn main() {
        App::new()
            .add_plugins((DefaultPlugins, NineSlicePlugin::default()))
            .add_systems(Startup, setup)
            .add_systems(Update, button_system)
            .run();
    }
    
    fn button_system(
        mut commands: Commands,
        mut interaction_query: Query<(Entity, &Interaction), (Changed<Interaction>, With<Button>)>,
        server: Res<AssetServer>,
    ) {
        for (entity, interaction) in &mut interaction_query {
            match *interaction {
                Interaction::Hovered => {
                    info!("Hovered.");
                    commands.entity(entity).insert(NineSliceTexture::from_slice(
                        server.load("panel_atlas.png"),
                        Rect::new(0., 0., 32., 32.),
                    ));
                }
                _ => {
                    info!("Unhovered.");
                    commands
                        .entity(entity)
                        .insert(NineSliceTexture::from_image(server.load("panel.png")));
                }
            }
        }
    }
    
    fn setup(mut commands: Commands, server: Res<AssetServer>) {
        commands.spawn(Camera2dBundle::default());
        commands
            .spawn(NodeBundle {
                style: Style {
                    width: Val::Percent(100.0),
                    height: Val::Percent(100.0),
                    align_items: AlignItems::Center,
                    justify_content: JustifyContent::Center,
                    ..default()
                },
                ..default()
            })
            .with_children(|parent| {
                parent.spawn((
                    ButtonBundle {
                        style: Style {
                            width: Val::Px(150.0),
                            height: Val::Px(65.0),
                            justify_content: JustifyContent::Center,
                            align_items: AlignItems::Center,
                            ..default()
                        },
                        ..default()
                    },
                    NineSliceTexture::from_image(server.load("panel.png")),
                ));
            });
    }
    
    opened by rparrett 4
  • Hot reloading only works properly when the image size stays the same.

    Hot reloading only works properly when the image size stays the same.

    Version tested: b74c871eb4380fddfe7cf4f2aca8ae650916ad62

    To reproduce, run with --features=bevy/file_watcher. Modify your nine slice image by resizing it. The effect is the most disturbing when making the image smaller.

    image
    opened by rparrett 2
  • Minor issues with README

    Minor issues with README

    https://github.com/Lommix/bevy_nine_slice_ui/blob/master/README.md?plain=1#L13C1-L13C25

    I think this is still true, but slightly confusing given the example immediately below involves the bundle.

    https://github.com/Lommix/bevy_nine_slice_ui/blob/master/README.md?plain=1#L16

    This seems to actually be NineSlicePlugin rather than NineSliceUiPlugin. Though perhaps it's the plugin that should be renamed?

    opened by rparrett 2
  • All of Bevy's default features aren't required

    All of Bevy's default features aren't required

    Hi, thanks for publishing this. It's the first crate I've seen making use of the new UI materials and seems quite handy!

    Cargo features are additive, so adding bevy_nine_slice_ui to my project means that I need to compile bevy_pbr, bevy_gltf, bevy_animation, and other features that my 2d project doesn't need.

    This also makes it impossible to do webgpu builds, because the webgl2 feature is included by default.

    It would be great if you could pare down to only the features required to make bevy_nine_slice_ui function.

    opened by rparrett 0
  • Consider allowing an array of colors for palette shifting

    Consider allowing an array of colors for palette shifting

    I'm just now getting around to checking out the 0.5 update. Thanks for getting that out mid-jam, but I was too busy to even think about it.

    Maybe this is only really useful for the very simple two-color graphics I was using and I haven't fully thought this through, but the main draw of the potential lookup gradient feature for me was dealing with fewer image assets. So the current implementation didn't seem worth using in my case.

    Now that I'm thinking about this a little more though, I guess it would be super easy to build the palette assets in code, but I guess that's not the most intuitive API.

    If you've already considered this, then I consider the issue resolved, so feel free to close.

    opened by rparrett 2
Owner
Lorenz
Game-dev, full-stack web and everything fun
Lorenz
🪄 Shader art using webgpu

✨ Shader art using webgpu ✨ This is the implementation of An introduction to Shader Art Coding in Rust using webgpu. ?? Setup You need: Rust compiler

BADR 7 Aug 29, 2023
Bevy plugin for a simple single-line text input widget.

bevy_simple_text_input An unambitious single-line text input widget for bevy_ui. Usage See examples/basic.rs. Alternatives If you need more features,

Rob Parrett 9 Oct 3, 2023
Cross-platform compute shader engine

wgpu-compute-toy This is the compute shader engine for https://compute.toys As well as running on the web via WebAssembly and WebGPU, it can run nativ

compute.toys 37 May 9, 2023
Bevy Simple Portals is a Bevy game engine plugin aimed to create portals.

Portals for Bevy Bevy Simple Portals is a Bevy game engine plugin aimed to create portals. Those portals are (for now) purely visual and can be used t

Sélène Amanita 11 May 28, 2023
A Client/Server game networking plugin using QUIC, for the Bevy game engine.

Bevy Quinnet A Client/Server game networking plugin using QUIC, for the Bevy game engine. Bevy Quinnet QUIC as a game networking protocol Features Roa

Gilles Henaux 65 Feb 20, 2023
An extendable system made up of autonomous execution services known as nodes organized in a tree of processes. Inspired by Godot!

NodeTree NodeTree is a framework to create large scalable programs and games through a tree of processes. Each process is fully autonomous and is capa

LunaticWyrm 3 Apr 10, 2024
Minecraft using Bevy and Bevy-Meshem

minecraft_bevy Minecraft_bevy was built to showcase bevy_meshem. After a week of developing it has: Chunk loading / unloading each chunk's mesh is bei

Adam 7 Oct 4, 2023
A Bevy plugin for loading the LDtk 2D tile map format.

bevy_ldtk ( Tileset from "Cavernas" by Adam Saltsman ) A Bevy plugin for loading LDtk tile maps. Usage use bevy::prelude::*; use bevy_ldtk::*; fn mai

Katharos Technology 23 Jul 4, 2022
Inspector plugin for the bevy game engine

bevy-inspector-egui This crate provides the ability to annotate structs with a #[derive(Inspectable)], which opens a debug interface using egui where

Jakob Hellermann 517 Dec 31, 2022
A plugin for Egui integration into Bevy

bevy_egui This crate provides a Egui integration for the Bevy game engine. Features: Desktop and web (bevy_webgl2) platforms support Clipboard (web su

Vladyslav Batyrenko 453 Jan 3, 2023
Crossterm plugin for the bevy game engine

What is bevy_crossterm? bevy_crossterm is a Bevy plugin that uses crossterm as a renderer. It provides custom components and events which allow users

null 79 Nov 2, 2022
A Bevy plugin to use Kira for game audio

Bevy Kira audio This bevy plugin is intended to try integrating Kira into Bevy. The end goal would be to replace or update bevy_audio, if Kira turns o

Niklas Eicker 172 Jan 5, 2023
A prototype plugin providing a simple line drawing api for bevy.

bevy_debug_lines A prototype plugin providing a simple line drawing api for bevy. See docs.rs for documentation. Expect breakage on master. Click on t

Michael Palmos 92 Dec 31, 2022
Bevy plugin helping with asset loading and organisation

Bevy asset loader This Bevy plugin reduces boilerplate when loading game assets. The crate offers the AssetCollection trait and can automatically load

Niklas Eicker 205 Jan 2, 2023
A sprite-sheet animation plugin for bevy

Benimator A sprite sheet animation plugin for bevy Features A SpriteSheetAnimation component to automatically update the indices of the TextureAtlasSp

Jonathan Cornaz 140 Dec 27, 2022
A Bevy Engine plugin for making 2D paths, smooth animations with Bezier curves

bevy_pen_tool A Bevy Engine plugin for making 2D paths and smooth animations with Bezier curves TODO: Mesh-making functionality for building 2D shapes

Eli 36 Dec 22, 2022
A procedural sky plugin for bevy

bevy_atmosphere A procedural sky plugin for bevy Example use bevy::prelude::*; use bevy_atmosphere::*; fn main() { App::build() .insert_re

Jonah Henriksson 137 Dec 23, 2022
Generic cellular automaton plugin for bevy.

Bevy Cellular Automaton bevy_life is a generic plugin for cellular automaton. From the classic 2D Conway's game of life to WireWorld and 3D rules, the

Félix Lescaudey de Maneville 34 Nov 23, 2022
Verlet physics plugin for bevy.

bevy_verlet Simple Verlet points and sticks implementation for bevy. Features You can simply add a VerletPoint component on any entity with a Transfor

Félix Lescaudey de Maneville 34 Dec 9, 2022