This commit is contained in:
Alexey 2026-01-28 23:38:51 +03:00
commit bbbf24fd2d
6 changed files with 6062 additions and 0 deletions

11
.cargo/config.toml Normal file
View file

@ -0,0 +1,11 @@
[unstable]
codegen-backend = true
[profile.dev]
codegen-backend = "cranelift"
[profile.dev.package."*"]
codegen-backend = "llvm"
[target.x86_64-unknown-linux-gnu]
rustflags = [ "-Zshare-generics=y" ]

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

5717
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

24
Cargo.toml Normal file
View file

@ -0,0 +1,24 @@
[package]
name = "bevy_scene_switch"
version = "0.1.0"
edition = "2024"
[dependencies]
bevy = { version = "0.18.0", features = ["debug", "dynamic_linking", "experimental_bevy_ui_widgets", "wayland"] }
[toolchain]
channel = "nightly"
[profile.dev]
opt-level = 1
[profile.dev.package."*"]
opt-level = 3
[profile.release]
codegen-units = 1
lto = "thin"
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=/usr/bin/mold"]

BIN
assets/fonts/default.ttf Normal file

Binary file not shown.

309
src/main.rs Normal file
View file

@ -0,0 +1,309 @@
use bevy::{
color::palettes::css::WHITE,
input::common_conditions::input_just_released,
input_focus::InputDispatchPlugin, picking::hover::Hovered,
prelude::*,
reflect::Is,
sprite::Anchor, ui::{
InteractionDisabled,
Pressed,
}, ui_widgets::{
Activate,
Button,
UiWidgetsPlugins,
observe,
}
};
#[derive(Component)]
pub struct Menu;
#[derive(Component)]
pub struct TwoD;
#[derive(Component)]
pub struct ThreeD;
#[derive(Component)]
pub struct MenuButton;
fn menu_button(asset_server: &AssetServer, width: Val, height: Val, text: impl ToString) -> impl Bundle {
(
Node {
width,
height,
border: UiRect::all(px(5)),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
border_radius: BorderRadius::MAX,
..default()
},
Button,
MenuButton,
Hovered::default(),
BorderColor::all(Color::BLACK),
BackgroundColor(Color::srgb(0.7, 0.7, 0.7)),
children![(
Text::new(text.to_string()),
TextFont {
font: asset_server.load("fonts/default.ttf"),
font_size: 24.0,
..default()
},
TextColor(Color::srgb(0.2, 0.2, 0.2)),
)],
)
}
fn button_on_interaction<E: EntityEvent, C: Component>(
event: On<E, C>,
mut buttons: Query<
(
&Hovered,
Has<InteractionDisabled>,
Has<Pressed>,
&mut BorderColor,
&Children,
),
With<MenuButton>,
>,
) {
if let Ok((hovered, disabled, pressed, mut border_color, children)) =
buttons.get_mut(event.event_target())
{
if children.is_empty() {
return;
}
let hovered = hovered.get();
let pressed = pressed && !(E::is::<Remove>() && C::is::<Pressed>());
let disabled = disabled && !(E::is::<Remove>() && C::is::<InteractionDisabled>());
match (disabled, hovered, pressed) {
// Disabled button
(true, _, _) => {
border_color.set_all(Color::srgb(0.8, 0.8, 0.8));
}
// Pressed and hovered button
(false, true, true) => {
border_color.set_all(Color::srgb(1.0, 0.3, 0.3));
}
// Hovered, unpressed button
(false, true, false) => {
border_color.set_all(Color::srgb(1.0, 1.0, 1.0));
}
// Unhovered button (either pressed or not).
(false, false, _) => {
border_color.set_all(Color::srgb(0.0, 0.0, 0.0));
}
}
}
}
fn handle_escape(
mut commands: Commands,
maybe_2d: Option<Single<(),With<TwoD>>>,
maybe_3d: Option<Single<(),With<ThreeD>>>,
) {
if maybe_2d.is_some() {
commands.run_system_cached(multidim_switch_2d_to_menu);
} else if maybe_3d.is_some() {
commands.run_system_cached(multidim_switch_3d_to_menu);
}
}
fn menu_bundle(asset_server: &AssetServer) -> impl Bundle {
(
Menu,
Node {
width: percent(100),
height: percent(100),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
display: Display::Flex,
flex_direction: FlexDirection::Column,
row_gap: px(10),
..default()
},
children![
( Camera2d ),
(
menu_button(asset_server, px(160), px(64), "2D"),
observe(multidim_switch_menu_to_2d),
),
(
menu_button(asset_server, px(160), px(64), "3D"),
observe(multidim_switch_menu_to_3d),
),
],
)
}
fn bundle_2d(asset_server: &AssetServer, mut meshes: ResMut<Assets<Mesh>>, mut materials: ResMut<Assets<ColorMaterial>>) -> impl Bundle {
(
TwoD,
Transform::default(),
children![
( Camera2d ),
(
Mesh2d(meshes.add(Rectangle::default())),
MeshMaterial2d(materials.add(Color::from(WHITE))),
Anchor::CENTER,
Transform {
translation: (-1. * Vec3::Z),
scale: Vec3::splat(128.),
..default()
},
),
(
Text2d::new("Random text over random mesh".to_string()),
TextFont {
font: asset_server.load("fonts/default.ttf"),
font_size: 24.0,
..default()
},
Anchor::CENTER,
TextBackgroundColor(Color::BLACK),
Transform::from_translation(Vec3 { x: 0., y: 100., z: 1. }),
),
],
)
}
fn bundle_3d(mut meshes: ResMut<Assets<Mesh>>, mut materials: ResMut<Assets<StandardMaterial>>) -> impl Bundle {
(
ThreeD,
Transform::default(),
children![
(
Mesh3d(meshes.add(Circle::new(4.0))),
MeshMaterial3d(materials.add(Color::WHITE)),
Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
),
(
Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
MeshMaterial3d(materials.add(Color::WHITE)),
Transform::from_xyz(0., 0.5, 0.),
),
(
PointLight {
shadows_enabled: true,
..default()
},
Transform::from_xyz(4.0, 8.0, 4.0),
),
(
Camera3d::default(),
Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
),
],
)
}
pub fn multidim_init_menu(
mut commands: Commands,
assets: Res<AssetServer>
) {
commands.spawn(menu_bundle(&assets));
}
fn multidim_init_2d(
mut commands: Commands,
asset_server: Res<AssetServer>,
meshes: ResMut<Assets<Mesh>>,
materials: ResMut<Assets<ColorMaterial>>,
) {
commands.spawn(bundle_2d(&asset_server, meshes, materials));
}
pub fn multidim_init_3d(
mut commands: Commands,
meshes: ResMut<Assets<Mesh>>,
materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn(bundle_3d(meshes, materials));
}
fn uninit_menu_dimension(
mut commands: Commands,
menu: Single<Entity, With<Menu>>,
) {
commands.entity(*menu).try_despawn();
}
fn uninit_2d(
mut commands: Commands,
two_d: Single<Entity, With<TwoD>>,
) {
commands.entity(*two_d).try_despawn();
}
fn uninit_3d(
mut commands: Commands,
three_d: Single<Entity, With<ThreeD>>
) {
commands.entity(*three_d).try_despawn();
}
fn multidim_switch_menu_to_2d(
_e: On<Activate>,
mut commands: Commands,
) {
commands.run_system_cached(uninit_menu_dimension);
commands.run_system_cached(multidim_init_2d);
}
fn multidim_switch_menu_to_3d(
_e: On<Activate>,
mut commands: Commands,
) {
commands.run_system_cached(uninit_menu_dimension);
commands.run_system_cached(multidim_init_3d);
}
fn multidim_switch_2d_to_menu(
mut commands: Commands,
) {
commands.run_system_cached(uninit_2d);
commands.run_system_cached(multidim_init_menu);
}
fn multidim_switch_3d_to_menu(
mut commands: Commands,
) {
commands.run_system_cached(uninit_3d);
commands.run_system_cached(multidim_init_menu);
}
pub struct MultidimPlugin;
impl Plugin for MultidimPlugin {
fn build(&self, app: &mut App) {
app
.add_observer(button_on_interaction::<Add, Pressed>)
.add_observer(button_on_interaction::<Remove, Pressed>)
.add_observer(button_on_interaction::<Add, InteractionDisabled>)
.add_observer(button_on_interaction::<Remove, InteractionDisabled>)
.add_observer(button_on_interaction::<Insert, Hovered>)
.add_systems(Startup, multidim_init_menu)
.add_systems(Update, handle_escape.run_if(input_just_released(KeyCode::Escape)));
}
}
fn main() {
App::new()
.add_plugins((
DefaultPlugins,
UiWidgetsPlugins,
InputDispatchPlugin,
MultidimPlugin,
))
.run();
}