-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TargetCamera
breaks UI mouse interaction
#12836
Comments
Can you get this working with |
I just tried using Snippetuse bevy::{
prelude::*,
render::{
camera::RenderTarget,
render_resource::{
Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
},
view::RenderLayers,
},
window::WindowResized,
};
use bevy_mod_picking::prelude::*;
/// In-game resolution width.
const RES_WIDTH: u32 = 160;
/// In-game resolution height.
const RES_HEIGHT: u32 = 90;
/// Default render layers for pixel-perfect rendering.
/// You can skip adding this component, as this is the default.
const PIXEL_PERFECT_LAYERS: RenderLayers = RenderLayers::layer(0);
/// Render layers for high-resolution rendering.
const HIGH_RES_LAYERS: RenderLayers = RenderLayers::layer(1);
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
.add_plugins(DefaultPickingPlugins)
.insert_resource(Msaa::Off)
.insert_resource(DebugPickingMode::Normal)
.add_systems(Startup, (setup_camera, setup_ui).chain())
.add_systems(Update, fit_canvas)
.run();
}
/// Low-resolution texture that contains the pixel-perfect world.
/// Canvas itself is rendered to the high-resolution world.
#[derive(Component)]
struct Canvas;
/// Camera that renders the pixel-perfect world to the [`Canvas`].
#[derive(Component)]
struct InGameCamera;
/// Camera that renders the [`Canvas`] (and other graphics on [`HIGH_RES_LAYERS`]) to the screen.
#[derive(Component)]
struct OuterCamera;
/// Our button
#[derive(Component)]
struct MyButton;
fn setup_ui(mut commands: Commands, query: Query<Entity, With<InGameCamera>>) {
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()
},
Pickable::IGNORE,
TargetCamera(query.single()),
))
.with_children(|parent| {
parent
.spawn((
MyButton,
ButtonBundle {
style: Style {
width: Val::Px(50.0),
height: Val::Px(20.0),
border: UiRect::all(Val::Px(2.0)),
// horizontally center child text
justify_content: JustifyContent::Center,
// vertically center child text
align_items: AlignItems::Center,
..default()
},
border_color: BorderColor(Color::BLACK),
background_color: BackgroundColor(Color::rgb(0.15, 0.15, 0.15)),
..default()
},
On::<Pointer<Click>>::run(|| info!("pressed!")),
On::<Pointer<Over>>::run(|| info!("hovered!")),
))
.with_children(|parent| {
parent.spawn((
TextBundle::from_section(
"Button",
TextStyle {
font_size: 10.0,
color: Color::rgb(0.9, 0.9, 0.9),
..default()
},
),
Pickable::IGNORE,
));
});
});
}
fn setup_camera(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
let canvas_size = Extent3d {
width: RES_WIDTH,
height: RES_HEIGHT,
..default()
};
// this Image serves as a canvas representing the low-resolution game screen
let mut canvas = Image {
texture_descriptor: TextureDescriptor {
label: None,
size: canvas_size,
dimension: TextureDimension::D2,
format: TextureFormat::Bgra8UnormSrgb,
mip_level_count: 1,
sample_count: 1,
usage: TextureUsages::TEXTURE_BINDING
| TextureUsages::COPY_DST
| TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
},
..default()
};
// fill image.data with zeroes
canvas.resize(canvas_size);
let image_handle = images.add(canvas);
// this camera renders whatever is on `PIXEL_PERFECT_LAYERS` to the canvas
commands.spawn((
Camera2dBundle {
camera: Camera {
// render before the "main pass" camera
order: -1,
target: RenderTarget::Image(image_handle.clone()),
..default()
},
..default()
},
InGameCamera,
PIXEL_PERFECT_LAYERS,
));
// spawn the canvas
commands.spawn((
SpriteBundle {
texture: image_handle,
..default()
},
Canvas,
Pickable::IGNORE,
HIGH_RES_LAYERS,
));
// the "outer" camera renders whatever is on `HIGH_RES_LAYERS` to the screen.
// here, the canvas and one of the sample sprites will be rendered by this camera
commands.spawn((Camera2dBundle::default(), OuterCamera, HIGH_RES_LAYERS));
}
fn fit_canvas(
mut resize_events: EventReader<WindowResized>,
mut projections: Query<&mut OrthographicProjection, With<OuterCamera>>,
) {
for event in resize_events.read() {
let h_scale = event.width / RES_WIDTH as f32;
let v_scale = event.height / RES_HEIGHT as f32;
let mut projection = projections.single_mut();
projection.scale = 1. / h_scale.min(v_scale).round();
}
} |
So I don't think it's Might even be a known limitation when rendering to a non-window target based on this comment here: bevy/crates/bevy_ui/src/focus.rs Line 193 in 017ffc5
but if you swap your bevy/crates/bevy_ui/src/ui_node.rs Lines 2180 to 2187 in 017ffc5
Edit: If support can't be added, it might be worth having |
Yeah, I think I think the best solution here is to provide a way to achieve the same thing without a Currently, if you zoom an I would love to hear how other pixel art devs currently do their UI. Also, does anyone know how other engines like Godot, Love2D or Ebitengine achieves this? I remember having a pretty easy time achieving pixel-art graphics there. Godot: https://docs.godotengine.org/en/stable/tutorials/rendering/multiple_resolutions.html#desktop-game Love2D: a327ex/blog#19 Ebitengine: https://ebitengine.org/en/examples/animation.html |
I haven't tested it yet but I think this might provide some the ground work to get interactions working with UI nodes that specify a https://github.com/aevyrie/bevy_mod_picking/blob/main/examples/render_to_texture.rs |
Bevy version
0.13.1
What you did
This is a combination of 2d/pixel_grid_snap.rs and ui/button.rs from the examples:
What went wrong
Button interaction simply does not work at all. Hovering and clicking the button should cause
hovered!
andpressed!
to be printed to the console, but it does nothing here.I believe this is a critical issue for pixel-art games as this prevents mouse interaction from working at all. I hope that there is at least a workaround for such a show-stopping bug.
Additional information
Some relevant PRs:
Relevant issues:
The text was updated successfully, but these errors were encountered: