Displays 9-Patch UI elements in Bevy

Overview

Bevy 9-Patch plugin

MIT/Apache 2.0 Doc Crate Bevy Tracking CI

Implementation of 9-patch images in Bevy. Let you have a UI that scale only the right parts of your images.

9 patch example

See the examples for what can be done.

Simple usage

After adding the NinePatchPlugin plugin, spawning an Entity with the NinePatchBundle component bundle will add a 9-patch UI element.

A simple builder based on Godot's NinePatchRect is available.

use bevy::prelude::*;
use bevy_ninepatch::*;

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut nine_patches: ResMut<Assets<NinePatchBuilder<()>>>,
) {
    // Texture for the base image
    let panel_texture_handle = asset_server.load("assets/glassPanel_corners.png");

    // Create a basic 9-Patch UI element with margins of 20 pixels
    let nine_patch_handle = nine_patches.add(NinePatchBuilder::by_margins(20, 20, 20, 20));

    // This entity will be placed in the center of the 9-Patch UI element
    let content_entity = commands.spawn_bundle(TextBundle { ..Default::default() }).id();

    commands.spawn_bundle(
        NinePatchBundle {
            style: Style {
                margin: Rect::all(Val::Auto),
                justify_content: JustifyContent::Center,
                align_items: AlignItems::Center,
                size: Size::new(Val::Px(500.), Val::Px(300.)),
                ..Default::default()
            },
            nine_patch_data: NinePatchData::with_single_content(
                panel_texture_handle,
                nine_patch_handle,
                content_entity,
            ),
            ..Default::default()
        },
    );
}

See plugin.rs example for a complete example.

Changing element size

The component Style can be changed to update the size of the 9-Patch UI element, by changing the size attribute.

See change_size.rs example for a complete example.

Specify content to use

You can specify the content to be used inside the 9-Patch UI element. When creating a 9-Patch by specifying the margins, a content zone will be available by default for the center of the 9-Patch UI element. This can be set with the NinePatchContent component.

See multi_content.rs example for a complete example.

More flexible definition

It is possible to set any number of patches for an image, the only constraints is that all patches in a line must have the same height. Using this methods, different parts of the image can grow at different rates, and several content zones can be created.

See full.rs example for a complete example.

Bevy Compatibility

Bevy bevy_ninepatch
main main
0.6 0.6
0.5 0.5
You might also like...
Crossterm plugin for the bevy game engine
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

A 4X style camera for bevy.

A 4X style camera for bevy. Demo Default Key Bindings: W / A / S / D / Arrow Keys / Mouse Left - Move along the horizontal plane Q / E / Mouse Right -

Game physics in one weekend with bevy

Game Physics in a Weekend (in Rust) This project is an implementation of the Game Physics in a Weekend book using the Rust programming language and th

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

Concise Reference Book for the Bevy Game Engine

Unofficial Bevy Cheat Book Click here to read the book! Concise reference to programming in the Bevy game engine. Covers useful syntax, features, prog

A prototype plugin providing a simple line drawing api for bevy.
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

Template for a Bevy game

A Bevy game template Template for a Game using the awesome Bevy engine featuring (almost) out of the box builds for Windows, Linux and MacOS. What doe

Pixel-Perfect, 2D Renderer for Bevy that Seamlessly Targets Desktop and Web
Pixel-Perfect, 2D Renderer for Bevy that Seamlessly Targets Desktop and Web

bevy_retro ( Screenshot of Bounty Bros. game made with Bevy Retro and Skip'n Go ) Bevy Retro is a 2D, pixel-perfect renderer for Bevy that can target

A tilemap rendering crate for bevy which is more ECS friendly.
A tilemap rendering crate for bevy which is more ECS friendly.

bevy_ecs_tilemap A tilemap rendering plugin for bevy which is more ECS friendly by having an entity per tile. Features A tile per entity Fast renderin

Comments
  • bevy_ninepatch weird gaps

    bevy_ninepatch weird gaps

    I'm just starting out with bevy and testing things out, seems that the tiles have weird gaps when the final size is uneven. Here is the code:

    use bevy::prelude::*;
    use bevy_ninepatch::{NinePatchBuilder, NinePatchBundle, NinePatchData, NinePatchPlugin};
    
    fn main() {
      App::build()
        .add_plugins(DefaultPlugins)
        .add_plugin(NinePatchPlugin::<()>::default())
        .add_startup_system(setup.system())
        .run();
    }
    
    fn setup(
        mut commands: Commands,
        asset_server: Res<AssetServer>,
        mut nine_patches: ResMut<Assets<NinePatchBuilder<()>>>,
    ) {
        let panel_texture_handle = asset_server.load("gui8.png");
    
        // load the 9-Patch as an assets and keep an `Handle<NinePatchBuilder<()>>`
        let nine_patch_handle = nine_patches.add(NinePatchBuilder::by_margins(32, 32, 32, 32));
    
        commands.spawn_bundle(
            // this component bundle will be detected by the plugin, and the 9-Patch UI element will be added as a child
            // of this entity
            NinePatchBundle {
                style: Style {
                    margin: Rect::all(Val::Auto),
                    justify_content: JustifyContent::Center,
                    align_items: AlignItems::Center,
                    size: Size::new(Val::Px(256.), Val::Px(257.)),
                    ..Default::default()
                },
                nine_patch_data: NinePatchData {
                    nine_patch: nine_patch_handle,
                    texture: panel_texture_handle,
                    ..Default::default()
                },
                ..Default::default()
            },
        );
    
        commands.spawn_bundle(UiCameraBundle::default());
    }
    

    Assets used: gui8.png

    Screenshot of the issue: 20211126194225

    opened by Atakku 0
  • Can't change nine patch texture

    Can't change nine patch texture

    Is there an easy way to change the texture of the nine patch?

    I'm trying to make a UI button which has nine patch states for normal, hover & pressed

    Here are the things I've tried:

    1. Changing the nine_patch_data.texture in a system but this doesn't appear to work
    2. Using despawn(nine_patch_bundle) but this doesn't remove the child objects
    3. Using despawn_recursive, but then spawning a new NinePatchBundle under the same parent (a ButtonBundle) doesn't result in it getting drawn, not sure why?

    I'm also finding after (3.) is run a number of times, my FPS grinds quickly down to a few frames a second.

    Do you have any tips on debugging / improving the performance of the UI? Perhaps I can cache the 3 nine patches I need for the button in some way? Still very new to Bevy!

    Great tool, very excited to be trying it out 😄

    Here's what I'm toying with:

    use bevy::prelude::*;
    use bevy_ninepatch::*;
    
    pub struct ButtonResource {
    	option: Option<ButtonTextures>,
    }
    
    impl FromResources for ButtonResource {
    	fn from_resources(_resources: &Resources) -> Self {
    		ButtonResource { option: None }
    	}
    }
    
    pub struct ButtonTextures {
    	pub normal: Handle<Texture>,
    	pub hover: Handle<Texture>,
    	pub pressed: Handle<Texture>,
    }
    
    pub fn button_system(
    	commands: &mut Commands,
    	button_resource: Res<ButtonResource>,
    	mut nine_patches: ResMut<Assets<NinePatchBuilder<()>>>,
    	mut interaction_query: Query<
    		(Entity, &Interaction, &Children),
    		(Mutated<Interaction>, With<Button>),
    	>,
    ) {
    	if let Some(textures) = &button_resource.option {
    		for (entity, interaction, children) in interaction_query.iter_mut() {
    			if let Some(child) = children.get(0) {
    				commands.despawn_recursive(*child);
    				let texture = match *interaction {
    					Interaction::Clicked => textures.pressed.clone(),
    					Interaction::Hovered => textures.hover.clone(),
    					Interaction::None => textures.normal.clone(),
    				};
    				let nine_patch = nine_patches.add(NinePatchBuilder::by_margins(20, 20, 20, 20));
    				let nine_patch_data = NinePatchData {
    					texture,
    					nine_patch,
    					..Default::default()
    				};
    				commands
    					.spawn(NinePatchBundle {
    						nine_patch_data,
    						..Default::default()
    					})
    					.with(Parent(entity));
    			}
    		}
    	}
    }
    
    pub fn setup_buttons(
    	commands: &mut Commands,
    	mut button_textures: ResMut<ButtonResource>,
    	asset_server: Res<AssetServer>,
    	mut materials: ResMut<Assets<ColorMaterial>>,
    	mut nine_patches: ResMut<Assets<NinePatchBuilder<()>>>,
    ) {
    	let normal = asset_server.load("button.png");
    	let nine_patch = nine_patches.add(NinePatchBuilder::by_margins(20, 20, 20, 20));
    	button_textures.option = Some(ButtonTextures {
    		normal: normal.clone(),
    		hover: asset_server.load("button-hover.png"),
    		pressed: asset_server.load("button-pressed.png"),
    	});
    	commands
    		.spawn(ButtonBundle {
    			material: materials.add(Color::NONE.into()),
    			style: Style {
    				size: Size::new(Val::Px(100.), Val::Px(32.)),
    				margin: Rect::all(Val::Auto),
    				justify_content: JustifyContent::Center,
    				align_items: AlignItems::Center,
    				..Default::default()
    			},
    			..Default::default()
    		})
    		.with_children(|parent| {
    			let nine_patch_data = NinePatchData {
    				texture: normal,
    				nine_patch,
    				..Default::default()
    			};
    			parent.spawn(NinePatchBundle {
    				style: Style {
    					size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
    					..Default::default()
    				},
    				nine_patch_data,
    				..Default::default()
    			});
    		})
    		.current_entity()
    		.unwrap();
    
    	commands.spawn(CameraUiBundle::default());
    }
    
    opened by Hugheth 0
Releases(v0.9.0)
Owner
null
Minecraft-esque voxel engine prototype made with the bevy game engine. Pending bevy 0.6 release to undergo a full rewrite.

vx_bevy A voxel engine prototype made using the Bevy game engine. Goals and features Very basic worldgen Animated chunk loading (ala cube world) Optim

Lucas Arriesse 125 Dec 31, 2022
bevy-hikari is an implementation of voxel cone tracing global illumination with anisotropic mip-mapping in Bevy

Bevy Voxel Cone Tracing bevy-hikari is an implementation of voxel cone tracing global illumination with anisotropic mip-mapping in Bevy. Bevy Version

研究社交 208 Dec 27, 2022
A simple extension for `bevy-editor-pls` to support tilemap editing right inside the bevy app.

What is this This is a simple tilemap editor plugin, that hooks right into bevy_editor_pls to work with bevy_ecs_tilemap. It works completely within i

null 3 May 8, 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
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
Basic first-person fly camera for the Bevy game engine

bevy_flycam A basic first-person fly camera for Bevy 0.4 Controls WASD to move horizontally SPACE to ascend LSHIFT to descend ESC to grab/release curs

Spencer Burris 85 Dec 23, 2022
An ergonomic physics API for bevy games.

Heron An ergonomic physics API for 2d and 3d bevy games. (powered by rapier) How it looks like fn main() { App::build() .add_plugins(DefaultPlug

Jonathan Cornaz 313 Dec 16, 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